1
1
Fork 0
mirror of https://code.mensbeam.com/MensBeam/Arsse.git synced 2024-12-22 13:12:41 +00:00

Changed "NewsSync" to "Arsse"

This commit is contained in:
Dustin Wilson 2017-03-27 23:12:12 -05:00
parent 9d5dab249c
commit 7236020b8b
68 changed files with 316 additions and 316 deletions

88
.gitignore vendored
View file

@ -1,44 +1,44 @@
#dependencies #dependencies
vendor vendor
#temp files #temp files
cache/* cache/*
newssync.db* arsse.db*
# Windows image file caches # Windows image file caches
Thumbs.db Thumbs.db
ehthumbs.db ehthumbs.db
# Folder config file # Folder config file
Desktop.ini Desktop.ini
# Recycle Bin used on file shares # Recycle Bin used on file shares
$RECYCLE.BIN/ $RECYCLE.BIN/
# Windows Installer files # Windows Installer files
*.cab *.cab
*.msi *.msi
*.msm *.msm
*.msp *.msp
# ========================= # =========================
# Operating System Files # Operating System Files
# ========================= # =========================
# OSX # OSX
# ========================= # =========================
.DS_Store .DS_Store
.AppleDouble .AppleDouble
.LSOverride .LSOverride
# Icon must ends with two \r. # Icon must ends with two \r.
Icon Icon
# Thumbnails # Thumbnails
._* ._*
# Files that might appear on external disk # Files that might appear on external disk
.Spotlight-V100 .Spotlight-V100
.Trashes .Trashes

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
const BASE = __DIR__.DIRECTORY_SEPARATOR; const BASE = __DIR__.DIRECTORY_SEPARATOR;
const NS_BASE = __NAMESPACE__."\\"; const NS_BASE = __NAMESPACE__."\\";

View file

@ -32,12 +32,12 @@
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"JKingWeb\\NewsSync\\": "lib/" "JKingWeb\\Arsse\\": "lib/"
} }
}, },
"autoload-dev": { "autoload-dev": {
"psr-4": { "psr-4": {
"JKingWeb\\NewsSync\\Test\\": "tests/lib/" "JKingWeb\\Arsse\\Test\\": "tests/lib/"
} }
} }
} }

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
abstract class AbstractException extends \Exception { abstract class AbstractException extends \Exception {

View file

@ -1,27 +1,27 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
class Conf { class Conf {
public $lang = "en"; public $lang = "en";
public $dbDriver = Db\SQLite3\Driver::class; public $dbDriver = Db\SQLite3\Driver::class;
public $dbSchemaBase = BASE.'sql'; public $dbSchemaBase = BASE.'sql';
public $dbSQLite3File = BASE."newssync.db"; public $dbSQLite3File = BASE."arsse.db";
public $dbSQLite3Key = ""; public $dbSQLite3Key = "";
public $dbSQLite3AutoUpd = true; public $dbSQLite3AutoUpd = true;
public $dbPostgreSQLHost = "localhost"; public $dbPostgreSQLHost = "localhost";
public $dbPostgreSQLUser = "newssync"; public $dbPostgreSQLUser = "arsse";
public $dbPostgreSQLPass = ""; public $dbPostgreSQLPass = "";
public $dbPostgreSQLPort = 5432; public $dbPostgreSQLPort = 5432;
public $dbPostgreSQLDb = "newssync"; public $dbPostgreSQLDb = "arsse";
public $dbPostgreSQLSchema = ""; public $dbPostgreSQLSchema = "";
public $dbPostgreSQLAutoUpd = false; public $dbPostgreSQLAutoUpd = false;
public $dbMySQLHost = "localhost"; public $dbMySQLHost = "localhost";
public $dbMySQLUser = "newssync"; public $dbMySQLUser = "arsse";
public $dbMySQLPass = ""; public $dbMySQLPass = "";
public $dbMySQLPort = 3306; public $dbMySQLPort = 3306;
public $dbMySQLDb = "newssync"; public $dbMySQLDb = "arsse";
public $dbMySQLAutoUpd = false; public $dbMySQLAutoUpd = false;
public $userDriver = User\Internal\Driver::class; public $userDriver = User\Internal\Driver::class;

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Conf; namespace JKingWeb\Arsse\Conf;
class Exception extends \JKingWeb\NewsSync\AbstractException { class Exception extends \JKingWeb\Arsse\AbstractException {
} }

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
use PasswordGenerator\Generator as PassGen; use PasswordGenerator\Generator as PassGen;
class Database { class Database {
@ -50,7 +50,7 @@ class Database {
} }
public function settingGet(string $key) { public function settingGet(string $key) {
$row = $this->db->prepare("SELECT value, type from newssync_settings where key = ?", "str")->run($key)->getRow(); $row = $this->db->prepare("SELECT value, type from arsse_settings where key = ?", "str")->run($key)->getRow();
if(!$row) return null; if(!$row) return null;
switch($row['type']) { switch($row['type']) {
case "int": return (int) $row['value']; case "int": return (int) $row['value'];
@ -157,17 +157,17 @@ class Database {
$value = $in; $value = $in;
break; break;
} }
return (bool) $this->db->prepare("REPLACE INTO newssync_settings(key,value,type) values(?,?,?)", "str", "str", "str")->run($key, $value, $type)->changes(); return (bool) $this->db->prepare("REPLACE INTO arsse_settings(key,value,type) values(?,?,?)", "str", "str", "str")->run($key, $value, $type)->changes();
} }
public function settingRemove(string $key): bool { public function settingRemove(string $key): bool {
$this->db->prepare("DELETE from newssync_settings where key is ?", "str")->run($key); $this->db->prepare("DELETE from arsse_settings where key is ?", "str")->run($key);
return true; return true;
} }
public function userExists(string $user): bool { public function userExists(string $user): bool {
if(!$this->data->user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!$this->data->user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
return (bool) $this->db->prepare("SELECT count(*) from newssync_users where id is ?", "str")->run($user)->getValue(); return (bool) $this->db->prepare("SELECT count(*) from arsse_users where id is ?", "str")->run($user)->getValue();
} }
public function userAdd(string $user, string $password = null): string { public function userAdd(string $user, string $password = null): string {
@ -176,13 +176,13 @@ class Database {
if($password===null) $password = (new PassGen)->length($this->data->conf->userTempPasswordLength)->get(); if($password===null) $password = (new PassGen)->length($this->data->conf->userTempPasswordLength)->get();
$hash = ""; $hash = "";
if(strlen($password) > 0) $hash = password_hash($password, \PASSWORD_DEFAULT); if(strlen($password) > 0) $hash = password_hash($password, \PASSWORD_DEFAULT);
$this->db->prepare("INSERT INTO newssync_users(id,password) values(?,?)", "str", "str")->runArray([$user,$hash]); $this->db->prepare("INSERT INTO arsse_users(id,password) values(?,?)", "str", "str")->runArray([$user,$hash]);
return $password; return $password;
} }
public function userRemove(string $user): bool { public function userRemove(string $user): bool {
if(!$this->data->user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!$this->data->user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
if($this->db->prepare("DELETE from newssync_users where id is ?", "str")->run($user)->changes() < 1) throw new User\Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); if($this->db->prepare("DELETE from arsse_users where id is ?", "str")->run($user)->changes() < 1) throw new User\Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]);
return true; return true;
} }
@ -191,17 +191,17 @@ class Database {
if(!$this->data->user->authorize("@".$domain, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $domain]); if(!$this->data->user->authorize("@".$domain, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $domain]);
$domain = str_replace(["\\","%","_"],["\\\\", "\\%", "\\_"], $domain); $domain = str_replace(["\\","%","_"],["\\\\", "\\%", "\\_"], $domain);
$domain = "%@".$domain; $domain = "%@".$domain;
return $this->db->prepare("SELECT id from newssync_users where id like ?", "str")->run($domain)->getAll(); return $this->db->prepare("SELECT id from arsse_users where id like ?", "str")->run($domain)->getAll();
} else { } else {
if(!$this->data->user->authorize("", __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => "global"]); if(!$this->data->user->authorize("", __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => "global"]);
return $this->db->prepare("SELECT id from newssync_users")->run()->getAll(); return $this->db->prepare("SELECT id from arsse_users")->run()->getAll();
} }
} }
public function userPasswordGet(string $user): string { public function userPasswordGet(string $user): string {
if(!$this->data->user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!$this->data->user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
if(!$this->userExists($user)) throw new User\Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); if(!$this->userExists($user)) throw new User\Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]);
return (string) $this->db->prepare("SELECT password from newssync_users where id is ?", "str")->run($user)->getValue(); return (string) $this->db->prepare("SELECT password from arsse_users where id is ?", "str")->run($user)->getValue();
} }
public function userPasswordSet(string $user, string $password = null): string { public function userPasswordSet(string $user, string $password = null): string {
@ -210,13 +210,13 @@ class Database {
if($password===null) $password = (new PassGen)->length($this->data->conf->userTempPasswordLength)->get(); if($password===null) $password = (new PassGen)->length($this->data->conf->userTempPasswordLength)->get();
$hash = ""; $hash = "";
if(strlen($password > 0)) $hash = password_hash($password, \PASSWORD_DEFAULT); if(strlen($password > 0)) $hash = password_hash($password, \PASSWORD_DEFAULT);
$this->db->prepare("UPDATE newssync_users set password = ? where id is ?", "str", "str")->run($hash, $user); $this->db->prepare("UPDATE arsse_users set password = ? where id is ?", "str", "str")->run($hash, $user);
return $password; return $password;
} }
public function userPropertiesGet(string $user): array { public function userPropertiesGet(string $user): array {
if(!$this->data->user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!$this->data->user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
$prop = $this->db->prepare("SELECT name,rights from newssync_users where id is ?", "str")->run($user)->getRow(); $prop = $this->db->prepare("SELECT name,rights from arsse_users where id is ?", "str")->run($user)->getRow();
if(!$prop) return []; if(!$prop) return [];
return $prop; return $prop;
} }
@ -230,7 +230,7 @@ class Database {
$this->db->begin(); $this->db->begin();
foreach($valid as $prop => $type) { foreach($valid as $prop => $type) {
if(!array_key_exists($prop, $properties)) continue; if(!array_key_exists($prop, $properties)) continue;
$this->db->prepare("UPDATE newssync_users set $prop = ? where id is ?", $type, "str")->run($properties[$prop], $user); $this->db->prepare("UPDATE arsse_users set $prop = ? where id is ?", $type, "str")->run($properties[$prop], $user);
} }
$this->db->commit(); $this->db->commit();
return $this->userPropertiesGet($user); return $this->userPropertiesGet($user);
@ -238,13 +238,13 @@ class Database {
public function userRightsGet(string $user): int { public function userRightsGet(string $user): int {
if(!$this->data->user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!$this->data->user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
return (int) $this->db->prepare("SELECT rights from newssync_users where id is ?", "str")->run($user)->getValue(); return (int) $this->db->prepare("SELECT rights from arsse_users where id is ?", "str")->run($user)->getValue();
} }
public function userRightsSet(string $user, int $rights): bool { public function userRightsSet(string $user, int $rights): bool {
if(!$this->data->user->authorize($user, __FUNCTION__, $rights)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!$this->data->user->authorize($user, __FUNCTION__, $rights)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
if(!$this->userExists($user)) return false; if(!$this->userExists($user)) return false;
$this->db->prepare("UPDATE newssync_users set rights = ? where id is ?", "int", "str")->run($rights, $user); $this->db->prepare("UPDATE arsse_users set rights = ? where id is ?", "int", "str")->run($rights, $user);
return true; return true;
} }
@ -262,7 +262,7 @@ class Database {
// If the feed doesn't already exist in the database then add it to the database // If the feed doesn't already exist in the database then add it to the database
// after determining its validity with PicoFeed. // after determining its validity with PicoFeed.
$qFeed = $this->db->prepare("SELECT id from newssync_feeds where url is ? and username is ? and password is ?", "str", "str", "str"); $qFeed = $this->db->prepare("SELECT id from arsse_feeds where url is ? and username is ? and password is ?", "str", "str", "str");
$feed = $qFeed->run($url, $fetchUser, $fetchPassword)->getValue(); $feed = $qFeed->run($url, $fetchUser, $fetchPassword)->getValue();
if ($feed === null) { if ($feed === null) {
$feed = new Feed($url); $feed = new Feed($url);
@ -271,7 +271,7 @@ class Database {
// Add the feed to the database and return its Id which will be used when adding // Add the feed to the database and return its Id which will be used when adding
// its articles to the database. // its articles to the database.
$feedID = $this->db->prepare( $feedID = $this->db->prepare(
'INSERT INTO newssync_feeds(url,title,favicon,source,updated,modified,etag,username,password) 'INSERT INTO arsse_feeds(url,title,favicon,source,updated,modified,etag,username,password)
values(?,?,?,?,?,?,?,?,?)', values(?,?,?,?,?,?,?,?,?)',
'str', 'str', 'str', 'str', 'datetime', 'datetime', 'str', 'str', 'str')->run( 'str', 'str', 'str', 'str', 'datetime', 'datetime', 'str', 'str', 'str')->run(
$url, $url,
@ -293,14 +293,14 @@ class Database {
} }
// Add the feed to the user's subscriptions. // Add the feed to the user's subscriptions.
$sub = $this->db->prepare('INSERT INTO newssync_subscriptions(owner,feed) values(?,?)', 'str', 'int')->run($user, $feedID)->lastId(); $sub = $this->db->prepare('INSERT INTO arsse_subscriptions(owner,feed) values(?,?)', 'str', 'int')->run($user, $feedID)->lastId();
$this->db->commit(); $this->db->commit();
return $sub; return $sub;
} }
public function subscriptionRemove(string $user, int $id): bool { public function subscriptionRemove(string $user, int $id): bool {
if(!$this->data->user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!$this->data->user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
return (bool) $this->db->prepare("DELETE from newssync_subscriptions where id is ?", "int")->run($id)->changes(); return (bool) $this->db->prepare("DELETE from arsse_subscriptions where id is ?", "int")->run($id)->changes();
} }
public function folderAdd(string $user, array $data): int { public function folderAdd(string $user, array $data): int {
@ -326,7 +326,7 @@ class Database {
$root = null; $root = null;
} else { } else {
// if a parent is specified, make sure it exists and belongs to the user; get its root (first-level) folder if it's a nested folder // if a parent is specified, make sure it exists and belongs to the user; get its root (first-level) folder if it's a nested folder
$p = $this->db->prepare("SELECT id,root from newssync_folders where owner is ? and id is ?", "str", "int")->run($user, $parent)->getRow(); $p = $this->db->prepare("SELECT id,root from arsse_folders where owner is ? and id is ?", "str", "int")->run($user, $parent)->getRow();
if(!$p) { if(!$p) {
throw new Db\ExceptionInput("idMissing", ["action" => __FUNCTION__, "field" => "parent", 'id' => $parent]); throw new Db\ExceptionInput("idMissing", ["action" => __FUNCTION__, "field" => "parent", 'id' => $parent]);
} else { } else {
@ -336,11 +336,11 @@ class Database {
} }
// check if a folder by the same name already exists, because nulls are wonky in SQL // check if a folder by the same name already exists, because nulls are wonky in SQL
// FIXME: How should folder name be compared? Should a Unicode normalization be applied before comparison and insertion? // FIXME: How should folder name be compared? Should a Unicode normalization be applied before comparison and insertion?
if($this->db->prepare("SELECT count(*) from newssync_folders where owner is ? and parent is ? and name is ?", "str", "int", "str")->run($user, $parent, $data['name'])->getValue() > 0) { if($this->db->prepare("SELECT count(*) from arsse_folders where owner is ? and parent is ? and name is ?", "str", "int", "str")->run($user, $parent, $data['name'])->getValue() > 0) {
throw new Db\ExceptionInput("constraintViolation"); // FIXME: There needs to be a practical message here throw new Db\ExceptionInput("constraintViolation"); // FIXME: There needs to be a practical message here
} }
// actually perform the insert (!) // actually perform the insert (!)
return $this->db->prepare("INSERT INTO newssync_folders(owner,parent,root,name) values(?,?,?,?)", "str", "int", "int", "str")->run($user, $parent, $root, $data['name'])->lastId(); return $this->db->prepare("INSERT INTO arsse_folders(owner,parent,root,name) values(?,?,?,?)", "str", "int", "int", "str")->run($user, $parent, $root, $data['name'])->lastId();
} }
public function folderList(string $user, int $parent = null, bool $recursive = true): Db\Result { public function folderList(string $user, int $parent = null, bool $recursive = true): Db\Result {
@ -354,11 +354,11 @@ class Database {
} }
// if we're not returning a recursive list we can use a simpler query // if we're not returning a recursive list we can use a simpler query
if(!$recursive) { if(!$recursive) {
return $this->db->preparre("SELECT id,name,parent from newssync_folders where owner is ? and parent is ?", "str", "int")->run($user, $parent); return $this->db->preparre("SELECT id,name,parent from arsse_folders where owner is ? and parent is ?", "str", "int")->run($user, $parent);
} else { } else {
return $this->db->prepare( return $this->db->prepare(
"WITH RECURSIVE folders(id) as (SELECT id from newssync_folders where owner is ? and parent is ? union select newssync_folders.id from newssync_folders join folders on newssync_folders.parent=folders.id) ". "WITH RECURSIVE folders(id) as (SELECT id from arsse_folders where owner is ? and parent is ? union select arsse_folders.id from arsse_folders join folders on arsse_folders.parent=folders.id) ".
"SELECT id,name,parent from newssync_folders where id in(SELECT id from folders) order by name", "SELECT id,name,parent from arsse_folders where id in(SELECT id from folders) order by name",
"str", "int")->run($user, $parent); "str", "int")->run($user, $parent);
} }
} }
@ -366,7 +366,7 @@ class Database {
public function articleAdd(PicoFeed\Parser\Item $article): int { public function articleAdd(PicoFeed\Parser\Item $article): int {
$this->db->begin(); $this->db->begin();
$articleId = $this->db->prepare('INSERT INTO newssync_articles(feed,url,title,author,published,edited,guid,content,url_title_hash,url_content_hash,title_content_hash) $articleId = $this->db->prepare('INSERT INTO arsse_articles(feed,url,title,author,published,edited,guid,content,url_title_hash,url_content_hash,title_content_hash)
values(?,?,?,?,?,?,?,?,?,?,?)', values(?,?,?,?,?,?,?,?,?,?,?)',
'int', 'str', 'str', 'str', 'datetime', 'datetime', 'str', 'str', 'str', 'str', 'str')->run( 'int', 'str', 'str', 'str', 'datetime', 'datetime', 'str', 'str', 'str', 'str', 'str')->run(
$feedID, $feedID,
@ -386,7 +386,7 @@ class Database {
$categories = $article->getTag('category'); $categories = $article->getTag('category');
if (count($categories) > 0) { if (count($categories) > 0) {
foreach ($categories as $c) { foreach ($categories as $c) {
$this->db->prepare('INSERT INTO newssync_tags(article,name) values(?,?)', 'int', 'str')->run($articleId, $c); $this->db->prepare('INSERT INTO arsse_tags(article,name) values(?,?)', 'int', 'str')->run($articleId, $c);
} }
} }
@ -395,7 +395,7 @@ class Database {
} }
public function updateFeeds(): int { public function updateFeeds(): int {
$feeds = $this->db->query('SELECT id, url, username, password, DATEFORMAT("http", modified) AS lastmodified, etag FROM newssync_feeds')->getAll(); $feeds = $this->db->query('SELECT id, url, username, password, DATEFORMAT("http", modified) AS lastmodified, etag FROM arsse_feeds')->getAll();
foreach ($feeds as $f) { foreach ($feeds as $f) {
$feed = new Feed($f['url'], $f['lastmodified'], $f['etag'], $f['username'], $f['password']); $feed = new Feed($f['url'], $f['lastmodified'], $f['etag'], $f['username'], $f['password']);
// FIXME: What to do if fails? It currently throws an exception which isn't ideal here. // FIXME: What to do if fails? It currently throws an exception which isn't ideal here.
@ -405,7 +405,7 @@ class Database {
$feed->parse(); $feed->parse();
$this->db->begin(); $this->db->begin();
$articles = $this->db->prepare('SELECT id, url, title, author, DATEFORMAT("http", edited) AS edited_date, guid, content, url_title_hash, url_content_hash, title_content_hash FROM newssync_articles WHERE feed is ? ORDER BY id', 'int')->run($f['id'])->getAll(); $articles = $this->db->prepare('SELECT id, url, title, author, DATEFORMAT("http", edited) AS edited_date, guid, content, url_title_hash, url_content_hash, title_content_hash FROM arsse_articles WHERE feed is ? ORDER BY id', 'int')->run($f['id'])->getAll();
foreach ($feed->data->items as $i) { foreach ($feed->data->items as $i) {
// Iterate through the articles in the database to determine a match for the one // Iterate through the articles in the database to determine a match for the one
@ -449,7 +449,7 @@ class Database {
} }
if ($update) { if ($update) {
$this->db->prepare('UPDATE newssync_articles SET url = ?, title = ?, author = ?, published = ?, edited = ?, modified = ?, guid = ?, content = ?, url_title_hash = ?, url_content_hash = ?, title_content_hash = ? WHERE id is ?', 'str', 'str', 'str', 'datetime', 'datetime', 'datetime', 'str', 'str', 'str', 'str', 'str', 'int')->run( $this->db->prepare('UPDATE arsse_articles SET url = ?, title = ?, author = ?, published = ?, edited = ?, modified = ?, guid = ?, content = ?, url_title_hash = ?, url_content_hash = ?, title_content_hash = ? WHERE id is ?', 'str', 'str', 'str', 'datetime', 'datetime', 'datetime', 'str', 'str', 'str', 'str', 'str', 'int')->run(
$i->url, $i->url,
$i->title, $i->title,
$i->author, $i->author,
@ -469,7 +469,7 @@ class Database {
} }
// Lastly update the feed database itself with updated information. // Lastly update the feed database itself with updated information.
$this->db->prepare('UPDATE newssync_feeds SET url = ?, title = ?, favicon = ?, source = ?, updated = ?, modified = ?, etag = ? WHERE id is ?', 'str', 'str', 'str', 'str', 'datetime', 'datetime', 'str', 'int')->run( $this->db->prepare('UPDATE arsse_feeds SET url = ?, title = ?, favicon = ?, source = ?, updated = ?, modified = ?, etag = ? WHERE id is ?', 'str', 'str', 'str', 'str', 'datetime', 'datetime', 'str', 'int')->run(
$feed->feedUrl, $feed->feedUrl,
$feed->title, $feed->title,
$feed->favicon, $feed->favicon,
@ -489,13 +489,13 @@ class Database {
public function folderRemove(string $user, int $id): bool { public function folderRemove(string $user, int $id): bool {
if(!$this->data->user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!$this->data->user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
// common table expression to list all descendant folders of the target folder // common table expression to list all descendant folders of the target folder
$cte = "RECURSIVE folders(id) as (SELECT id from newssync_folders where owner is ? and id is ? union select newssync_folders.id from newssync_folders join folders on newssync_folders.parent=folders.id) "; $cte = "RECURSIVE folders(id) as (SELECT id from arsse_folders where owner is ? and id is ? union select arsse_folders.id from arsse_folders join folders on arsse_folders.parent=folders.id) ";
$changes = 0; $changes = 0;
$this->db->begin(); $this->db->begin();
// first delete any feed subscriptions contained within the folder tree (this may not be necesary because of foreign keys) // first delete any feed subscriptions contained within the folder tree (this may not be necesary because of foreign keys)
$changes += $this->db->prepare("WITH $cte"."DELETE FROM newssync_subscriptions where folder in(select id from folders)", "str", "int")->run($user, $id)->changes(); $changes += $this->db->prepare("WITH $cte"."DELETE FROM arsse_subscriptions where folder in(select id from folders)", "str", "int")->run($user, $id)->changes();
// next delete the folders themselves // next delete the folders themselves
$changes += $this->db->prepare("WITH $cte"."DELETE FROM newssync_folders where id in(select id from folders)", "str", "int")->run($user, $id)->changes(); $changes += $this->db->prepare("WITH $cte"."DELETE FROM arsse_folders where id in(select id from folders)", "str", "int")->run($user, $id)->changes();
$this->db->commit(); $this->db->commit();
return (bool) $changes; return (bool) $changes;
} }

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Db; namespace JKingWeb\Arsse\Db;
use JKingWeb\DrUUID\UUID as UUID; use JKingWeb\DrUUID\UUID as UUID;
abstract class AbstractDriver implements Driver { abstract class AbstractDriver implements Driver {
@ -8,21 +8,21 @@ abstract class AbstractDriver implements Driver {
public function schemaVersion(): int { public function schemaVersion(): int {
try { try {
return (int) $this->query("SELECT value from newssync_settings where key is schema_version")->getValue(); return (int) $this->query("SELECT value from arsse_settings where key is schema_version")->getValue();
} catch(Exception $e) { } catch(Exception $e) {
return 0; return 0;
} }
} }
public function begin(): bool { public function begin(): bool {
$this->exec("SAVEPOINT newssync_".(++$this->transDepth)); $this->exec("SAVEPOINT arsse_".(++$this->transDepth));
return true; return true;
} }
public function commit(bool $all = false): bool { public function commit(bool $all = false): bool {
if($this->transDepth==0) return false; if($this->transDepth==0) return false;
if(!$all) { if(!$all) {
$this->exec("RELEASE SAVEPOINT newssync_".($this->transDepth--)); $this->exec("RELEASE SAVEPOINT arsse_".($this->transDepth--));
} else { } else {
$this->exec("COMMIT TRANSACTION"); $this->exec("COMMIT TRANSACTION");
$this->transDepth = 0; $this->transDepth = 0;
@ -33,9 +33,9 @@ abstract class AbstractDriver implements Driver {
public function rollback(bool $all = false): bool { public function rollback(bool $all = false): bool {
if($this->transDepth==0) return false; if($this->transDepth==0) return false;
if(!$all) { if(!$all) {
$this->exec("ROLLBACK TRANSACTION TO SAVEPOINT newssync_".($this->transDepth)); $this->exec("ROLLBACK TRANSACTION TO SAVEPOINT arsse_".($this->transDepth));
// rollback to savepoint does not collpase the savepoint // rollback to savepoint does not collpase the savepoint
$this->exec("RELEASE SAVEPOINT newssync_".($this->transDepth--)); $this->exec("RELEASE SAVEPOINT arsse_".($this->transDepth--));
} else { } else {
$this->exec("ROLLBACK TRANSACTION"); $this->exec("ROLLBACK TRANSACTION");
$this->transDepth = 0; $this->transDepth = 0;
@ -48,23 +48,23 @@ abstract class AbstractDriver implements Driver {
if($this->isLocked()) return false; if($this->isLocked()) return false;
$uuid = UUID::mintStr(); $uuid = UUID::mintStr();
try { try {
$this->prepare("INSERT INTO newssync_settings(key,value) values(?,?)", "str", "str")->run("lock", $uuid); $this->prepare("INSERT INTO arsse_settings(key,value) values(?,?)", "str", "str")->run("lock", $uuid);
} catch(ExceptionInput $e) { } catch(ExceptionInput $e) {
return false; return false;
} }
sleep(1); sleep(1);
return ($this->query("SELECT value from newssync_settings where key is 'lock'")->getValue() == $uuid); return ($this->query("SELECT value from arsse_settings where key is 'lock'")->getValue() == $uuid);
} }
public function unlock(): bool { public function unlock(): bool {
if($this->schemaVersion() < 1) return true; if($this->schemaVersion() < 1) return true;
$this->exec("DELETE from newssync_settings where key is 'lock'"); $this->exec("DELETE from arsse_settings where key is 'lock'");
return true; return true;
} }
public function isLocked(): bool { public function isLocked(): bool {
if($this->schemaVersion() < 1) return false; if($this->schemaVersion() < 1) return false;
return ($this->query("SELECT count(*) from newssync_settings where key is 'lock'")->getValue() > 0); return ($this->query("SELECT count(*) from arsse_settings where key is 'lock'")->getValue() > 0);
} }
public function prepare(string $query, string ...$paramType): Statement { public function prepare(string $query, string ...$paramType): Statement {

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Db; namespace JKingWeb\Arsse\Db;
abstract class AbstractStatement implements Statement { abstract class AbstractStatement implements Statement {

View file

@ -1,9 +1,9 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Db; namespace JKingWeb\Arsse\Db;
interface Driver { interface Driver {
function __construct(\JKingWeb\NewsSync\RuntimeData $data, bool $install = false); function __construct(\JKingWeb\Arsse\RuntimeData $data, bool $install = false);
// 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)
static function driverName(): string; static function driverName(): string;
// returns the version of the scheme of the opened database; if uninitialized should return 0 // returns the version of the scheme of the opened database; if uninitialized should return 0

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Db; namespace JKingWeb\Arsse\Db;
class Exception extends \JKingWeb\NewsSync\AbstractException { class Exception extends \JKingWeb\Arsse\AbstractException {
} }

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Db; namespace JKingWeb\Arsse\Db;
class ExceptionInput extends \JKingWeb\NewsSync\AbstractException { class ExceptionInput extends \JKingWeb\Arsse\AbstractException {
} }

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Db; namespace JKingWeb\Arsse\Db;
class ExceptionTimeout extends \JKingWeb\NewsSync\AbstractException { class ExceptionTimeout extends \JKingWeb\Arsse\AbstractException {
} }

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Db; namespace JKingWeb\Arsse\Db;
interface Result extends \Iterator { interface Result extends \Iterator {
function current(); function current();

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Db\SQLite3; namespace JKingWeb\Arsse\Db\SQLite3;
class CustomFunctions { class CustomFunctions {
// Converts from SQLite3's date format to a specified standard date format. // Converts from SQLite3's date format to a specified standard date format.

View file

@ -1,13 +1,13 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Db\SQLite3; namespace JKingWeb\Arsse\Db\SQLite3;
use JKingWeb\NewsSync\Lang; use JKingWeb\Arsse\Lang;
use JKingWeb\NewsSync\Db\Exception; use JKingWeb\Arsse\Db\Exception;
use JKingWeb\NewsSync\Db\ExceptionInput; use JKingWeb\Arsse\Db\ExceptionInput;
use JKingWeb\NewsSync\Db\ExceptionTimeout; use JKingWeb\Arsse\Db\ExceptionTimeout;
class Driver extends \JKingWeb\NewsSync\Db\AbstractDriver { class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
use ExceptionBuilder; use ExceptionBuilder;
const SQLITE_BUSY = 5; const SQLITE_BUSY = 5;
@ -17,7 +17,7 @@ class Driver extends \JKingWeb\NewsSync\Db\AbstractDriver {
protected $db; protected $db;
protected $data; protected $data;
public function __construct(\JKingWeb\NewsSync\RuntimeData $data, bool $install = false) { public function __construct(\JKingWeb\Arsse\RuntimeData $data, bool $install = false) {
// check to make sure required extension is loaded // check to make sure required extension is loaded
if(!class_exists("SQLite3")) throw new Exception("extMissing", self::driverName()); if(!class_exists("SQLite3")) throw new Exception("extMissing", self::driverName());
$this->data = $data; $this->data = $data;
@ -115,7 +115,7 @@ class Driver extends \JKingWeb\NewsSync\Db\AbstractDriver {
} }
} }
public function query(string $query): \JKingWeb\NewsSync\Db\Result { public function query(string $query): \JKingWeb\Arsse\Db\Result {
try { try {
$r = $this->db->query($query); $r = $this->db->query($query);
} catch(\Exception $e) { } catch(\Exception $e) {
@ -127,7 +127,7 @@ class Driver extends \JKingWeb\NewsSync\Db\AbstractDriver {
return new Result($r, [$changes, $lastId]); return new Result($r, [$changes, $lastId]);
} }
public function prepareArray(string $query, array $paramTypes): \JKingWeb\NewsSync\Db\Statement { public function prepareArray(string $query, array $paramTypes): \JKingWeb\Arsse\Db\Statement {
try { try {
$s = $this->db->prepare($query); $s = $this->db->prepare($query);
} catch(\Exception $e) { } catch(\Exception $e) {

View file

@ -1,9 +1,9 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Db\SQLite3; namespace JKingWeb\Arsse\Db\SQLite3;
use JKingWeb\NewsSync\Db\Exception; use JKingWeb\Arsse\Db\Exception;
use JKingWeb\NewsSync\Db\ExceptionInput; use JKingWeb\Arsse\Db\ExceptionInput;
use JKingWeb\NewsSync\Db\ExceptionTimeout; use JKingWeb\Arsse\Db\ExceptionTimeout;
trait ExceptionBuilder { trait ExceptionBuilder {

View file

@ -1,8 +1,8 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Db\SQLite3; namespace JKingWeb\Arsse\Db\SQLite3;
class Result implements \JKingWeb\NewsSync\Db\Result { class Result implements \JKingWeb\Arsse\Db\Result {
protected $st; protected $st;
protected $set; protected $set;
protected $pos = 0; protected $pos = 0;

View file

@ -1,11 +1,11 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Db\SQLite3; namespace JKingWeb\Arsse\Db\SQLite3;
use JKingWeb\NewsSync\Db\Exception; use JKingWeb\Arsse\Db\Exception;
use JKingWeb\NewsSync\Db\ExceptionInput; use JKingWeb\Arsse\Db\ExceptionInput;
use JKingWeb\NewsSync\Db\ExceptionTimeout; use JKingWeb\Arsse\Db\ExceptionTimeout;
class Statement extends \JKingWeb\NewsSync\Db\AbstractStatement { class Statement extends \JKingWeb\Arsse\Db\AbstractStatement {
use ExceptionBuilder; use ExceptionBuilder;
const SQLITE_BUSY = 5; const SQLITE_BUSY = 5;
@ -46,7 +46,7 @@ class Statement extends \JKingWeb\NewsSync\Db\AbstractStatement {
])[$part]; ])[$part];
} }
public function runArray(array $values = null): \JKingWeb\NewsSync\Db\Result { public function runArray(array $values = null): \JKingWeb\Arsse\Db\Result {
$this->st->clear(); $this->st->clear();
$l = sizeof($values); $l = sizeof($values);
for($a = 0; $a < $l; $a++) { for($a = 0; $a < $l; $a++) {

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Db; namespace JKingWeb\Arsse\Db;
interface Statement { interface Statement {
const TS_TIME = -1; const TS_TIME = -1;

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
class Exception extends AbstractException { class Exception extends AbstractException {
} }

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
class ExceptionFatal extends AbstractException { class ExceptionFatal extends AbstractException {
public function __construct($msg = "", $code = 0, $e = null) { public function __construct($msg = "", $code = 0, $e = null) {

View file

@ -1,5 +1,5 @@
<?php <?php
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
use PicoFeed\Reader\Reader; use PicoFeed\Reader\Reader;
use PicoFeed\PicoFeedException; use PicoFeed\PicoFeedException;
use PicoFeed\Reader\Favicon; use PicoFeed\Reader\Favicon;

View file

@ -1,8 +1,8 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Feed; namespace JKingWeb\Arsse\Feed;
class Exception extends \JKingWeb\NewsSync\AbstractException { class Exception extends \JKingWeb\Arsse\AbstractException {
public function __construct($url, \Throwable $e) { public function __construct($url, \Throwable $e) {
$className = get_class($e); $className = get_class($e);
// Convert the exception thrown by PicoFeed to the one to be thrown here. // Convert the exception thrown by PicoFeed to the one to be thrown here.

View file

@ -1,19 +1,19 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
use \Webmozart\Glob\Glob; use \Webmozart\Glob\Glob;
class Lang { class Lang {
const DEFAULT = "en"; // fallback locale const DEFAULT = "en"; // fallback locale
const REQUIRED = [ // collection of absolutely required strings to handle pathological errors const REQUIRED = [ // collection of absolutely required strings to handle pathological errors
'Exception.JKingWeb/NewsSync/Exception.uncoded' => 'The specified exception symbol {0} has no code specified in AbstractException.php', 'Exception.JKingWeb/Arsse/Exception.uncoded' => 'The specified exception symbol {0} has no code specified in AbstractException.php',
'Exception.JKingWeb/NewsSync/Exception.unknown' => 'An unknown error has occurred', 'Exception.JKingWeb/Arsse/Exception.unknown' => 'An unknown error has occurred',
'Exception.JKingWeb/NewsSync/Lang/Exception.defaultFileMissing' => 'Default language file "{0}" missing', 'Exception.JKingWeb/Arsse/Lang/Exception.defaultFileMissing' => 'Default language file "{0}" missing',
'Exception.JKingWeb/NewsSync/Lang/Exception.fileMissing' => 'Language file "{0}" is not available', 'Exception.JKingWeb/Arsse/Lang/Exception.fileMissing' => 'Language file "{0}" is not available',
'Exception.JKingWeb/NewsSync/Lang/Exception.fileUnreadable' => 'Insufficient permissions to read language file "{0}"', 'Exception.JKingWeb/Arsse/Lang/Exception.fileUnreadable' => 'Insufficient permissions to read language file "{0}"',
'Exception.JKingWeb/NewsSync/Lang/Exception.fileCorrupt' => 'Language file "{0}" is corrupt or does not conform to expected format', 'Exception.JKingWeb/Arsse/Lang/Exception.fileCorrupt' => 'Language file "{0}" is corrupt or does not conform to expected format',
'Exception.JKingWeb/NewsSync/Lang/Exception.stringMissing' => 'Message string "{msgID}" missing from all loaded language files ({fileList})', 'Exception.JKingWeb/Arsse/Lang/Exception.stringMissing' => 'Message string "{msgID}" missing from all loaded language files ({fileList})',
'Exception.JKingWeb/NewsSync/Lang/Exception.stringInvalid' => 'Message string "{msgID}" is not a valid ICU message string (language files loaded: {fileList})', 'Exception.JKingWeb/Arsse/Lang/Exception.stringInvalid' => 'Message string "{msgID}" is not a valid ICU message string (language files loaded: {fileList})',
]; ];
static public $path = BASE."locale".DIRECTORY_SEPARATOR; // path to locale files; this is a public property to facilitate unit testing static public $path = BASE."locale".DIRECTORY_SEPARATOR; // path to locale files; this is a public property to facilitate unit testing

View file

@ -1,8 +1,8 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Lang; namespace JKingWeb\Arsse\Lang;
class Exception extends \JKingWeb\NewsSync\AbstractException { class Exception extends \JKingWeb\Arsse\AbstractException {
static $test = false; // used during PHPUnit testing only static $test = false; // used during PHPUnit testing only
function __construct(string $msgID = "", $vars = null, \Throwable $e = null) { function __construct(string $msgID = "", $vars = null, \Throwable $e = null) {

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
class REST { class REST {
protected $apis = [ protected $apis = [

View file

@ -1,9 +1,9 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\REST; namespace JKingWeb\Arsse\REST;
abstract class AbstractHandler implements Handler { abstract class AbstractHandler implements Handler {
abstract function __construct(\JKingWeb\NewsSync\RuntimeData $data); abstract function __construct(\JKingWeb\Arsse\RuntimeData $data);
abstract function dispatch(Request $req): Response; abstract function dispatch(Request $req): Response;
protected function parseURL(string $url): array { protected function parseURL(string $url): array {

View file

@ -1,8 +1,8 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\REST; namespace JKingWeb\Arsse\REST;
interface Handler { interface Handler {
function __construct(\JKingWeb\NewsSync\RuntimeData $data); function __construct(\JKingWeb\Arsse\RuntimeData $data);
function dispatch(Request $req): Response; function dispatch(Request $req): Response;
} }

View file

@ -1,14 +1,14 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\REST\NextCloudNews; namespace JKingWeb\Arsse\REST\NextCloudNews;
use JKingWeb\NewsSync\REST\Response; use JKingWeb\Arsse\REST\Response;
class Versions extends \JKingWeb\NewsSync\REST\AbstractHandler { class Versions extends \JKingWeb\Arsse\REST\AbstractHandler {
function __construct(\JKingWeb\NewsSync\RuntimeData $data) { function __construct(\JKingWeb\Arsse\RuntimeData $data) {
// runtime data is not needed; this method is deliberately empty // runtime data is not needed; this method is deliberately empty
} }
function dispatch(\JKingWeb\NewsSync\REST\Request $req): \JKingWeb\NewsSync\REST\Response { function dispatch(\JKingWeb\Arsse\REST\Request $req): \JKingWeb\Arsse\REST\Response {
// parse the URL and populate $path and $query // parse the URL and populate $path and $query
extract($this->parseURL($req->url)); extract($this->parseURL($req->url));
// if a method other than GET was used, this is an error // if a method other than GET was used, this is an error

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\REST; namespace JKingWeb\Arsse\REST;
class Request { class Request {
public $method = "GET"; public $method = "GET";

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\REST; namespace JKingWeb\Arsse\REST;
class Response { class Response {
const T_JSON = "application/json"; const T_JSON = "application/json";

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
class RuntimeData { class RuntimeData {
public $conf; public $conf;

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
class User { class User {
public $id = null; public $id = null;
@ -23,7 +23,7 @@ class User {
return $classes; return $classes;
} }
public function __construct(\JKingWeb\NewsSync\RuntimeData $data) { public function __construct(\JKingWeb\Arsse\RuntimeData $data) {
$this->data = $data; $this->data = $data;
$driver = $data->conf->userDriver; $driver = $data->conf->userDriver;
$this->u = new $driver($data); $this->u = new $driver($data);

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\User; namespace JKingWeb\Arsse\User;
Interface Driver { Interface Driver {
const FUNC_NOT_IMPLEMENTED = 0; const FUNC_NOT_IMPLEMENTED = 0;
@ -14,7 +14,7 @@ Interface Driver {
const RIGHTS_GLOBAL_ADMIN = 100; // is completely unrestricted const RIGHTS_GLOBAL_ADMIN = 100; // is completely unrestricted
// returns an instance of a class implementing this interface. Implemented as a static method for consistency with database classes // returns an instance of a class implementing this interface. Implemented as a static method for consistency with database classes
function __construct(\JKingWeb\NewsSync\RuntimeData $data); function __construct(\JKingWeb\Arsse\RuntimeData $data);
// 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)
static function driverName(): string; static function driverName(): string;
// returns an array (or single queried member of same) of methods defined by this interface and whether the class implements the internal function or a custom version // returns an array (or single queried member of same) of methods defined by this interface and whether the class implements the internal function or a custom version

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\User; namespace JKingWeb\Arsse\User;
class Exception extends \JKingWeb\NewsSync\AbstractException { class Exception extends \JKingWeb\Arsse\AbstractException {
} }

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\User; namespace JKingWeb\Arsse\User;
class ExceptionAuthz extends Exception { class ExceptionAuthz extends Exception {
} }

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\User; namespace JKingWeb\Arsse\User;
class ExceptionNotImplemented extends Exception { class ExceptionNotImplemented extends Exception {
} }

View file

@ -1,8 +1,8 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\User\Internal; namespace JKingWeb\Arsse\User\Internal;
use JKingWeb\NewsSync\Lang; use JKingWeb\Arsse\Lang;
use JKingWeb\NewsSync\User\Driver as Iface; use JKingWeb\Arsse\User\Driver as Iface;
final class Driver implements Iface { final class Driver implements Iface {
use InternalFunctions; use InternalFunctions;
@ -22,7 +22,7 @@ final class Driver implements Iface {
"userRightsSet" => Iface::FUNC_INTERNAL, "userRightsSet" => Iface::FUNC_INTERNAL,
]; ];
static public function create(\JKingWeb\NewsSync\RuntimeData $data): Driver { static public function create(\JKingWeb\Arsse\RuntimeData $data): Driver {
return new static($data); return new static($data);
} }

View file

@ -1,11 +1,11 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\User\Internal; namespace JKingWeb\Arsse\User\Internal;
trait InternalFunctions { trait InternalFunctions {
protected $actor = []; protected $actor = [];
public function __construct(\JKingWeb\NewsSync\RuntimeData $data) { public function __construct(\JKingWeb\Arsse\RuntimeData $data) {
$this->data = $data; $this->data = $data;
$this->db = $this->data->db; $this->db = $this->data->db;
} }

View file

@ -5,64 +5,64 @@ return [
'Driver.Db.SQLite3.Name' => 'SQLite 3', 'Driver.Db.SQLite3.Name' => 'SQLite 3',
// this should only be encountered in testing (because tests should cover all exceptions!) // this should only be encountered in testing (because tests should cover all exceptions!)
'Exception.JKingWeb/NewsSync/Exception.uncoded' => 'The specified exception symbol {0} has no code specified in AbstractException.php', 'Exception.JKingWeb/Arsse/Exception.uncoded' => 'The specified exception symbol {0} has no code specified in AbstractException.php',
// this should not usually be encountered // this should not usually be encountered
'Exception.JKingWeb/NewsSync/Exception.unknown' => 'An unknown error has occurred', 'Exception.JKingWeb/Arsse/Exception.unknown' => 'An unknown error has occurred',
'Exception.JKingWeb/NewsSync/Lang/Exception.defaultFileMissing' => 'Default language file "{0}" missing', 'Exception.JKingWeb/Arsse/Lang/Exception.defaultFileMissing' => 'Default language file "{0}" missing',
'Exception.JKingWeb/NewsSync/Lang/Exception.fileMissing' => 'Language file "{0}" is not available', 'Exception.JKingWeb/Arsse/Lang/Exception.fileMissing' => 'Language file "{0}" is not available',
'Exception.JKingWeb/NewsSync/Lang/Exception.fileUnreadable' => 'Insufficient permissions to read language file "{0}"', 'Exception.JKingWeb/Arsse/Lang/Exception.fileUnreadable' => 'Insufficient permissions to read language file "{0}"',
'Exception.JKingWeb/NewsSync/Lang/Exception.fileCorrupt' => 'Language file "{0}" is corrupt or does not conform to expected format', 'Exception.JKingWeb/Arsse/Lang/Exception.fileCorrupt' => 'Language file "{0}" is corrupt or does not conform to expected format',
'Exception.JKingWeb/NewsSync/Lang/Exception.stringMissing' => 'Message string "{msgID}" missing from all loaded language files ({fileList})', 'Exception.JKingWeb/Arsse/Lang/Exception.stringMissing' => 'Message string "{msgID}" missing from all loaded language files ({fileList})',
'Exception.JKingWeb/NewsSync/Lang/Exception.stringInvalid' => 'Message string "{msgID}" is not a valid ICU message string (language files loaded: {fileList})', 'Exception.JKingWeb/Arsse/Lang/Exception.stringInvalid' => 'Message string "{msgID}" is not a valid ICU message string (language files loaded: {fileList})',
'Exception.JKingWeb/NewsSync/Conf/Exception.fileMissing' => 'Configuration file "{0}" does not exist', 'Exception.JKingWeb/Arsse/Conf/Exception.fileMissing' => 'Configuration file "{0}" does not exist',
'Exception.JKingWeb/NewsSync/Conf/Exception.fileUnreadable' => 'Insufficient permissions to read configuration file "{0}"', 'Exception.JKingWeb/Arsse/Conf/Exception.fileUnreadable' => 'Insufficient permissions to read configuration file "{0}"',
'Exception.JKingWeb/NewsSync/Conf/Exception.fileUncreatable' => 'Insufficient permissions to write new configuration file "{0}"', 'Exception.JKingWeb/Arsse/Conf/Exception.fileUncreatable' => 'Insufficient permissions to write new configuration file "{0}"',
'Exception.JKingWeb/NewsSync/Conf/Exception.fileUnwritable' => 'Insufficient permissions to overwrite configuration file "{0}"', 'Exception.JKingWeb/Arsse/Conf/Exception.fileUnwritable' => 'Insufficient permissions to overwrite configuration file "{0}"',
'Exception.JKingWeb/NewsSync/Conf/Exception.fileCorrupt' => 'Configuration file "{0}" is corrupt or does not conform to expected format', 'Exception.JKingWeb/Arsse/Conf/Exception.fileCorrupt' => 'Configuration file "{0}" is corrupt or does not conform to expected format',
'Exception.JKingWeb/NewsSync/Db/Exception.extMissing' => 'Required PHP extension for driver "{0}" not installed', 'Exception.JKingWeb/Arsse/Db/Exception.extMissing' => 'Required PHP extension for driver "{0}" not installed',
'Exception.JKingWeb/NewsSync/Db/Exception.fileMissing' => 'Database file "{0}" does not exist', 'Exception.JKingWeb/Arsse/Db/Exception.fileMissing' => 'Database file "{0}" does not exist',
'Exception.JKingWeb/NewsSync/Db/Exception.fileUnreadable' => 'Insufficient permissions to open database file "{0}" for reading', 'Exception.JKingWeb/Arsse/Db/Exception.fileUnreadable' => 'Insufficient permissions to open database file "{0}" for reading',
'Exception.JKingWeb/NewsSync/Db/Exception.fileUnwritable' => 'Insufficient permissions to open database file "{0}" for writing', 'Exception.JKingWeb/Arsse/Db/Exception.fileUnwritable' => 'Insufficient permissions to open database file "{0}" for writing',
'Exception.JKingWeb/NewsSync/Db/Exception.fileUnusable' => 'Insufficient permissions to open database file "{0}" for reading or writing', 'Exception.JKingWeb/Arsse/Db/Exception.fileUnusable' => 'Insufficient permissions to open database file "{0}" for reading or writing',
'Exception.JKingWeb/NewsSync/Db/Exception.fileUncreatable' => 'Insufficient permissions to create new database file "{0}"', 'Exception.JKingWeb/Arsse/Db/Exception.fileUncreatable' => 'Insufficient permissions to create new database file "{0}"',
'Exception.JKingWeb/NewsSync/Db/Exception.fileCorrupt' => 'Database file "{0}" is corrupt or not a valid database', 'Exception.JKingWeb/Arsse/Db/Exception.fileCorrupt' => 'Database file "{0}" is corrupt or not a valid database',
'Exception.JKingWeb/NewsSync/Db/Exception.paramTypeInvalid' => 'Prepared statement parameter type "{0}" is invalid', 'Exception.JKingWeb/Arsse/Db/Exception.paramTypeInvalid' => 'Prepared statement parameter type "{0}" is invalid',
'Exception.JKingWeb/NewsSync/Db/Exception.paramTypeUnknown' => 'Prepared statement parameter type "{0}" is valid, but not implemented', 'Exception.JKingWeb/Arsse/Db/Exception.paramTypeUnknown' => 'Prepared statement parameter type "{0}" is valid, but not implemented',
'Exception.JKingWeb/NewsSync/Db/Exception.paramTypeMissing' => 'Prepared statement parameter type for parameter #{0} was not specified', 'Exception.JKingWeb/Arsse/Db/Exception.paramTypeMissing' => 'Prepared statement parameter type for parameter #{0} was not specified',
'Exception.JKingWeb/NewsSync/Db/Exception.updateManual' => 'Exception.JKingWeb/Arsse/Db/Exception.updateManual' =>
'{from_version, select, '{from_version, select,
0 {{driver_name} database is configured for manual updates and is not initialized; please populate the database with the base schema} 0 {{driver_name} database is configured for manual updates and is not initialized; please populate the database with the base schema}
other {{driver_name} database is configured for manual updates; please update from schema version {current} to version {target}} other {{driver_name} database is configured for manual updates; please update from schema version {current} to version {target}}
}', }',
'Exception.JKingWeb/NewsSync/Db/Exception.updateManualOnly' => 'Exception.JKingWeb/Arsse/Db/Exception.updateManualOnly' =>
'{from_version, select, '{from_version, select,
0 {{driver_name} database must be updated manually and is not initialized; please populate the database with the base schema} 0 {{driver_name} database must be updated manually and is not initialized; please populate the database with the base schema}
other {{driver_name} database must be updated manually; please update from schema version {current} to version {target}} other {{driver_name} database must be updated manually; please update from schema version {current} to version {target}}
}', }',
'Exception.JKingWeb/NewsSync/Db/Exception.updateFileMissing' => 'Automatic updating of the {driver_name} database failed due to instructions for updating from version {current} not being available', 'Exception.JKingWeb/Arsse/Db/Exception.updateFileMissing' => 'Automatic updating of the {driver_name} database failed due to instructions for updating from version {current} not being available',
'Exception.JKingWeb/NewsSync/Db/Exception.updateFileUnreadable' => 'Automatic updating of the {driver_name} database failed due to insufficient permissions to read instructions for updating from version {current}', 'Exception.JKingWeb/Arsse/Db/Exception.updateFileUnreadable' => 'Automatic updating of the {driver_name} database failed due to insufficient permissions to read instructions for updating from version {current}',
'Exception.JKingWeb/NewsSync/Db/Exception.updateFileUnusable' => 'Automatic updating of the {driver_name} database failed due to an error reading instructions for updating from version {current}', 'Exception.JKingWeb/Arsse/Db/Exception.updateFileUnusable' => 'Automatic updating of the {driver_name} database failed due to an error reading instructions for updating from version {current}',
'Exception.JKingWeb/NewsSync/Db/Exception.updateFileError' => 'Automatic updating of the {driver_name} database failed updating from version {current} with the following error: "{message}"', 'Exception.JKingWeb/Arsse/Db/Exception.updateFileError' => 'Automatic updating of the {driver_name} database failed updating from version {current} with the following error: "{message}"',
'Exception.JKingWeb/NewsSync/Db/Exception.updateFileIncomplete' => 'Automatic updating of the {driver_name} database failed due to instructions for updating from version {current} being incomplete', 'Exception.JKingWeb/Arsse/Db/Exception.updateFileIncomplete' => 'Automatic updating of the {driver_name} database failed due to instructions for updating from version {current} being incomplete',
'Exception.JKingWeb/NewsSync/Db/Exception.updateTooNew' => 'Exception.JKingWeb/Arsse/Db/Exception.updateTooNew' =>
'{difference, select, '{difference, select,
0 {Automatic updating of the {driver_name} database failed because it is already up to date with the requested version, {target}} 0 {Automatic updating of the {driver_name} database failed because it is already up to date with the requested version, {target}}
other {Automatic updating of the {driver_name} database failed because its version, {current}, is newer than the requested version, {target}} other {Automatic updating of the {driver_name} database failed because its version, {current}, is newer than the requested version, {target}}
}', }',
'Exception.JKingWeb/NewsSync/Db/Exception.engineErrorGeneral' => '{0}', 'Exception.JKingWeb/Arsse/Db/Exception.engineErrorGeneral' => '{0}',
'Exception.JKingWeb/NewsSync/Db/ExceptionInput.missing' => 'Required field "{field}" missing while performing action "{action}"', 'Exception.JKingWeb/Arsse/Db/ExceptionInput.missing' => 'Required field "{field}" missing while performing action "{action}"',
'Exception.JKingWeb/NewsSync/Db/ExceptionInput.whitespace' => 'Required field "{field}" of action "{action}" may not contain only whitespace', 'Exception.JKingWeb/Arsse/Db/ExceptionInput.whitespace' => 'Required field "{field}" of action "{action}" may not contain only whitespace',
'Exception.JKingWeb/NewsSync/Db/ExceptionInput.tooLong' => 'Required field "{field}" of action "{action}" has a maximum length of {max}', 'Exception.JKingWeb/Arsse/Db/ExceptionInput.tooLong' => 'Required field "{field}" of action "{action}" has a maximum length of {max}',
'Exception.JKingWeb/NewsSync/Db/ExceptionInput.tooShort' => 'Required field "{field}" of action "{action}" has a minimum length of {min}', 'Exception.JKingWeb/Arsse/Db/ExceptionInput.tooShort' => 'Required field "{field}" of action "{action}" has a minimum length of {min}',
'Exception.JKingWeb/NewsSync/Db/ExceptionInput.idMissing' => 'Referenced ID ({id}) in field "{field}" does not exist', 'Exception.JKingWeb/Arsse/Db/ExceptionInput.idMissing' => 'Referenced ID ({id}) in field "{field}" does not exist',
'Exception.JKingWeb/NewsSync/Db/ExceptionInput.constraintViolation' => '{0}', 'Exception.JKingWeb/Arsse/Db/ExceptionInput.constraintViolation' => '{0}',
'Exception.JKingWeb/NewsSync/Db/ExceptionInput.typeViolation' => '{0}', 'Exception.JKingWeb/Arsse/Db/ExceptionInput.typeViolation' => '{0}',
'Exception.JKingWeb/NewsSync/Db/ExceptionTimeout.general' => '{0}', 'Exception.JKingWeb/Arsse/Db/ExceptionTimeout.general' => '{0}',
'Exception.JKingWeb/NewsSync/User/Exception.alreadyExists' => 'Could not perform action "{action}" because the user {user} already exists', 'Exception.JKingWeb/Arsse/User/Exception.alreadyExists' => 'Could not perform action "{action}" because the user {user} already exists',
'Exception.JKingWeb/NewsSync/User/Exception.doesNotExist' => 'Could not perform action "{action}" because the user {user} does not exist', 'Exception.JKingWeb/Arsse/User/Exception.doesNotExist' => 'Could not perform action "{action}" because the user {user} does not exist',
'Exception.JKingWeb/NewsSync/User/Exception.authMissing' => 'Please log in to proceed', 'Exception.JKingWeb/Arsse/User/Exception.authMissing' => 'Please log in to proceed',
'Exception.JKingWeb/NewsSync/User/Exception.authFailed' => 'Authentication failed', 'Exception.JKingWeb/Arsse/User/Exception.authFailed' => 'Authentication failed',
'Exception.JKingWeb/NewsSync/User/ExceptionAuthz.notAuthorized' => 'Exception.JKingWeb/Arsse/User/ExceptionAuthz.notAuthorized' =>
'{action, select, '{action, select,
userList {{user, select, userList {{user, select,
global {Authenticated user is not authorized to view the global user list} global {Authenticated user is not authorized to view the global user list}
@ -70,15 +70,15 @@ return [
}} }}
other {Authenticated user is not authorized to perform the action "{action}" on behalf of {user}} other {Authenticated user is not authorized to perform the action "{action}" on behalf of {user}}
}', }',
'Exception.JKingWeb/NewsSync/Feed/Exception.invalidCertificate' => 'Could not download feed "{url}" because its server is serving an invalid SSL certificate', 'Exception.JKingWeb/Arsse/Feed/Exception.invalidCertificate' => 'Could not download feed "{url}" because its server is serving an invalid SSL certificate',
'Exception.JKingWeb/NewsSync/Feed/Exception.invalidURL' => 'Feed URL "{url}" is invalid', 'Exception.JKingWeb/Arsse/Feed/Exception.invalidURL' => 'Feed URL "{url}" is invalid',
'Exception.JKingWeb/NewsSync/Feed/Exception.maxRedirect' => 'Could not download feed "{url}" because its server reached its maximum number of HTTP redirections', 'Exception.JKingWeb/Arsse/Feed/Exception.maxRedirect' => 'Could not download feed "{url}" because its server reached its maximum number of HTTP redirections',
'Exception.JKingWeb/NewsSync/Feed/Exception.maxSize' => 'Could not download feed "{url}" because its size exceeds the maximum allowed on its server', 'Exception.JKingWeb/Arsse/Feed/Exception.maxSize' => 'Could not download feed "{url}" because its size exceeds the maximum allowed on its server',
'Exception.JKingWeb/NewsSync/Feed/Exception.timeout' => 'Could not download feed "{url}" because its server timed out', 'Exception.JKingWeb/Arsse/Feed/Exception.timeout' => 'Could not download feed "{url}" because its server timed out',
'Exception.JKingWeb/NewsSync/Feed/Exception.forbidden' => 'Could not download feed "{url}" because you do not have permission to access it', 'Exception.JKingWeb/Arsse/Feed/Exception.forbidden' => 'Could not download feed "{url}" because you do not have permission to access it',
'Exception.JKingWeb/NewsSync/Feed/Exception.unauthorized' => 'Could not download feed "{url}" because you provided insufficient or invalid credentials', 'Exception.JKingWeb/Arsse/Feed/Exception.unauthorized' => 'Could not download feed "{url}" because you provided insufficient or invalid credentials',
'Exception.JKingWeb/NewsSync/Feed/Exception.malformed' => 'Could not parse feed "{url}" because it is malformed', 'Exception.JKingWeb/Arsse/Feed/Exception.malformed' => 'Could not parse feed "{url}" because it is malformed',
'Exception.JKingWeb/NewsSync/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/NewsSync/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/NewsSync/Feed/Exception.unsupportedFormat' => 'Feed "{url}" is of an unsupported format' 'Exception.JKingWeb/Arsse/Feed/Exception.unsupportedFormat' => 'Feed "{url}" is of an unsupported format'
]; ];

View file

@ -1,5 +1,5 @@
-- settings -- settings
create table newssync_settings( create table arsse_settings(
key varchar(255) primary key not null, -- setting key key varchar(255) primary key not null, -- setting key
value varchar(255), -- setting value, serialized as a string value varchar(255), -- setting value, serialized as a string
type varchar(255) not null check( type varchar(255) not null check(
@ -8,7 +8,7 @@ create table newssync_settings(
) without rowid; ) without rowid;
-- users -- users
create table newssync_users( create table arsse_users(
id TEXT primary key not null, -- user id id TEXT primary key not null, -- user id
password TEXT, -- password, salted and hashed; if using external authentication this would be blank password TEXT, -- password, salted and hashed; if using external authentication this would be blank
name TEXT, -- display name name TEXT, -- display name
@ -19,7 +19,7 @@ create table newssync_users(
) without rowid; ) without rowid;
-- newsfeeds, deduplicated -- newsfeeds, deduplicated
create table newssync_feeds( create table arsse_feeds(
id integer primary key not null, -- sequence number id integer primary key not null, -- sequence number
url TEXT not null, -- URL of feed url TEXT not null, -- URL of feed
title TEXT, -- default title of feed title TEXT, -- default title of feed
@ -36,23 +36,23 @@ create table newssync_feeds(
); );
-- users' subscriptions to newsfeeds, with settings -- users' subscriptions to newsfeeds, with settings
create table newssync_subscriptions( create table arsse_subscriptions(
id integer primary key not null, -- sequence number id integer primary key not null, -- sequence number
owner TEXT not null references newssync_users(id) on delete cascade on update cascade, -- owner of subscription owner TEXT not null references arsse_users(id) on delete cascade on update cascade, -- owner of subscription
feed integer not null references newssync_feeds(id) on delete cascade, -- feed for the subscription feed integer not null references arsse_feeds(id) on delete cascade, -- feed for the subscription
added datetime not null default CURRENT_TIMESTAMP, -- time at which feed was added added datetime not null default CURRENT_TIMESTAMP, -- time at which feed was added
modified datetime not null default CURRENT_TIMESTAMP, -- date at which subscription properties were last modified modified datetime not null default CURRENT_TIMESTAMP, -- date at which subscription properties were last modified
title TEXT, -- user-supplied title title TEXT, -- user-supplied title
order_type int not null default 0, -- NextCloud sort order order_type int not null default 0, -- NextCloud sort order
pinned boolean not null default 0, -- whether feed is pinned (always sorts at top) pinned boolean not null default 0, -- whether feed is pinned (always sorts at top)
folder integer references newssync_folders(id) on delete cascade, -- TT-RSS category (nestable); the first-level category (which acts as NextCloud folder) is joined in when needed folder integer references arsse_folders(id) on delete cascade, -- TT-RSS category (nestable); the first-level category (which acts as NextCloud folder) is joined in when needed
unique(owner,feed) -- a given feed should only appear once for a given owner unique(owner,feed) -- a given feed should only appear once for a given owner
); );
-- TT-RSS categories and NextCloud folders -- TT-RSS categories and NextCloud folders
create table newssync_folders( create table arsse_folders(
id integer primary key not null, -- sequence number id integer primary key not null, -- sequence number
owner TEXT not null references newssync_users(id) on delete cascade on update cascade, -- owner of folder owner TEXT not null references arsse_users(id) on delete cascade on update cascade, -- owner of folder
parent integer default null, -- parent folder id parent integer default null, -- parent folder id
root integer default null, -- first-level folder (NextCloud folder) root integer default null, -- first-level folder (NextCloud folder)
name TEXT not null, -- folder name name TEXT not null, -- folder name
@ -61,9 +61,9 @@ create table newssync_folders(
); );
-- entries in newsfeeds -- entries in newsfeeds
create table newssync_articles( create table arsse_articles(
id integer primary key not null, -- sequence number id integer primary key not null, -- sequence number
feed integer not null references newssync_feeds(id) on delete cascade, -- feed for the subscription feed integer not null references arsse_feeds(id) on delete cascade, -- feed for the subscription
url TEXT not null, -- URL of article url TEXT not null, -- URL of article
title TEXT, -- article title title TEXT, -- article title
author TEXT, -- author's name author TEXT, -- author's name
@ -78,35 +78,35 @@ create table newssync_articles(
); );
-- enclosures associated with articles -- enclosures associated with articles
create table newssync_enclosures( create table arsse_enclosures(
article integer not null references newssync_articles(id) on delete cascade, article integer not null references arsse_articles(id) on delete cascade,
url TEXT, url TEXT,
type varchar(255) type varchar(255)
); );
-- users' actions on newsfeed entries -- users' actions on newsfeed entries
create table newssync_subscription_articles( create table arsse_subscription_articles(
id integer primary key not null, id integer primary key not null,
article integer not null references newssync_articles(id) on delete cascade, article integer not null references arsse_articles(id) on delete 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 datetime not null default CURRENT_TIMESTAMP modified datetime not null default CURRENT_TIMESTAMP
); );
-- user labels associated with newsfeed entries -- user labels associated with newsfeed entries
create table newssync_labels( create table arsse_labels(
sub_article integer not null references newssync_subscription_articles(id) on delete cascade, -- sub_article integer not null references arsse_subscription_articles(id) on delete cascade, --
owner TEXT not null references newssync_users(id) on delete cascade on update cascade, owner TEXT not null references arsse_users(id) on delete cascade on update cascade,
name TEXT name TEXT
); );
create index newssync_label_names on newssync_labels(name); create index arsse_label_names on arsse_labels(name);
-- author labels ("categories" in RSS/Atom parlance) associated with newsfeed entries -- author labels ("categories" in RSS/Atom parlance) associated with newsfeed entries
create table newssync_tags( create table arsse_tags(
article integer not null references newssync_articles(id) on delete cascade, article integer not null references arsse_articles(id) on delete cascade,
name TEXT name TEXT
); );
-- set version marker -- set version marker
pragma user_version = 1; pragma user_version = 1;
insert into newssync_settings values('schema_version',1,'int'); insert into arsse_settings values('schema_version',1,'int');

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
use \org\bovigo\vfs\vfsStream; use \org\bovigo\vfs\vfsStream;

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase { class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase {
@ -267,7 +267,7 @@ class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase {
$this->assertFalse($this->drv->isLocked()); $this->assertFalse($this->drv->isLocked());
$this->assertTrue($this->drv->lock()); $this->assertTrue($this->drv->lock());
$this->assertFalse($this->drv->isLocked()); $this->assertFalse($this->drv->isLocked());
$this->drv->exec("CREATE TABLE newssync_settings(key primary key, value, type) without rowid; PRAGMA user_version=1"); $this->drv->exec("CREATE TABLE arsse_settings(key primary key, value, type) without rowid; PRAGMA user_version=1");
$this->assertTrue($this->drv->lock()); $this->assertTrue($this->drv->lock());
$this->assertTrue($this->drv->isLocked()); $this->assertTrue($this->drv->isLocked());
$this->assertFalse($this->drv->lock()); $this->assertFalse($this->drv->lock());

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
class TestDbResultSQLite3 extends \PHPUnit\Framework\TestCase { class TestDbResultSQLite3 extends \PHPUnit\Framework\TestCase {

View file

@ -1,7 +1,7 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
use JKingWeb\NewsSync\Db\Statement; use JKingWeb\Arsse\Db\Statement;
class TestDbStatementSQLite3 extends \PHPUnit\Framework\TestCase { class TestDbStatementSQLite3 extends \PHPUnit\Framework\TestCase {

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
use \org\bovigo\vfs\vfsStream; use \org\bovigo\vfs\vfsStream;
@ -12,7 +12,7 @@ class TestDbUpdateSQLite3 extends \PHPUnit\Framework\TestCase {
protected $vfs; protected $vfs;
protected $base; protected $base;
const MINIMAL1 = "create table newssync_settings(key text primary key not null, value text, type text not null); pragma user_version=1"; const MINIMAL1 = "create table arsse_settings(key text primary key not null, value text, type text not null); pragma user_version=1";
const MINIMAL2 = "pragma user_version=2"; const MINIMAL2 = "pragma user_version=2";
function setUp() { function setUp() {
@ -51,7 +51,7 @@ class TestDbUpdateSQLite3 extends \PHPUnit\Framework\TestCase {
} }
function testLoadIncompleteFile() { function testLoadIncompleteFile() {
file_put_contents($this->base."0.sql", "create table newssync_settings(key text primary key not null, value text, type text not null);"); file_put_contents($this->base."0.sql", "create table arsse_settings(key text primary key not null, value text, type text not null);");
$this->assertException("updateFileIncomplete", "Db"); $this->assertException("updateFileIncomplete", "Db");
$this->drv->schemaUpdate(1); $this->drv->schemaUpdate(1);
} }

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
class TestDatabase extends \PHPUnit\Framework\TestCase { class TestDatabase extends \PHPUnit\Framework\TestCase {

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
class TestException extends \PHPUnit\Framework\TestCase { class TestException extends \PHPUnit\Framework\TestCase {

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
use \org\bovigo\vfs\vfsStream; use \org\bovigo\vfs\vfsStream;
@ -43,7 +43,7 @@ class TestLang extends \PHPUnit\Framework\TestCase {
function testLoadDefaultLanguage() { function testLoadDefaultLanguage() {
$this->assertEquals(Lang::DEFAULT, Lang::set(Lang::DEFAULT, true)); $this->assertEquals(Lang::DEFAULT, Lang::set(Lang::DEFAULT, true));
$str = Lang::dump(); $str = Lang::dump();
$this->assertArrayHasKey('Exception.JKingWeb/NewsSync/Exception.uncoded', $str); $this->assertArrayHasKey('Exception.JKingWeb/Arsse/Exception.uncoded', $str);
$this->assertArrayHasKey('Test.presentText', $str); $this->assertArrayHasKey('Test.presentText', $str);
} }
@ -54,7 +54,7 @@ class TestLang extends \PHPUnit\Framework\TestCase {
Lang::set(Lang::DEFAULT, true); Lang::set(Lang::DEFAULT, true);
$this->assertEquals("ja", Lang::set("ja", true)); $this->assertEquals("ja", Lang::set("ja", true));
$str = Lang::dump(); $str = Lang::dump();
$this->assertArrayHasKey('Exception.JKingWeb/NewsSync/Exception.uncoded', $str); $this->assertArrayHasKey('Exception.JKingWeb/Arsse/Exception.uncoded', $str);
$this->assertArrayHasKey('Test.presentText', $str); $this->assertArrayHasKey('Test.presentText', $str);
$this->assertArrayHasKey('Test.absentText', $str); $this->assertArrayHasKey('Test.absentText', $str);
} }

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
use \org\bovigo\vfs\vfsStream; use \org\bovigo\vfs\vfsStream;

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
use \org\bovigo\vfs\vfsStream; use \org\bovigo\vfs\vfsStream;
@ -64,7 +64,7 @@ class TestLangComplex extends \PHPUnit\Framework\TestCase {
*/ */
function testFetchAMessageWithSingleNumericParameter() { function testFetchAMessageWithSingleNumericParameter() {
Lang::set("en_ca", true); Lang::set("en_ca", true);
$this->assertEquals('Default language file "en" missing', Lang::msg('Exception.JKingWeb/NewsSync/Lang/Exception.defaultFileMissing', Lang::DEFAULT)); $this->assertEquals('Default language file "en" missing', Lang::msg('Exception.JKingWeb/Arsse/Lang/Exception.defaultFileMissing', Lang::DEFAULT));
} }
/** /**
@ -79,7 +79,7 @@ class TestLangComplex extends \PHPUnit\Framework\TestCase {
* @depends testFetchAMessage * @depends testFetchAMessage
*/ */
function testFetchAMessageWithNamedParameters() { function testFetchAMessageWithNamedParameters() {
$this->assertEquals('Message string "Test.absentText" missing from all loaded language files (en)', Lang::msg('Exception.JKingWeb/NewsSync/Lang/Exception.stringMissing', ['msgID' => 'Test.absentText', 'fileList' => 'en'])); $this->assertEquals('Message string "Test.absentText" missing from all loaded language files (en)', Lang::msg('Exception.JKingWeb/Arsse/Lang/Exception.stringMissing', ['msgID' => 'Test.absentText', 'fileList' => 'en']));
} }
/** /**

View file

@ -1,8 +1,8 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
use JKingWeb\NewsSync\Rest\Request; use JKingWeb\Arsse\Rest\Request;
use JKingWeb\NewsSync\Rest\Response; use JKingWeb\Arsse\Rest\Response;
class TestNCNVersionDiscovery extends \PHPUnit\Framework\TestCase { class TestNCNVersionDiscovery extends \PHPUnit\Framework\TestCase {

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
class TestAuthorization extends \PHPUnit\Framework\TestCase { class TestAuthorization extends \PHPUnit\Framework\TestCase {

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
class TestUserInternalDriver extends \PHPUnit\Framework\TestCase { class TestUserInternalDriver extends \PHPUnit\Framework\TestCase {

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
class TestUserMockExternal extends \PHPUnit\Framework\TestCase { class TestUserMockExternal extends \PHPUnit\Framework\TestCase {

View file

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
class TestUserMockInternal extends \PHPUnit\Framework\TestCase { class TestUserMockInternal extends \PHPUnit\Framework\TestCase {

View file

@ -1,7 +1,7 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Test\Db; namespace JKingWeb\Arsse\Test\Db;
use JKingWeb\NewsSync\Db\Statement; use JKingWeb\Arsse\Db\Statement;
trait BindingTests { trait BindingTests {
function testBindNull() { function testBindNull() {

View file

@ -1,9 +1,9 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Test\Db; namespace JKingWeb\Arsse\Test\Db;
trait Tools { trait Tools {
function prime(\JKingWeb\NewsSync\Db\Driver $drv, array $data): bool { function prime(\JKingWeb\Arsse\Db\Driver $drv, array $data): bool {
$drv->begin(); $drv->begin();
foreach($data as $table => $info) { foreach($data as $table => $info) {
$cols = implode(",", array_keys($info['columns'])); $cols = implode(",", array_keys($info['columns']));
@ -18,7 +18,7 @@ trait Tools {
return true; return true;
} }
function compare(\JKingWeb\NewsSync\Db\Driver $drv, array $expected): bool { function compare(\JKingWeb\Arsse\Db\Driver $drv, array $expected): bool {
foreach($expected as $table => $info) { foreach($expected as $table => $info) {
$cols = implode(",", array_keys($info['columns'])); $cols = implode(",", array_keys($info['columns']));
foreach($drv->prepare("SELECT $cols from $table")->run() as $num => $row) { foreach($drv->prepare("SELECT $cols from $table")->run() as $num => $row) {

View file

@ -1,14 +1,14 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Test\Lang; namespace JKingWeb\Arsse\Test\Lang;
use \org\bovigo\vfs\vfsStream, \JKingWeb\NewsSync\Lang; use \org\bovigo\vfs\vfsStream, \JKingWeb\Arsse\Lang;
trait Setup { trait Setup {
static function setUpBeforeClass() { static function setUpBeforeClass() {
// this is required to keep from having exceptions in Lang::msg() in turn calling Lang::msg() and looping // this is required to keep from having exceptions in Lang::msg() in turn calling Lang::msg() and looping
\JKingWeb\NewsSync\Lang\Exception::$test = true; \JKingWeb\Arsse\Lang\Exception::$test = true;
// test files // test files
self::$files = [ self::$files = [
'en.php' => '<?php return ["Test.presentText" => "and the Philosopher\'s Stone"];', 'en.php' => '<?php return ["Test.presentText" => "and the Philosopher\'s Stone"];',
@ -38,7 +38,7 @@ trait Setup {
} }
static function tearDownAfterClass() { static function tearDownAfterClass() {
\JKingWeb\NewsSync\Lang\Exception::$test = false; \JKingWeb\Arsse\Lang\Exception::$test = false;
Lang::$path = self::$defaultPath; Lang::$path = self::$defaultPath;
self::$path = null; self::$path = null;
self::$vfs = null; self::$vfs = null;

View file

@ -1,13 +1,13 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Test; namespace JKingWeb\Arsse\Test;
class RuntimeData extends \JKingWeb\NewsSync\RuntimeData { class RuntimeData extends \JKingWeb\Arsse\RuntimeData {
public $conf; public $conf;
public $db; public $db;
public $user; public $user;
public function __construct(\JKingWeb\NewsSync\Conf $conf = null) { public function __construct(\JKingWeb\Arsse\Conf $conf = null) {
$this->conf = $conf; $this->conf = $conf;
} }
} }

View file

@ -1,11 +1,11 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Test; namespace JKingWeb\Arsse\Test;
use \JKingWeb\NewsSync\Exception; use \JKingWeb\Arsse\Exception;
trait Tools { trait Tools {
function assertException(string $msg, string $prefix = "", string $type = "Exception") { function assertException(string $msg, string $prefix = "", string $type = "Exception") {
$class = \JKingWeb\NewsSync\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];

View file

@ -1,7 +1,7 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Test\User; namespace JKingWeb\Arsse\Test\User;
use JKingWeb\NewsSync\User\Driver; use JKingWeb\Arsse\User\Driver;
trait CommonTests { trait CommonTests {
function testListUsers() { function testListUsers() {

View file

@ -1,16 +1,16 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Test\User; namespace JKingWeb\Arsse\Test\User;
use JKingWeb\NewsSync\User\Driver; use JKingWeb\Arsse\User\Driver;
use JKingWeb\NewsSync\User\Exception; use JKingWeb\Arsse\User\Exception;
use JKingWeb\NewsSync\User\ExceptionAuthz; use JKingWeb\Arsse\User\ExceptionAuthz;
use PasswordGenerator\Generator as PassGen; use PasswordGenerator\Generator as PassGen;
class Database extends DriverSkeleton { class Database extends DriverSkeleton {
public $db = []; public $db = [];
public function __construct(\JKingWeb\NewsSync\RuntimeData $data) { public function __construct(\JKingWeb\Arsse\RuntimeData $data) {
$this->data = $data; $this->data = $data;
} }

View file

@ -1,8 +1,8 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Test\User; namespace JKingWeb\Arsse\Test\User;
use JKingWeb\NewsSync\User\Driver; use JKingWeb\Arsse\User\Driver;
use JKingWeb\NewsSync\User\Exception; use JKingWeb\Arsse\User\Exception;
use PasswordGenerator\Generator as PassGen; use PasswordGenerator\Generator as PassGen;
class DriverExternalMock extends DriverSkeleton implements Driver { class DriverExternalMock extends DriverSkeleton implements Driver {
@ -22,7 +22,7 @@ class DriverExternalMock extends DriverSkeleton implements Driver {
"userRightsSet" => Driver::FUNC_EXTERNAL, "userRightsSet" => Driver::FUNC_EXTERNAL,
]; ];
static public function create(\JKingWeb\NewsSync\RuntimeData $data): Driver { static public function create(\JKingWeb\Arsse\RuntimeData $data): Driver {
return new static($data); return new static($data);
} }
@ -39,7 +39,7 @@ class DriverExternalMock extends DriverSkeleton implements Driver {
} }
} }
public function __construct(\JKingWeb\NewsSync\RuntimeData $data) { public function __construct(\JKingWeb\Arsse\RuntimeData $data) {
$this->data = $data; $this->data = $data;
} }

View file

@ -1,7 +1,7 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Test\User; namespace JKingWeb\Arsse\Test\User;
use JKingWeb\NewsSync\User\Driver; use JKingWeb\Arsse\User\Driver;
class DriverInternalMock extends Database implements Driver { class DriverInternalMock extends Database implements Driver {
@ -20,7 +20,7 @@ class DriverInternalMock extends Database implements Driver {
"userRightsSet" => Driver::FUNC_INTERNAL, "userRightsSet" => Driver::FUNC_INTERNAL,
]; ];
static public function create(\JKingWeb\NewsSync\RuntimeData $data): Driver { static public function create(\JKingWeb\Arsse\RuntimeData $data): Driver {
return new static($data); return new static($data);
} }
@ -37,7 +37,7 @@ class DriverInternalMock extends Database implements Driver {
} }
} }
public function __construct(\JKingWeb\NewsSync\RuntimeData $data) { public function __construct(\JKingWeb\Arsse\RuntimeData $data) {
$this->data = $data; $this->data = $data;
} }

View file

@ -1,10 +1,10 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\NewsSync\Test\User; namespace JKingWeb\Arsse\Test\User;
use JKingWeb\NewsSync\Lang; use JKingWeb\Arsse\Lang;
use JKingWeb\NewsSync\User\Driver; use JKingWeb\Arsse\User\Driver;
use JKingWeb\NewsSync\User\Exception; use JKingWeb\Arsse\User\Exception;
use JKingWeb\NewsSync\User\ExceptionAuthz; use JKingWeb\Arsse\User\ExceptionAuthz;
use PasswordGenerator\Generator as PassGen; use PasswordGenerator\Generator as PassGen;
abstract class DriverSkeleton { abstract class DriverSkeleton {

View file

@ -1,5 +1,5 @@
<?php <?php
namespace JKingWeb\NewsSync; namespace JKingWeb\Arsse;
const INSTALL = true; const INSTALL = true;
require_once "../bootstrap.php"; require_once "../bootstrap.php";