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

Changed Misc\DateFormatter to a collection of static methods and renamed it to Date; renamed Data to Arsse to avoid confusion and better reflect its centrality

This commit is contained in:
J. King 2017-07-17 07:47:57 -04:00
parent fd1f23fd82
commit da092d5f8c
38 changed files with 719 additions and 734 deletions

View file

@ -1,7 +1,7 @@
<?php <?php
namespace JKingWeb\Arsse; namespace JKingWeb\Arsse;
require_once __DIR__.DIRECTORY_SEPARATOR."bootstrap.php"; require_once __DIR__.DIRECTORY_SEPARATOR."bootstrap.php";
Data::load(new Conf()); Arsse::load(new Conf());
if(\PHP_SAPI=="cli") { if(\PHP_SAPI=="cli") {
(new Service)->watch(); (new Service)->watch();

View file

@ -83,7 +83,7 @@ abstract class AbstractException extends \Exception {
$code = self::CODES[$codeID]; $code = self::CODES[$codeID];
$msg = "Exception.".str_replace("\\", "/", $class).".$msgID"; $msg = "Exception.".str_replace("\\", "/", $class).".$msgID";
} }
$msg = Data::$lang->msg($msg, $vars); $msg = Arsse::$lang->msg($msg, $vars);
} }
parent::__construct($msg, $code, $e); parent::__construct($msg, $code, $e);
} }

View file

@ -2,22 +2,14 @@
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse; namespace JKingWeb\Arsse;
class Data { class Arsse {
/** /** @var Lang */
* @var Lang
*/
public static $lang; public static $lang;
/** /** @var Conf */
* @var Conf
*/
public static $conf; public static $conf;
/** /** @var Database */
* @var Database
*/
public static $db; public static $db;
/** /** @var User */
* @var User
*/
public static $user; public static $user;
static function load(Conf $conf) { static function load(Conf $conf) {

View file

@ -4,23 +4,20 @@ namespace JKingWeb\Arsse;
use PasswordGenerator\Generator as PassGen; use PasswordGenerator\Generator as PassGen;
use JKingWeb\Arsse\Misc\Query; use JKingWeb\Arsse\Misc\Query;
use JKingWeb\Arsse\Misc\Context; use JKingWeb\Arsse\Misc\Context;
use JKingWeb\Arsse\Misc\Date;
class Database { class Database {
use Misc\DateFormatter;
const SCHEMA_VERSION = 1; const SCHEMA_VERSION = 1;
const FORMAT_TS = "Y-m-d h:i:s"; const FORMAT_TS = "Y-m-d h:i:s";
const FORMAT_DATE = "Y-m-d"; const FORMAT_DATE = "Y-m-d";
const FORMAT_TIME = "h:i:s"; const FORMAT_TIME = "h:i:s";
/** /** @var Db\Driver */
* @var Db\Driver
*/
public $db; public $db;
public function __construct() { public function __construct() {
$driver = Data::$conf->dbDriver; $driver = Arsse::$conf->dbDriver;
$this->db = new $driver(INSTALL); $this->db = new $driver(INSTALL);
$ver = $this->db->schemaVersion(); $ver = $this->db->schemaVersion();
if(!INSTALL && $ver < self::SCHEMA_VERSION) { if(!INSTALL && $ver < self::SCHEMA_VERSION) {
@ -103,14 +100,14 @@ class Database {
} }
public function userExists(string $user): bool { public function userExists(string $user): bool {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
return (bool) $this->db->prepare("SELECT count(*) from arsse_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 {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
if($this->userExists($user)) throw new User\Exception("alreadyExists", ["action" => __FUNCTION__, "user" => $user]); if($this->userExists($user)) throw new User\Exception("alreadyExists", ["action" => __FUNCTION__, "user" => $user]);
if($password===null) $password = (new PassGen)->length(Data::$conf->userTempPasswordLength)->get(); if($password===null) $password = (new PassGen)->length(Arsse::$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 arsse_users(id,password) values(?,?)", "str", "str")->runArray([$user,$hash]); $this->db->prepare("INSERT INTO arsse_users(id,password) values(?,?)", "str", "str")->runArray([$user,$hash]);
@ -118,7 +115,7 @@ class Database {
} }
public function userRemove(string $user): bool { public function userRemove(string $user): bool {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["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]); 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;
} }
@ -126,14 +123,14 @@ class Database {
public function userList(string $domain = null): array { public function userList(string $domain = null): array {
$out = []; $out = [];
if($domain !== null) { if($domain !== null) {
if(!Data::$user->authorize("@".$domain, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $domain]); if(!Arsse::$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;
foreach($this->db->prepare("SELECT id from arsse_users where id like ?", "str")->run($domain) as $user) { foreach($this->db->prepare("SELECT id from arsse_users where id like ?", "str")->run($domain) as $user) {
$out[] = $user['id']; $out[] = $user['id'];
} }
} else { } else {
if(!Data::$user->authorize("", __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => "global"]); if(!Arsse::$user->authorize("", __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => "global"]);
foreach($this->db->prepare("SELECT id from arsse_users")->run() as $user) { foreach($this->db->prepare("SELECT id from arsse_users")->run() as $user) {
$out[] = $user['id']; $out[] = $user['id'];
} }
@ -142,15 +139,15 @@ class Database {
} }
public function userPasswordGet(string $user): string { public function userPasswordGet(string $user): string {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$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 arsse_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 {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$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]);
if($password===null) $password = (new PassGen)->length(Data::$conf->userTempPasswordLength)->get(); if($password===null) $password = (new PassGen)->length(Arsse::$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 arsse_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);
@ -158,14 +155,14 @@ class Database {
} }
public function userPropertiesGet(string $user): array { public function userPropertiesGet(string $user): array {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
$prop = $this->db->prepare("SELECT name,rights from arsse_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) throw new User\Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); if(!$prop) throw new User\Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]);
return $prop; return $prop;
} }
public function userPropertiesSet(string $user, array $properties): array { public function userPropertiesSet(string $user, array $properties): array {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$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]);
$valid = [ // FIXME: add future properties $valid = [ // FIXME: add future properties
"name" => "str", "name" => "str",
@ -176,12 +173,12 @@ class Database {
} }
public function userRightsGet(string $user): int { public function userRightsGet(string $user): int {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
return (int) $this->db->prepare("SELECT rights from arsse_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(!Data::$user->authorize($user, __FUNCTION__, $rights)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__, $rights)) 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]);
$this->db->prepare("UPDATE arsse_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;
@ -189,7 +186,7 @@ class Database {
public function folderAdd(string $user, array $data): int { public function folderAdd(string $user, array $data): int {
// If the user isn't authorized to perform this action then throw an exception. // If the user isn't authorized to perform this action then throw an exception.
if(!Data::$user->authorize($user, __FUNCTION__)) { if(!Arsse::$user->authorize($user, __FUNCTION__)) {
throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
} }
// if the desired folder name is missing or invalid, throw an exception // if the desired folder name is missing or invalid, throw an exception
@ -219,7 +216,7 @@ class Database {
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 {
// if the user isn't authorized to perform this action then throw an exception. // if the user isn't authorized to perform this action then throw an exception.
if(!Data::$user->authorize($user, __FUNCTION__)) { if(!Arsse::$user->authorize($user, __FUNCTION__)) {
throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
} }
// check to make sure the parent exists, if one is specified // check to make sure the parent exists, if one is specified
@ -240,21 +237,21 @@ class Database {
} }
public function folderRemove(string $user, int $id): bool { public function folderRemove(string $user, int $id): bool {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
$changes = $this->db->prepare("DELETE FROM arsse_folders where owner is ? and id is ?", "str", "int")->run($user, $id)->changes(); $changes = $this->db->prepare("DELETE FROM arsse_folders where owner is ? and id is ?", "str", "int")->run($user, $id)->changes();
if(!$changes) throw new Db\ExceptionInput("subjectMissing", ["action" => __FUNCTION__, "field" => "folder", 'id' => $id]); if(!$changes) throw new Db\ExceptionInput("subjectMissing", ["action" => __FUNCTION__, "field" => "folder", 'id' => $id]);
return true; return true;
} }
public function folderPropertiesGet(string $user, int $id): array { public function folderPropertiesGet(string $user, int $id): array {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
$props = $this->db->prepare("SELECT id,name,parent from arsse_folders where owner is ? and id is ?", "str", "int")->run($user, $id)->getRow(); $props = $this->db->prepare("SELECT id,name,parent from arsse_folders where owner is ? and id is ?", "str", "int")->run($user, $id)->getRow();
if(!$props) throw new Db\ExceptionInput("subjectMissing", ["action" => __FUNCTION__, "field" => "folder", 'id' => $id]); if(!$props) throw new Db\ExceptionInput("subjectMissing", ["action" => __FUNCTION__, "field" => "folder", 'id' => $id]);
return $props; return $props;
} }
public function folderPropertiesSet(string $user, int $id, array $data): bool { public function folderPropertiesSet(string $user, int $id, array $data): bool {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
// validate the folder ID and, if specified, the parent to move it to // validate the folder ID and, if specified, the parent to move it to
$parent = null; $parent = null;
if(array_key_exists("parent", $data)) $parent = $data['parent']; if(array_key_exists("parent", $data)) $parent = $data['parent'];
@ -319,7 +316,7 @@ class Database {
} }
public function subscriptionAdd(string $user, string $url, string $fetchUser = "", string $fetchPassword = ""): int { public function subscriptionAdd(string $user, string $url, string $fetchUser = "", string $fetchPassword = ""): int {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
// check to see if the feed exists // check to see if the feed exists
$feedID = $this->db->prepare("SELECT id from arsse_feeds where url is ? and username is ? and password is ?", "str", "str", "str")->run($url, $fetchUser, $fetchPassword)->getValue(); $feedID = $this->db->prepare("SELECT id from arsse_feeds where url is ? and username is ? and password is ?", "str", "str", "str")->run($url, $fetchUser, $fetchPassword)->getValue();
if(is_null($feedID)) { if(is_null($feedID)) {
@ -339,7 +336,7 @@ class Database {
} }
public function subscriptionList(string $user, int $folder = null, int $id = null): Db\Result { public function subscriptionList(string $user, int $folder = null, int $id = null): Db\Result {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
// create a complex query // create a complex query
$q = new Query( $q = new Query(
"SELECT "SELECT
@ -374,24 +371,24 @@ class Database {
} }
public function subscriptionRemove(string $user, int $id): bool { public function subscriptionRemove(string $user, int $id): bool {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
$changes = $this->db->prepare("DELETE from arsse_subscriptions where owner is ? and id is ?", "str", "int")->run($user, $id)->changes(); $changes = $this->db->prepare("DELETE from arsse_subscriptions where owner is ? and id is ?", "str", "int")->run($user, $id)->changes();
if(!$changes) throw new Db\ExceptionInput("subjectMissing", ["action" => __FUNCTION__, "field" => "folder", 'id' => $id]); if(!$changes) throw new Db\ExceptionInput("subjectMissing", ["action" => __FUNCTION__, "field" => "folder", 'id' => $id]);
return true; return true;
} }
public function subscriptionPropertiesGet(string $user, int $id): array { public function subscriptionPropertiesGet(string $user, int $id): array {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
// disable authorization checks for the list call // disable authorization checks for the list call
Data::$user->authorizationEnabled(false); Arsse::$user->authorizationEnabled(false);
$sub = $this->subscriptionList($user, null, $id)->getRow(); $sub = $this->subscriptionList($user, null, $id)->getRow();
Data::$user->authorizationEnabled(true); Arsse::$user->authorizationEnabled(true);
if(!$sub) throw new Db\ExceptionInput("subjectMissing", ["action" => __FUNCTION__, "field" => "feed", 'id' => $id]); if(!$sub) throw new Db\ExceptionInput("subjectMissing", ["action" => __FUNCTION__, "field" => "feed", 'id' => $id]);
return $sub; return $sub;
} }
public function subscriptionPropertiesSet(string $user, int $id, array $data): bool { public function subscriptionPropertiesSet(string $user, int $id, array $data): bool {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
$tr = $this->db->begin(); $tr = $this->db->begin();
if(!$this->db->prepare("SELECT count(*) from arsse_subscriptions where owner is ? and id is ?", "str", "int")->run($user, $id)->getValue()) { if(!$this->db->prepare("SELECT count(*) from arsse_subscriptions where owner is ? and id is ?", "str", "int")->run($user, $id)->getValue()) {
// if the ID doesn't exist or doesn't belong to the user, throw an exception // if the ID doesn't exist or doesn't belong to the user, throw an exception
@ -442,7 +439,7 @@ class Database {
// here. When an exception is thrown it should update the database with the // here. When an exception is thrown it should update the database with the
// error instead of failing; if other exceptions are thrown, we should simply roll back // error instead of failing; if other exceptions are thrown, we should simply roll back
try { try {
$feed = new Feed($feedID, $f['url'], (string) $this->dateTransform($f['modified'], "http", "sql"), $f['etag'], $f['username'], $f['password']); $feed = new Feed($feedID, $f['url'], (string) Date::transform($f['modified'], "http", "sql"), $f['etag'], $f['username'], $f['password']);
if(!$feed->modified) { if(!$feed->modified) {
// if the feed hasn't changed, just compute the next fetch time and record it // if the feed hasn't changed, just compute the next fetch time and record it
$this->db->prepare("UPDATE arsse_feeds SET updated = CURRENT_TIMESTAMP, next_fetch = ? WHERE id is ?", 'datetime', 'int')->run($feed->nextFetch, $feedID); $this->db->prepare("UPDATE arsse_feeds SET updated = CURRENT_TIMESTAMP, next_fetch = ? WHERE id is ?", 'datetime', 'int')->run($feed->nextFetch, $feedID);
@ -567,7 +564,7 @@ class Database {
} }
public function articleStarredCount(string $user, array $context = []): int { public function articleStarredCount(string $user, array $context = []): int {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
return $this->db->prepare( return $this->db->prepare(
"WITH RECURSIVE "WITH RECURSIVE
user(user) as (SELECT ?), user(user) as (SELECT ?),
@ -582,7 +579,7 @@ class Database {
} }
public function editionLatest(string $user, Context $context = null): int { public function editionLatest(string $user, Context $context = null): int {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
if(!$context) $context = new Context; if(!$context) $context = new Context;
$q = new Query("SELECT max(arsse_editions.id) from arsse_editions left join arsse_articles on article is arsse_articles.id left join arsse_feeds on arsse_articles.feed is arsse_feeds.id"); $q = new Query("SELECT max(arsse_editions.id) from arsse_editions left join arsse_articles on article is arsse_articles.id left join arsse_feeds on arsse_articles.feed is arsse_feeds.id");
if($context->subscription()) { if($context->subscription()) {
@ -598,7 +595,7 @@ class Database {
} }
public function articleList(string $user, Context $context = null): Db\Result { public function articleList(string $user, Context $context = null): Db\Result {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
if(!$context) $context = new Context; if(!$context) $context = new Context;
$q = new Query( $q = new Query(
"SELECT "SELECT
@ -656,7 +653,7 @@ class Database {
} }
public function articleMark(string $user, array $data, Context $context = null): bool { public function articleMark(string $user, array $data, Context $context = null): bool {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
if(!$context) $context = new Context; if(!$context) $context = new Context;
// sanitize input // sanitize input
$values = [ $values = [

View file

@ -1,9 +1,9 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Db; namespace JKingWeb\Arsse\Db;
use JKingWeb\Arsse\Misc\Date;
abstract class AbstractStatement implements Statement { abstract class AbstractStatement implements Statement {
use \JKingWeb\Arsse\Misc\DateFormatter;
protected $types = []; protected $types = [];
protected $isNullable = []; protected $isNullable = [];
@ -45,13 +45,13 @@ abstract class AbstractStatement implements Statement {
switch($t) { switch($t) {
case "date": case "date":
if(is_null($v) && !$nullable) $v = 0; if(is_null($v) && !$nullable) $v = 0;
return $this->dateTransform($v, "date"); return Date::transform($v, "date");
case "time": case "time":
if(is_null($v) && !$nullable) $v = 0; if(is_null($v) && !$nullable) $v = 0;
return $this->dateTransform($v, "time"); return Date::transform($v, "time");
case "datetime": case "datetime":
if(is_null($v) && !$nullable) $v = 0; if(is_null($v) && !$nullable) $v = 0;
return $this->dateTransform($v, "sql"); return Date::transform($v, "sql");
case "null": case "null":
case "integer": case "integer":
case "float": case "float":
@ -61,7 +61,7 @@ abstract class AbstractStatement implements Statement {
if($t=="binary") $t = "string"; if($t=="binary") $t = "string";
if($v instanceof \DateTimeInterface) { if($v instanceof \DateTimeInterface) {
if($t=="string") { if($t=="string") {
return $this->dateTransform($v, "sql"); return Date::transform($v, "sql");
} else { } else {
$v = $v->getTimestamp(); $v = $v->getTimestamp();
settype($v, $t); settype($v, $t);

View file

@ -1,7 +1,7 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Db\SQLite3; namespace JKingWeb\Arsse\Db\SQLite3;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\Db\Exception; use JKingWeb\Arsse\Db\Exception;
use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\Db\ExceptionInput;
use JKingWeb\Arsse\Db\ExceptionTimeout; use JKingWeb\Arsse\Db\ExceptionTimeout;
@ -19,10 +19,10 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
public function __construct(bool $install = false) { public function __construct(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());
$file = Data::$conf->dbSQLite3File; $file = Arsse::$conf->dbSQLite3File;
// if the file exists (or we're initializing the database), try to open it // if the file exists (or we're initializing the database), try to open it
try { try {
$this->db = $this->makeConnection($file, ($install) ? \SQLITE3_OPEN_READWRITE | \SQLITE3_OPEN_CREATE : \SQLITE3_OPEN_READWRITE, Data::$conf->dbSQLite3Key); $this->db = $this->makeConnection($file, ($install) ? \SQLITE3_OPEN_READWRITE | \SQLITE3_OPEN_CREATE : \SQLITE3_OPEN_READWRITE, Arsse::$conf->dbSQLite3Key);
} catch(\Throwable $e) { } catch(\Throwable $e) {
// if opening the database doesn't work, check various pre-conditions to find out what the problem might be // if opening the database doesn't work, check various pre-conditions to find out what the problem might be
if(!file_exists($file)) { if(!file_exists($file)) {
@ -57,7 +57,7 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
static public function driverName(): string { static public function driverName(): string {
return Data::$lang->msg("Driver.Db.SQLite3.Name"); return Arsse::$lang->msg("Driver.Db.SQLite3.Name");
} }
public function schemaVersion(): int { public function schemaVersion(): int {
@ -66,10 +66,10 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
public function schemaUpdate(int $to): bool { public function schemaUpdate(int $to): bool {
$ver = $this->schemaVersion(); $ver = $this->schemaVersion();
if(!Data::$conf->dbAutoUpdate) throw new Exception("updateManual", ['version' => $ver, 'driver_name' => $this->driverName()]); if(!Arsse::$conf->dbAutoUpdate) throw new Exception("updateManual", ['version' => $ver, 'driver_name' => $this->driverName()]);
if($ver >= $to) throw new Exception("updateTooNew", ['difference' => ($ver - $to), 'current' => $ver, 'target' => $to, 'driver_name' => $this->driverName()]); if($ver >= $to) throw new Exception("updateTooNew", ['difference' => ($ver - $to), 'current' => $ver, 'target' => $to, 'driver_name' => $this->driverName()]);
$sep = \DIRECTORY_SEPARATOR; $sep = \DIRECTORY_SEPARATOR;
$path = Data::$conf->dbSchemaBase.$sep."SQLite3".$sep; $path = Arsse::$conf->dbSchemaBase.$sep."SQLite3".$sep;
// lock the database // lock the database
$this->savepointCreate(true); $this->savepointCreate(true);
for($a = $this->schemaVersion(); $a < $to; $a++) { for($a = $this->schemaVersion(); $a < $to; $a++) {

View file

@ -1,14 +1,13 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse; namespace JKingWeb\Arsse;
use JKingWeb\Arsse\Misc\Date;
use PicoFeed\Reader\Reader; use PicoFeed\Reader\Reader;
use PicoFeed\PicoFeedException; use PicoFeed\PicoFeedException;
use PicoFeed\Reader\Favicon; use PicoFeed\Reader\Favicon;
use PicoFeed\Config\Config; use PicoFeed\Config\Config;
class Feed { class Feed {
use Misc\DateFormatter;
public $data = null; public $data = null;
public $favicon; public $favicon;
public $parser; public $parser;
@ -26,7 +25,7 @@ class Feed {
// format the HTTP Last-Modified date returned // format the HTTP Last-Modified date returned
$lastMod = $this->resource->getLastModified(); $lastMod = $this->resource->getLastModified();
if(strlen($lastMod)) { if(strlen($lastMod)) {
$this->lastModified = $this->dateNormalize($lastMod, "http"); $this->lastModified = Date::normalize($lastMod, "http");
} }
$this->modified = $this->resource->isModified(); $this->modified = $this->resource->isModified();
//parse the feed, if it has been modified //parse the feed, if it has been modified
@ -46,11 +45,11 @@ class Feed {
public function download(string $url, string $lastModified = '', string $etag = '', string $username = '', string $password = ''): bool { public function download(string $url, string $lastModified = '', string $etag = '', string $username = '', string $password = ''): bool {
try { try {
$config = new Config; $config = new Config;
$config->setMaxBodySize(Data::$conf->fetchSizeLimit); $config->setMaxBodySize(Arsse::$conf->fetchSizeLimit);
$config->setClientTimeout(Data::$conf->fetchTimeout); $config->setClientTimeout(Arsse::$conf->fetchTimeout);
$config->setGrabberTimeout(Data::$conf->fetchTimeout); $config->setGrabberTimeout(Arsse::$conf->fetchTimeout);
$config->setClientUserAgent(Data::$conf->fetchUserAgentString); $config->setClientUserAgent(Arsse::$conf->fetchUserAgentString);
$config->setGrabberUserAgent(Data::$conf->fetchUserAgentString); $config->setGrabberUserAgent(Arsse::$conf->fetchUserAgentString);
$this->reader = new Reader($config); $this->reader = new Reader($config);
$this->resource = $this->reader->download($url, $lastModified, $etag, $username, $password); $this->resource = $this->reader->download($url, $lastModified, $etag, $username, $password);
@ -195,7 +194,7 @@ class Feed {
return true; return true;
} }
// get as many of the latest articles in the database as there are in the feed // get as many of the latest articles in the database as there are in the feed
$articles = Data::$db->feedMatchLatest($feedID, sizeof($items))->getAll(); $articles = Arsse::$db->feedMatchLatest($feedID, sizeof($items))->getAll();
// perform a first pass matching the latest articles against items in the feed // perform a first pass matching the latest articles against items in the feed
list($this->newItems, $this->changedItems) = $this->matchItems($items, $articles); list($this->newItems, $this->changedItems) = $this->matchItems($items, $articles);
if(sizeof($this->newItems) && sizeof($items) <= sizeof($articles)) { if(sizeof($this->newItems) && sizeof($items) <= sizeof($articles)) {
@ -207,7 +206,7 @@ class Feed {
if($i->urlContentHash) $hashesUC[] = $i->urlContentHash; if($i->urlContentHash) $hashesUC[] = $i->urlContentHash;
if($i->titleContentHash) $hashesTC[] = $i->titleContentHash; if($i->titleContentHash) $hashesTC[] = $i->titleContentHash;
} }
$articles = Data::$db->feedMatchIds($feedID, $ids, $hashesUT, $hashesUC, $hashesTC)->getAll(); $articles = Arsse::$db->feedMatchIds($feedID, $ids, $hashesUT, $hashesUC, $hashesTC)->getAll();
list($this->newItems, $changed) = $this->matchItems($this->newItems, $articles); list($this->newItems, $changed) = $this->matchItems($this->newItems, $articles);
// merge the two change-lists, preserving keys // merge the two change-lists, preserving keys
$this->changedItems = array_combine(array_merge(array_keys($this->changedItems), array_keys($changed)), array_merge($this->changedItems, $changed)); $this->changedItems = array_combine(array_merge(array_keys($this->changedItems), array_keys($changed)), array_merge($this->changedItems, $changed));
@ -232,7 +231,7 @@ class Feed {
($i->urlContentHash && $i->urlContentHash === $a['url_content_hash']) || ($i->urlContentHash && $i->urlContentHash === $a['url_content_hash']) ||
($i->titleContentHash && $i->titleContentHash === $a['title_content_hash']) ($i->titleContentHash && $i->titleContentHash === $a['title_content_hash'])
) { ) {
if($i->updatedDate && $this->dateTransform($i->updatedDate, "sql") !== $a['edited']) { if($i->updatedDate && Date::transform($i->updatedDate, "sql") !== $a['edited']) {
// if the item has an edit timestamp and it doesn't match that of the article in the database, the the article has been edited // if the item has an edit timestamp and it doesn't match that of the article in the database, the the article has been edited
// we store the item index and database record ID as a key/value pair // we store the item index and database record ID as a key/value pair
$found = true; $found = true;
@ -256,7 +255,7 @@ class Feed {
} }
public function computeNextFetch(): \DateTime { public function computeNextFetch(): \DateTime {
$now = $this->dateNormalize(time()); $now = Date::normalize(time());
if(!$this->modified) { if(!$this->modified) {
$diff = $now->getTimestamp() - $this->lastModified->getTimestamp(); $diff = $now->getTimestamp() - $this->lastModified->getTimestamp();
$offset = $this->normalizeDateDiff($diff); $offset = $this->normalizeDateDiff($diff);
@ -295,7 +294,7 @@ class Feed {
} else { } else {
$offset = "1 day"; $offset = "1 day";
} }
return self::dateNormalize("now + ".$offset); return Date::normalize("now + ".$offset);
} }
protected function normalizeDateDiff(int $diff): string { protected function normalizeDateDiff(int $diff): string {
@ -317,7 +316,7 @@ class Feed {
if(!$this->modified) return $this->lastModified; if(!$this->modified) return $this->lastModified;
$dates = $this->gatherDates(); $dates = $this->gatherDates();
if(sizeof($dates)) { if(sizeof($dates)) {
return $this->dateNormalize($dates[0]); return Date::normalize($dates[0]);
} else { } else {
return null; return null;
} }

View file

@ -1,10 +1,9 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Misc; namespace JKingWeb\Arsse\Misc;
use JKingWeb\Arsse\Misc\Date;
class Context { class Context {
use DateFormatter;
public $reverse = false; public $reverse = false;
public $limit = 0; public $limit = 0;
public $offset = 0; public $offset = 0;
@ -91,12 +90,12 @@ class Context {
} }
function modifiedSince($spec = null) { function modifiedSince($spec = null) {
$spec = $this->dateNormalize($spec); $spec = Date::normalize($spec);
return $this->act(__FUNCTION__, func_num_args(), $spec); return $this->act(__FUNCTION__, func_num_args(), $spec);
} }
function notModifiedSince($spec = null) { function notModifiedSince($spec = null) {
$spec = $this->dateNormalize($spec); $spec = Date::normalize($spec);
return $this->act(__FUNCTION__, func_num_args(), $spec); return $this->act(__FUNCTION__, func_num_args(), $spec);
} }

View file

@ -2,10 +2,10 @@
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Misc; namespace JKingWeb\Arsse\Misc;
trait DateFormatter { class Date {
protected function dateTransform($date, string $outFormat = null, string $inFormat = null, bool $inLocal = false) { static function transform($date, string $outFormat = null, string $inFormat = null, bool $inLocal = false) {
$date = $this->dateNormalize($date, $inFormat, $inLocal); $date = self::normalize($date, $inFormat, $inLocal);
if(is_null($date) || is_null($outFormat)) return $date; if(is_null($date) || is_null($outFormat)) return $date;
$outFormat = strtolower($outFormat); $outFormat = strtolower($outFormat);
if($outFormat=="unix") return $date->getTimestamp(); if($outFormat=="unix") return $date->getTimestamp();
@ -20,7 +20,7 @@ trait DateFormatter {
return $date->format($f); return $date->format($f);
} }
protected function dateNormalize($date, string $inFormat = null, bool $inLocal = false) { static function normalize($date, string $inFormat = null, bool $inLocal = false) {
if($date instanceof \DateTimeInterface) { if($date instanceof \DateTimeInterface) {
return $date; return $date;
} else if(is_numeric($date)) { } else if(is_numeric($date)) {

View file

@ -38,7 +38,7 @@ class REST {
$class = $this->apis[$api]['class']; $class = $this->apis[$api]['class'];
$drv = new $class(); $drv = new $class();
$out = $drv->dispatch($req); $out = $drv->dispatch($req);
header("Status: ".$out->code." ".Data::$lang->msg("HTTP.Status.".$out->code)); header("Status: ".$out->code." ".Arsse::$lang->msg("HTTP.Status.".$out->code));
if(!is_null($out->payload)) { if(!is_null($out->payload)) {
header("Content-Type: ".$out->type); header("Content-Type: ".$out->type);
switch($out->type) { switch($out->type) {

View file

@ -1,9 +1,9 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\REST; namespace JKingWeb\Arsse\REST;
use JKingWeb\Arsse\Misc\Date;
abstract class AbstractHandler implements Handler { abstract class AbstractHandler implements Handler {
use \JKingWeb\Arsse\Misc\DateFormatter;
abstract function __construct(); abstract function __construct();
abstract function dispatch(Request $req): Response; abstract function dispatch(Request $req): Response;
@ -22,7 +22,7 @@ abstract class AbstractHandler implements Handler {
foreach($map as $key => $type) { foreach($map as $key => $type) {
if(array_key_exists($key, $data)) { if(array_key_exists($key, $data)) {
if($type=="datetime" && $dateFormat != "sql") { if($type=="datetime" && $dateFormat != "sql") {
$data[$key] = $this->dateTransform($data[$key], $dateFormat, "sql"); $data[$key] = Date::transform($data[$key], $dateFormat, "sql");
} else { } else {
settype($data[$key], $type); settype($data[$key], $type);
} }
@ -71,7 +71,7 @@ abstract class AbstractHandler implements Handler {
if(is_numeric($value)) $out[$key] = (float) $value; if(is_numeric($value)) $out[$key] = (float) $value;
break; break;
case "datetime": case "datetime":
$t = $this->dateNormalize($value, $dateFormat); $t = Date::normalize($value, $dateFormat);
if($t) $out[$key] = $t; if($t) $out[$key] = $t;
break; break;
default: default:

View file

@ -1,7 +1,7 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\REST\NextCloudNews; namespace JKingWeb\Arsse\REST\NextCloudNews;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\User; use JKingWeb\Arsse\User;
use JKingWeb\Arsse\Misc\Context; use JKingWeb\Arsse\Misc\Context;
use JKingWeb\Arsse\AbstractException; use JKingWeb\Arsse\AbstractException;
@ -40,7 +40,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
function dispatch(\JKingWeb\Arsse\REST\Request $req): Response { function dispatch(\JKingWeb\Arsse\REST\Request $req): Response {
// try to authenticate // try to authenticate
if(!Data::$user->authHTTP()) return new Response(401, "", "", ['WWW-Authenticate: Basic realm="'.self::REALM.'"']); if(!Arsse::$user->authHTTP()) return new Response(401, "", "", ['WWW-Authenticate: Basic realm="'.self::REALM.'"']);
// only accept GET, POST, PUT, or DELETE // only accept GET, POST, PUT, or DELETE
if(!in_array($req->method, ["GET", "POST", "PUT", "DELETE"])) return new Response(405, "", "", ['Allow: GET, POST, PUT, DELETE']); if(!in_array($req->method, ["GET", "POST", "PUT", "DELETE"])) return new Response(405, "", "", ['Allow: GET, POST, PUT, DELETE']);
// normalize the input // normalize the input
@ -213,14 +213,14 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
// list folders // list folders
protected function folderList(array $url, array $data): Response { protected function folderList(array $url, array $data): Response {
$folders = Data::$db->folderList(Data::$user->id, null, false)->getAll(); $folders = Arsse::$db->folderList(Arsse::$user->id, null, false)->getAll();
return new Response(200, ['folders' => $folders]); return new Response(200, ['folders' => $folders]);
} }
// create a folder // create a folder
protected function folderAdd(array $url, array $data): Response { protected function folderAdd(array $url, array $data): Response {
try { try {
$folder = Data::$db->folderAdd(Data::$user->id, $data); $folder = Arsse::$db->folderAdd(Arsse::$user->id, $data);
} catch(ExceptionInput $e) { } catch(ExceptionInput $e) {
switch($e->getCode()) { switch($e->getCode()) {
// folder already exists // folder already exists
@ -232,7 +232,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
default: return new Response(400); default: return new Response(400);
} }
} }
$folder = Data::$db->folderPropertiesGet(Data::$user->id, $folder); $folder = Arsse::$db->folderPropertiesGet(Arsse::$user->id, $folder);
return new Response(200, ['folders' => [$folder]]); return new Response(200, ['folders' => [$folder]]);
} }
@ -240,7 +240,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
protected function folderRemove(array $url, array $data): Response { protected function folderRemove(array $url, array $data): Response {
// perform the deletion // perform the deletion
try { try {
Data::$db->folderRemove(Data::$user->id, (int) $url[1]); Arsse::$db->folderRemove(Arsse::$user->id, (int) $url[1]);
} catch(ExceptionInput $e) { } catch(ExceptionInput $e) {
// folder does not exist // folder does not exist
return new Response(404); return new Response(404);
@ -254,7 +254,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
if(!sizeof($data)) return new Response(422); if(!sizeof($data)) return new Response(422);
// perform the edit // perform the edit
try { try {
Data::$db->folderPropertiesSet(Data::$user->id, (int) $url[1], $data); Arsse::$db->folderPropertiesSet(Arsse::$user->id, (int) $url[1], $data);
} catch(ExceptionInput $e) { } catch(ExceptionInput $e) {
switch($e->getCode()) { switch($e->getCode()) {
// folder does not exist // folder does not exist
@ -285,7 +285,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
$c->folder((int) $url[1]); $c->folder((int) $url[1]);
// perform the operation // perform the operation
try { try {
Data::$db->articleMark(Data::$user->id, ['read' => true], $c); Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c);
} catch(ExceptionInput $e) { } catch(ExceptionInput $e) {
// folder does not exist // folder does not exist
return new Response(404); return new Response(404);
@ -296,9 +296,9 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
// return list of feeds which should be refreshed // return list of feeds which should be refreshed
protected function feedListStale(array $url, array $data): Response { protected function feedListStale(array $url, array $data): Response {
// function requires admin rights per spec // function requires admin rights per spec
if(Data::$user->rightsGet(Data::$user->id)==User::RIGHTS_NONE) return new Response(403); if(Arsse::$user->rightsGet(Arsse::$user->id)==User::RIGHTS_NONE) return new Response(403);
// list stale feeds which should be checked for updates // list stale feeds which should be checked for updates
$feeds = Data::$db->feedListStale(); $feeds = Arsse::$db->feedListStale();
$out = []; $out = [];
foreach($feeds as $feed) { foreach($feeds as $feed) {
// since in our implementation feeds don't belong the users, the 'userId' field will always be an empty string // since in our implementation feeds don't belong the users, the 'userId' field will always be an empty string
@ -310,11 +310,11 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
// refresh a feed // refresh a feed
protected function feedUpdate(array $url, array $data): Response { protected function feedUpdate(array $url, array $data): Response {
// function requires admin rights per spec // function requires admin rights per spec
if(Data::$user->rightsGet(Data::$user->id)==User::RIGHTS_NONE) return new Response(403); if(Arsse::$user->rightsGet(Arsse::$user->id)==User::RIGHTS_NONE) return new Response(403);
// perform an update of a single feed // perform an update of a single feed
if(!isset($data['feedId'])) return new Response(422); if(!isset($data['feedId'])) return new Response(422);
try { try {
Data::$db->feedUpdate($data['feedId']); Arsse::$db->feedUpdate($data['feedId']);
} catch(ExceptionInput $e) { } catch(ExceptionInput $e) {
return new Response(404); return new Response(404);
} }
@ -328,9 +328,9 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
// normalize the folder ID, if specified; zero should be transformed to null // normalize the folder ID, if specified; zero should be transformed to null
$folder = (isset($data['folderId']) && $data['folderId']) ? $data['folderId'] : null; $folder = (isset($data['folderId']) && $data['folderId']) ? $data['folderId'] : null;
// try to add the feed // try to add the feed
$tr = Data::$db->begin(); $tr = Arsse::$db->begin();
try { try {
$id = Data::$db->subscriptionAdd(Data::$user->id, $data['url']); $id = Arsse::$db->subscriptionAdd(Arsse::$user->id, $data['url']);
} catch(ExceptionInput $e) { } catch(ExceptionInput $e) {
// feed already exists // feed already exists
return new Response(409); return new Response(409);
@ -341,29 +341,29 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
// if a folder was specified, move the feed to the correct folder; silently ignore errors // if a folder was specified, move the feed to the correct folder; silently ignore errors
if($folder) { if($folder) {
try { try {
Data::$db->subscriptionPropertiesSet(Data::$user->id, $id, ['folder' => $folder]); Arsse::$db->subscriptionPropertiesSet(Arsse::$user->id, $id, ['folder' => $folder]);
} catch(ExceptionInput $e) {} } catch(ExceptionInput $e) {}
} }
$tr->commit(); $tr->commit();
// fetch the feed's metadata and format it appropriately // fetch the feed's metadata and format it appropriately
$feed = Data::$db->subscriptionPropertiesGet(Data::$user->id, $id); $feed = Arsse::$db->subscriptionPropertiesGet(Arsse::$user->id, $id);
$feed = $this->feedTranslate($feed); $feed = $this->feedTranslate($feed);
$out = ['feeds' => [$feed]]; $out = ['feeds' => [$feed]];
$newest = Data::$db->editionLatest(Data::$user->id, (new Context)->subscription($id)); $newest = Arsse::$db->editionLatest(Arsse::$user->id, (new Context)->subscription($id));
if($newest) $out['newestItemId'] = $newest; if($newest) $out['newestItemId'] = $newest;
return new Response(200, $out); return new Response(200, $out);
} }
// return list of feeds for the logged-in user // return list of feeds for the logged-in user
protected function subscriptionList(array $url, array $data): Response { protected function subscriptionList(array $url, array $data): Response {
$subs = Data::$db->subscriptionList(Data::$user->id); $subs = Arsse::$db->subscriptionList(Arsse::$user->id);
$out = []; $out = [];
foreach($subs as $sub) { foreach($subs as $sub) {
$out[] = $this->feedTranslate($sub); $out[] = $this->feedTranslate($sub);
} }
$out = ['feeds' => $out]; $out = ['feeds' => $out];
$out['starredCount'] = Data::$db->articleStarredCount(Data::$user->id); $out['starredCount'] = Arsse::$db->articleStarredCount(Arsse::$user->id);
$newest = Data::$db->editionLatest(Data::$user->id); $newest = Arsse::$db->editionLatest(Arsse::$user->id);
if($newest) $out['newestItemId'] = $newest; if($newest) $out['newestItemId'] = $newest;
return new Response(200, $out); return new Response(200, $out);
} }
@ -371,7 +371,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
// delete a feed // delete a feed
protected function subscriptionRemove(array $url, array $data): Response { protected function subscriptionRemove(array $url, array $data): Response {
try { try {
Data::$db->subscriptionRemove(Data::$user->id, (int) $url[1]); Arsse::$db->subscriptionRemove(Arsse::$user->id, (int) $url[1]);
} catch(ExceptionInput $e) { } catch(ExceptionInput $e) {
// feed does not exist // feed does not exist
return new Response(404); return new Response(404);
@ -390,7 +390,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
} }
// perform the renaming // perform the renaming
try { try {
Data::$db->subscriptionPropertiesSet(Data::$user->id, (int) $url[1], $in); Arsse::$db->subscriptionPropertiesSet(Arsse::$user->id, (int) $url[1], $in);
} catch(ExceptionInput $e) { } catch(ExceptionInput $e) {
switch($e->getCode()) { switch($e->getCode()) {
// subscription does not exist // subscription does not exist
@ -416,7 +416,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
} }
// perform the move // perform the move
try { try {
Data::$db->subscriptionPropertiesSet(Data::$user->id, (int) $url[1], $in); Arsse::$db->subscriptionPropertiesSet(Arsse::$user->id, (int) $url[1], $in);
} catch(ExceptionInput $e) { } catch(ExceptionInput $e) {
switch($e->getCode()) { switch($e->getCode()) {
// subscription does not exist // subscription does not exist
@ -443,7 +443,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
$c->subscription((int) $url[1]); $c->subscription((int) $url[1]);
// perform the operation // perform the operation
try { try {
Data::$db->articleMark(Data::$user->id, ['read' => true], $c); Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c);
} catch(ExceptionInput $e) { } catch(ExceptionInput $e) {
// subscription does not exist // subscription does not exist
return new Response(404); return new Response(404);
@ -492,7 +492,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
if(isset($data['lastModified'])) $c->modifiedSince($data['lastModified']); if(isset($data['lastModified'])) $c->modifiedSince($data['lastModified']);
// perform the fetch // perform the fetch
try { try {
$items = Data::$db->articleList(Data::$user->id, $c); $items = Arsse::$db->articleList(Arsse::$user->id, $c);
} catch(ExceptionInput $e) { } catch(ExceptionInput $e) {
// ID of subscription or folder is not valid // ID of subscription or folder is not valid
return new Response(422); return new Response(422);
@ -516,7 +516,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
return new Response(422); return new Response(422);
} }
// perform the operation // perform the operation
Data::$db->articleMark(Data::$user->id, ['read' => true], $c); Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c);
return new Response(204); return new Response(204);
} }
@ -528,7 +528,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
// determine whether to mark read or unread // determine whether to mark read or unread
$set = ($url[2]=="read"); $set = ($url[2]=="read");
try { try {
Data::$db->articleMark(Data::$user->id, ['read' => $set], $c); Arsse::$db->articleMark(Arsse::$user->id, ['read' => $set], $c);
} catch(ExceptionInput $e) { } catch(ExceptionInput $e) {
// ID is not valid // ID is not valid
return new Response(404); return new Response(404);
@ -544,7 +544,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
// determine whether to mark read or unread // determine whether to mark read or unread
$set = ($url[3]=="star"); $set = ($url[3]=="star");
try { try {
Data::$db->articleMark(Data::$user->id, ['starred' => $set], $c); Arsse::$db->articleMark(Arsse::$user->id, ['starred' => $set], $c);
} catch(ExceptionInput $e) { } catch(ExceptionInput $e) {
// ID is not valid // ID is not valid
return new Response(404); return new Response(404);
@ -559,14 +559,14 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
// if the input data is not at all valid, return an error // if the input data is not at all valid, return an error
if(!isset($data['items']) || !is_array($data['items'])) return new Response(422); if(!isset($data['items']) || !is_array($data['items'])) return new Response(422);
// start a transaction and loop through the items // start a transaction and loop through the items
$t = Data::$db->begin(); $t = Arsse::$db->begin();
$in = array_chunk($data['items'], 50); $in = array_chunk($data['items'], 50);
for($a = 0; $a < sizeof($in); $a++) { for($a = 0; $a < sizeof($in); $a++) {
// initialize the matching context // initialize the matching context
$c = new Context; $c = new Context;
$c->editions($in[$a]); $c->editions($in[$a]);
try { try {
Data::$db->articleMark(Data::$user->id, ['read' => $set], $c); Arsse::$db->articleMark(Arsse::$user->id, ['read' => $set], $c);
} catch(ExceptionInput $e) {} } catch(ExceptionInput $e) {}
} }
$t->commit(); $t->commit();
@ -580,14 +580,14 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
// if the input data is not at all valid, return an error // if the input data is not at all valid, return an error
if(!isset($data['items']) || !is_array($data['items'])) return new Response(422); if(!isset($data['items']) || !is_array($data['items'])) return new Response(422);
// start a transaction and loop through the items // start a transaction and loop through the items
$t = Data::$db->begin(); $t = Arsse::$db->begin();
$in = array_chunk(array_column($data['items'], "guidHash"), 50); $in = array_chunk(array_column($data['items'], "guidHash"), 50);
for($a = 0; $a < sizeof($in); $a++) { for($a = 0; $a < sizeof($in); $a++) {
// initialize the matching context // initialize the matching context
$c = new Context; $c = new Context;
$c->articles($in[$a]); $c->articles($in[$a]);
try { try {
Data::$db->articleMark(Data::$user->id, ['starred' => $set], $c); Arsse::$db->articleMark(Arsse::$user->id, ['starred' => $set], $c);
} catch(ExceptionInput $e) {} } catch(ExceptionInput $e) {}
} }
$t->commit(); $t->commit();
@ -596,10 +596,10 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
protected function userStatus(array $url, array $data): Response { protected function userStatus(array $url, array $data): Response {
// FIXME: stub // FIXME: stub
$data = Data::$db->userPropertiesGet(Data::$user->id); $data = Arsse::$db->userPropertiesGet(Arsse::$user->id);
$out = [ $out = [
'userId' => Data::$user->id, 'userId' => Arsse::$user->id,
'displayName' => $data['name'] ?? Data::$user->id, 'displayName' => $data['name'] ?? Arsse::$user->id,
'lastLoginTimestamp' => time(), 'lastLoginTimestamp' => time(),
'avatar' => null, 'avatar' => null,
]; ];
@ -608,14 +608,14 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
protected function cleanupBefore(array $url, array $data): Response { protected function cleanupBefore(array $url, array $data): Response {
// function requires admin rights per spec // function requires admin rights per spec
if(Data::$user->rightsGet(Data::$user->id)==User::RIGHTS_NONE) return new Response(403); if(Arsse::$user->rightsGet(Arsse::$user->id)==User::RIGHTS_NONE) return new Response(403);
// FIXME: stub // FIXME: stub
return new Response(204); return new Response(204);
} }
protected function cleanupAfter(array $url, array $data): Response { protected function cleanupAfter(array $url, array $data): Response {
// function requires admin rights per spec // function requires admin rights per spec
if(Data::$user->rightsGet(Data::$user->id)==User::RIGHTS_NONE) return new Response(403); if(Arsse::$user->rightsGet(Arsse::$user->id)==User::RIGHTS_NONE) return new Response(403);
// FIXME: stub // FIXME: stub
return new Response(204); return new Response(204);
} }

View file

@ -1,25 +1,21 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse; namespace JKingWeb\Arsse;
use JKingWeb\Arsse\Misc\Date;
class Service { class Service {
use Misc\DateFormatter;
/** /** @var Service\Driver */
* @var Service\Driver
*/
protected $drv; protected $drv;
/** /** @var \DateInterval */
* @var \DateInterval
*/
protected $interval; protected $interval;
protected static function interval(): \DateInterval { protected static function interval(): \DateInterval {
return new \DateInterval(Data::$conf->serviceFrequency); // FIXME: this needs to fall back in case of incorrect input return new \DateInterval(Arsse::$conf->serviceFrequency); // FIXME: this needs to fall back in case of incorrect input
} }
function __construct() { function __construct() {
$driver = Data::$conf->serviceDriver; $driver = Arsse::$conf->serviceDriver;
$this->drv = new $driver(); $this->drv = new $driver();
$this->interval = static::interval(); $this->interval = static::interval();
} }
@ -29,7 +25,7 @@ class Service {
do { do {
$this->checkIn(); $this->checkIn();
static::cleanupPre(); static::cleanupPre();
$list = Data::$db->feedListStale(); $list = Arsse::$db->feedListStale();
if($list) { if($list) {
echo date("H:i:s")." Updating feeds ".json_encode($list)."\n"; echo date("H:i:s")." Updating feeds ".json_encode($list)."\n";
$this->drv->queue(...$list); $this->drv->queue(...$list);
@ -45,15 +41,15 @@ class Service {
} }
function checkIn(): bool { function checkIn(): bool {
return Data::$db->metaSet("service_last_checkin", time(), "datetime"); return Arsse::$db->metaSet("service_last_checkin", time(), "datetime");
} }
static function hasCheckedIn(): bool { static function hasCheckedIn(): bool {
$checkin = Data::$db->metaGet("service_last_checkin"); $checkin = Arsse::$db->metaGet("service_last_checkin");
// if the service has never checked in, return false // if the service has never checked in, return false
if(!$checkin) return false; if(!$checkin) return false;
// convert the check-in timestamp to a DateTime instance // convert the check-in timestamp to a DateTime instance
$checkin = static::dateNormalize($checkin, "sql"); $checkin = Date::normalize($checkin, "sql");
// get the checking interval // get the checking interval
$int = static::interval(); $int = static::interval();
// subtract twice the checking interval from the current time to the earliest acceptable check-in time // subtract twice the checking interval from the current time to the earliest acceptable check-in time

View file

@ -1,7 +1,7 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Service\Curl; namespace JKingWeb\Arsse\Service\Curl;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
class Driver implements \JKingWeb\Arsse\Service\Driver { class Driver implements \JKingWeb\Arsse\Service\Driver {
protected $options = []; protected $options = [];
@ -9,7 +9,7 @@ class Driver implements \JKingWeb\Arsse\Service\Driver {
protected $handles = []; protected $handles = [];
static function driverName(): string { static function driverName(): string {
return Data::$lang->msg("Driver.Service.Curl.Name"); return Arsse::$lang->msg("Driver.Service.Curl.Name");
} }
static function requirementsMet(): bool { static function requirementsMet(): bool {
@ -19,7 +19,7 @@ class Driver implements \JKingWeb\Arsse\Service\Driver {
function __construct() { function __construct() {
//default curl options for individual requests //default curl options for individual requests
$this->options = [ $this->options = [
\CURLOPT_URL => Data::$serviceCurlBase."index.php/apps/news/api/v1-2/feeds/update", \CURLOPT_URL => Arsse::$serviceCurlBase."index.php/apps/news/api/v1-2/feeds/update",
\CURLOPT_CUSTOMREQUEST => "GET", \CURLOPT_CUSTOMREQUEST => "GET",
\CURLOPT_FAILONERROR => false, \CURLOPT_FAILONERROR => false,
\CURLOPT_FOLLOWLOCATION => false, \CURLOPT_FOLLOWLOCATION => false,
@ -28,8 +28,8 @@ class Driver implements \JKingWeb\Arsse\Service\Driver {
\CURLOPT_DNS_CACHE_TIMEOUT => 360, // FIXME: this should probably be twice the update-check interval so that the DNS cache is always in memory \CURLOPT_DNS_CACHE_TIMEOUT => 360, // FIXME: this should probably be twice the update-check interval so that the DNS cache is always in memory
\CURLOPT_PROTOCOLS => \CURLPROTO_HTTP | \CURLPROTO_HTTPS, \CURLOPT_PROTOCOLS => \CURLPROTO_HTTP | \CURLPROTO_HTTPS,
\CURLOPT_DEFAULT_PROTOCOL => "https", \CURLOPT_DEFAULT_PROTOCOL => "https",
\CURLOPT_USERAGENT => Data::$conf->fetchUserAgentString, \CURLOPT_USERAGENT => Arsse::$conf->fetchUserAgentString,
\CURLMOPT_MAX_HOST_CONNECTIONS => Data::$conf->serviceQueueWidth, \CURLMOPT_MAX_HOST_CONNECTIONS => Arsse::$conf->serviceQueueWidth,
\CURLOPT_HTTPHEADER => [ \CURLOPT_HTTPHEADER => [
'Accept: application/json', 'Accept: application/json',
'Content-Type: application/json', 'Content-Type: application/json',
@ -58,7 +58,7 @@ class Driver implements \JKingWeb\Arsse\Service\Driver {
curl_multi_exec($this->queue, $active); curl_multi_exec($this->queue, $active);
curl_multi_select($this->queue); curl_multi_select($this->queue);
} while ($active > 0); } while ($active > 0);
return Data::$conf->serviceQueueWidth - $active; return Arsse::$conf->serviceQueueWidth - $active;
} }
function clean(): bool { function clean(): bool {

View file

@ -1,13 +1,13 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Service\Internal; namespace JKingWeb\Arsse\Service\Internal;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
class Driver implements \JKingWeb\Arsse\Service\Driver { class Driver implements \JKingWeb\Arsse\Service\Driver {
protected $queue = []; protected $queue = [];
static function driverName(): string { static function driverName(): string {
return Data::$lang->msg("Driver.Service.Internal.Name"); return Arsse::$lang->msg("Driver.Service.Internal.Name");
} }
static function requirementsMet(): bool { static function requirementsMet(): bool {
@ -26,9 +26,9 @@ class Driver implements \JKingWeb\Arsse\Service\Driver {
function exec(): int { function exec(): int {
while(sizeof($this->queue)) { while(sizeof($this->queue)) {
$id = array_shift($this->queue); $id = array_shift($this->queue);
Data::$db->feedUpdate($id); Arsse::$db->feedUpdate($id);
} }
return Data::$conf->serviceQueueWidth - sizeof($this->queue); return Arsse::$conf->serviceQueueWidth - sizeof($this->queue);
} }
function clean(): bool { function clean(): bool {

View file

@ -32,7 +32,7 @@ class User {
} }
public function __construct() { public function __construct() {
$driver = Data::$conf->userDriver; $driver = Arsse::$conf->userDriver;
$this->u = new $driver(); $this->u = new $driver();
} }
@ -48,13 +48,13 @@ class User {
// if we don't have a logged-in user, fetch credentials // if we don't have a logged-in user, fetch credentials
if($this->id===null) $this->credentials(); if($this->id===null) $this->credentials();
// if the affected user is the actor and the actor is not trying to grant themselves rights, accept the request // if the affected user is the actor and the actor is not trying to grant themselves rights, accept the request
if($affectedUser==Data::$user->id && $action != "userRightsSet") return true; if($affectedUser==Arsse::$user->id && $action != "userRightsSet") return true;
// if we're authorizing something other than a user function and the affected user is not the actor, make sure the affected user exists // if we're authorizing something other than a user function and the affected user is not the actor, make sure the affected user exists
$this->authorizationEnabled(false); $this->authorizationEnabled(false);
if(Data::$user->id != $affectedUser && strpos($action, "user")!==0 && !$this->exists($affectedUser)) throw new User\Exception("doesNotExist", ["action" => $action, "user" => $affectedUser]); if(Arsse::$user->id != $affectedUser && strpos($action, "user")!==0 && !$this->exists($affectedUser)) throw new User\Exception("doesNotExist", ["action" => $action, "user" => $affectedUser]);
$this->authorizationEnabled(true); $this->authorizationEnabled(true);
// get properties of actor if not already available // get properties of actor if not already available
if(!sizeof($this->actor)) $this->actor = $this->propertiesGet(Data::$user->id); if(!sizeof($this->actor)) $this->actor = $this->propertiesGet(Arsse::$user->id);
$rights = $this->actor["rights"]; $rights = $this->actor["rights"];
// if actor is a global admin, accept the request // if actor is a global admin, accept the request
if($rights==User\Driver::RIGHTS_GLOBAL_ADMIN) return true; if($rights==User\Driver::RIGHTS_GLOBAL_ADMIN) return true;
@ -63,7 +63,7 @@ class User {
// if actor is not some other sort of admin, deny the request // if actor is not some other sort of admin, deny the request
if(!in_array($rights,[User\Driver::RIGHTS_GLOBAL_MANAGER,User\Driver::RIGHTS_DOMAIN_MANAGER,User\Driver::RIGHTS_DOMAIN_ADMIN],true)) return false; if(!in_array($rights,[User\Driver::RIGHTS_GLOBAL_MANAGER,User\Driver::RIGHTS_DOMAIN_MANAGER,User\Driver::RIGHTS_DOMAIN_ADMIN],true)) return false;
// if actor is a domain admin/manager and domains don't match, deny the request // if actor is a domain admin/manager and domains don't match, deny the request
if(Data::$conf->userComposeNames && $this->actor["domain"] && $rights != User\Driver::RIGHTS_GLOBAL_MANAGER) { if(Arsse::$conf->userComposeNames && $this->actor["domain"] && $rights != User\Driver::RIGHTS_GLOBAL_MANAGER) {
$test = "@".$this->actor["domain"]; $test = "@".$this->actor["domain"];
if(substr($affectedUser,-1*strlen($test)) != $test) return false; if(substr($affectedUser,-1*strlen($test)) != $test) return false;
} }
@ -96,7 +96,7 @@ class User {
} else { } else {
$out = ["user" => "", "password" => ""]; $out = ["user" => "", "password" => ""];
} }
if(Data::$conf->userComposeNames && $out["user"] != "") { if(Arsse::$conf->userComposeNames && $out["user"] != "") {
$out["user"] = $this->composeName($out["user"]); $out["user"] = $this->composeName($out["user"]);
} }
$this->id = $out["user"]; $this->id = $out["user"];
@ -111,16 +111,16 @@ class User {
$this->actor = []; $this->actor = [];
switch($this->u->driverFunctions("auth")) { switch($this->u->driverFunctions("auth")) {
case User\Driver::FUNC_EXTERNAL: case User\Driver::FUNC_EXTERNAL:
if(Data::$conf->userPreAuth) { if(Arsse::$conf->userPreAuth) {
$out = true; $out = true;
} else { } else {
$out = $this->u->auth($user, $password); $out = $this->u->auth($user, $password);
} }
if($out && !Data::$db->userExists($user)) $this->autoProvision($user, $password); if($out && !Arsse::$db->userExists($user)) $this->autoProvision($user, $password);
return $out; return $out;
case User\Driver::FUNC_INTERNAL: case User\Driver::FUNC_INTERNAL:
if(Data::$conf->userPreAuth) { if(Arsse::$conf->userPreAuth) {
if(!Data::$db->userExists($user)) $this->autoProvision($user, $password); if(!Arsse::$db->userExists($user)) $this->autoProvision($user, $password);
return true; return true;
} else { } else {
return $this->u->auth($user, $password); return $this->u->auth($user, $password);
@ -173,7 +173,7 @@ class User {
// we handle authorization checks for external drivers // we handle authorization checks for external drivers
if(!$this->authorize($user, $func)) throw new User\ExceptionAuthz("notAuthorized", ["action" => $func, "user" => $user]); if(!$this->authorize($user, $func)) throw new User\ExceptionAuthz("notAuthorized", ["action" => $func, "user" => $user]);
$out = $this->u->userExists($user); $out = $this->u->userExists($user);
if($out && !Data::$db->userExists($user)) $this->autoProvision($user, ""); if($out && !Arsse::$db->userExists($user)) $this->autoProvision($user, "");
return $out; return $out;
case User\Driver::FUNC_INTERNAL: case User\Driver::FUNC_INTERNAL:
// internal functions handle their own authorization // internal functions handle their own authorization
@ -192,7 +192,7 @@ class User {
if(!$this->authorize($user, $func)) throw new User\ExceptionAuthz("notAuthorized", ["action" => $func, "user" => $user]); if(!$this->authorize($user, $func)) throw new User\ExceptionAuthz("notAuthorized", ["action" => $func, "user" => $user]);
$newPassword = $this->u->userAdd($user, $password); $newPassword = $this->u->userAdd($user, $password);
// if there was no exception and we don't have the user in the internal database, add it // if there was no exception and we don't have the user in the internal database, add it
if(!Data::$db->userExists($user)) $this->autoProvision($user, $newPassword); if(!Arsse::$db->userExists($user)) $this->autoProvision($user, $newPassword);
return $newPassword; return $newPassword;
case User\Driver::FUNC_INTERNAL: case User\Driver::FUNC_INTERNAL:
// internal functions handle their own authorization // internal functions handle their own authorization
@ -209,9 +209,9 @@ class User {
// we handle authorization checks for external drivers // we handle authorization checks for external drivers
if(!$this->authorize($user, $func)) throw new User\ExceptionAuthz("notAuthorized", ["action" => $func, "user" => $user]); if(!$this->authorize($user, $func)) throw new User\ExceptionAuthz("notAuthorized", ["action" => $func, "user" => $user]);
$out = $this->u->userRemove($user); $out = $this->u->userRemove($user);
if($out && Data::$db->userExists($user)) { if($out && Arsse::$db->userExists($user)) {
// if the user was removed and we have it in our data, remove it there // if the user was removed and we have it in our data, remove it there
if(!Data::$db->userExists($user)) Data::$db->userRemove($user); if(!Arsse::$db->userExists($user)) Arsse::$db->userRemove($user);
} }
return $out; return $out;
case User\Driver::FUNC_INTERNAL: case User\Driver::FUNC_INTERNAL:
@ -229,9 +229,9 @@ class User {
// we handle authorization checks for external drivers // we handle authorization checks for external drivers
if(!$this->authorize($user, $func)) throw new User\ExceptionAuthz("notAuthorized", ["action" => $func, "user" => $user]); if(!$this->authorize($user, $func)) throw new User\ExceptionAuthz("notAuthorized", ["action" => $func, "user" => $user]);
$out = $this->u->userPasswordSet($user, $newPassword, $oldPassword); $out = $this->u->userPasswordSet($user, $newPassword, $oldPassword);
if(Data::$db->userExists($user)) { if(Arsse::$db->userExists($user)) {
// if the password change was successful and the user exists, set the internal password to the same value // if the password change was successful and the user exists, set the internal password to the same value
Data::$db->userPasswordSet($user, $out); Arsse::$db->userPasswordSet($user, $out);
} else { } else {
// if the user does not exists in the internal database, create it // if the user does not exists in the internal database, create it
$this->autoProvision($user, $out); $this->autoProvision($user, $out);
@ -248,7 +248,7 @@ class User {
public function propertiesGet(string $user): array { public function propertiesGet(string $user): array {
// prepare default values // prepare default values
$domain = null; $domain = null;
if(Data::$conf->userComposeNames) $domain = substr($user,strrpos($user,"@")+1); if(Arsse::$conf->userComposeNames) $domain = substr($user,strrpos($user,"@")+1);
$init = [ $init = [
"id" => $user, "id" => $user,
"name" => $user, "name" => $user,
@ -264,7 +264,7 @@ class User {
// remove password if it is return (not exhaustive, but...) // remove password if it is return (not exhaustive, but...)
if(array_key_exists('password', $out)) unset($out['password']); if(array_key_exists('password', $out)) unset($out['password']);
// if the user does not exist in the internal database, add it // if the user does not exist in the internal database, add it
if(!Data::$db->userExists($user)) $this->autoProvision($user, "", $out); if(!Arsse::$db->userExists($user)) $this->autoProvision($user, "", $out);
return $out; return $out;
case User\Driver::FUNC_INTERNAL: case User\Driver::FUNC_INTERNAL:
// internal functions handle their own authorization // internal functions handle their own authorization
@ -286,9 +286,9 @@ class User {
// we handle authorization checks for external drivers // we handle authorization checks for external drivers
if(!$this->authorize($user, $func)) throw new User\ExceptionAuthz("notAuthorized", ["action" => $func, "user" => $user]); if(!$this->authorize($user, $func)) throw new User\ExceptionAuthz("notAuthorized", ["action" => $func, "user" => $user]);
$out = $this->u->userPropertiesSet($user, $properties); $out = $this->u->userPropertiesSet($user, $properties);
if(Data::$db->userExists($user)) { if(Arsse::$db->userExists($user)) {
// if the property change was successful and the user exists, set the internal properties to the same values // if the property change was successful and the user exists, set the internal properties to the same values
Data::$db->userPropertiesSet($user, $out); Arsse::$db->userPropertiesSet($user, $out);
} else { } else {
// if the user does not exists in the internal database, create it // if the user does not exists in the internal database, create it
$this->autoProvision($user, "", $out); $this->autoProvision($user, "", $out);
@ -310,7 +310,7 @@ class User {
if(!$this->authorize($user, $func)) throw new User\ExceptionAuthz("notAuthorized", ["action" => $func, "user" => $user]); if(!$this->authorize($user, $func)) throw new User\ExceptionAuthz("notAuthorized", ["action" => $func, "user" => $user]);
$out = $this->u->userRightsGet($user); $out = $this->u->userRightsGet($user);
// if the user does not exist in the internal database, add it // if the user does not exist in the internal database, add it
if(!Data::$db->userExists($user)) $this->autoProvision($user, "", null, $out); if(!Arsse::$db->userExists($user)) $this->autoProvision($user, "", null, $out);
return $out; return $out;
case User\Driver::FUNC_INTERNAL: case User\Driver::FUNC_INTERNAL:
// internal functions handle their own authorization // internal functions handle their own authorization
@ -329,10 +329,10 @@ class User {
if(!$this->authorize($user, $func)) throw new User\ExceptionAuthz("notAuthorized", ["action" => $func, "user" => $user]); if(!$this->authorize($user, $func)) throw new User\ExceptionAuthz("notAuthorized", ["action" => $func, "user" => $user]);
$out = $this->u->userRightsSet($user, $level); $out = $this->u->userRightsSet($user, $level);
// if the user does not exist in the internal database, add it // if the user does not exist in the internal database, add it
if($out && Data::$db->userExists($user)) { if($out && Arsse::$db->userExists($user)) {
$authz = $this->authorizationEnabled(); $authz = $this->authorizationEnabled();
$this->authorizationEnabled(false); $this->authorizationEnabled(false);
Data::$db->userRightsSet($user, $level); Arsse::$db->userRightsSet($user, $level);
$this->authorizationEnabled($authz); $this->authorizationEnabled($authz);
} else if($out) { } else if($out) {
$this->autoProvision($user, "", null, $level); $this->autoProvision($user, "", null, $level);
@ -358,18 +358,18 @@ class User {
// temporarily disable authorization checks, to avoid potential problems // temporarily disable authorization checks, to avoid potential problems
$this->authorizationEnabled(false); $this->authorizationEnabled(false);
// create the user // create the user
$out = Data::$db->userAdd($user, $password); $out = Arsse::$db->userAdd($user, $password);
// set the user rights // set the user rights
Data::$db->userRightsSet($user, $rights); Arsse::$db->userRightsSet($user, $rights);
// set the user properties... // set the user properties...
if($properties===null) { if($properties===null) {
// if nothing is provided but the driver uses an external function, try to get the current values from the external source // if nothing is provided but the driver uses an external function, try to get the current values from the external source
try { try {
if($this->u->driverFunctions("userPropertiesGet")==User\Driver::FUNC_EXTERNAL) Data::$db->userPropertiesSet($user, $this->u->userPropertiesGet($user)); if($this->u->driverFunctions("userPropertiesGet")==User\Driver::FUNC_EXTERNAL) Arsse::$db->userPropertiesSet($user, $this->u->userPropertiesGet($user));
} catch(\Throwable $e) {} } catch(\Throwable $e) {}
} else { } else {
// otherwise if values are provided, use those // otherwise if values are provided, use those
Data::$db->userPropertiesSet($user, $properties); Arsse::$db->userPropertiesSet($user, $properties);
} }
// re-enable authorization and return // re-enable authorization and return
$this->authorizationEnabled(true); $this->authorizationEnabled(true);

View file

@ -20,7 +20,7 @@ final class Driver implements \JKingWeb\Arsse\User\Driver {
]; ];
static public function driverName(): string { static public function driverName(): string {
return Data::$lang->msg("Driver.User.Internal.Name"); return Arsse::$lang->msg("Driver.User.Internal.Name");
} }
public function driverFunctions(string $function = null) { public function driverFunctions(string $function = null) {

View file

@ -1,17 +1,17 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\User\Internal; namespace JKingWeb\Arsse\User\Internal;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
trait InternalFunctions { trait InternalFunctions {
protected $actor = []; protected $actor = [];
public function __construct() { public function __construct() {
$this->db = Data::$db; $this->db = Arsse::$db;
} }
function auth(string $user, string $password): bool { function auth(string $user, string $password): bool {
if(!Data::$user->exists($user)) return false; if(!Arsse::$user->exists($user)) return false;
$hash = $this->db->userPasswordGet($user); $hash = $this->db->userPasswordGet($user);
if($password==="" && $hash==="") return true; if($password==="" && $hash==="") return true;
return password_verify($password, $hash); return password_verify($password, $hash);

View file

@ -16,21 +16,21 @@ class TestDbDriverSQLite3 extends Test\AbstractTest {
$conf = new Conf(); $conf = new Conf();
$conf->dbDriver = Db\SQLite3\Driver::class; $conf->dbDriver = Db\SQLite3\Driver::class;
$conf->dbSQLite3File = tempnam(sys_get_temp_dir(), 'ook'); $conf->dbSQLite3File = tempnam(sys_get_temp_dir(), 'ook');
Data::$conf = $conf; Arsse::$conf = $conf;
$this->drv = new Db\SQLite3\Driver(true); $this->drv = new Db\SQLite3\Driver(true);
$this->ch = new \SQLite3(Data::$conf->dbSQLite3File); $this->ch = new \SQLite3(Arsse::$conf->dbSQLite3File);
$this->ch->enableExceptions(true); $this->ch->enableExceptions(true);
} }
function tearDown() { function tearDown() {
unset($this->drv); unset($this->drv);
unset($this->ch); unset($this->ch);
unlink(Data::$conf->dbSQLite3File); unlink(Arsse::$conf->dbSQLite3File);
$this->clearData(); $this->clearData();
} }
function testFetchDriverName() { function testFetchDriverName() {
$class = Data::$conf->dbDriver; $class = Arsse::$conf->dbDriver;
$this->assertTrue(strlen($class::driverName()) > 0); $this->assertTrue(strlen($class::driverName()) > 0);
} }

View file

@ -24,7 +24,7 @@ class TestDbUpdateSQLite3 extends Test\AbstractTest {
$conf->dbSchemaBase = $this->vfs->url(); $conf->dbSchemaBase = $this->vfs->url();
$this->base = $this->vfs->url()."/SQLite3/"; $this->base = $this->vfs->url()."/SQLite3/";
$conf->dbSQLite3File = ":memory:"; $conf->dbSQLite3File = ":memory:";
Data::$conf = $conf; Arsse::$conf = $conf;
$this->drv = new Db\SQLite3\Driver(true); $this->drv = new Db\SQLite3\Driver(true);
} }
@ -85,7 +85,7 @@ class TestDbUpdateSQLite3 extends Test\AbstractTest {
} }
function testPerformActualUpdate() { function testPerformActualUpdate() {
Data::$conf->dbSchemaBase = (new Conf())->dbSchemaBase; Arsse::$conf->dbSchemaBase = (new Conf())->dbSchemaBase;
$this->drv->schemaUpdate(Database::SCHEMA_VERSION); $this->drv->schemaUpdate(Database::SCHEMA_VERSION);
$this->assertEquals(Database::SCHEMA_VERSION, $this->drv->schemaVersion()); $this->assertEquals(Database::SCHEMA_VERSION, $this->drv->schemaVersion());
} }

View file

@ -8,14 +8,14 @@ class TestException extends Test\AbstractTest {
function setUp() { function setUp() {
$this->clearData(false); $this->clearData(false);
// create a mock Lang object so as not to create a dependency loop // create a mock Lang object so as not to create a dependency loop
Data::$lang = Phake::mock(Lang::class); Arsse::$lang = Phake::mock(Lang::class);
Phake::when(Data::$lang)->msg->thenReturn(""); Phake::when(Arsse::$lang)->msg->thenReturn("");
} }
function tearDown() { function tearDown() {
// verify calls to the mock Lang object // verify calls to the mock Lang object
Phake::verify(Data::$lang, Phake::atLeast(0))->msg($this->isType("string"), $this->anything()); Phake::verify(Arsse::$lang, Phake::atLeast(0))->msg($this->isType("string"), $this->anything());
Phake::verifyNoOtherInteractions(Data::$lang); Phake::verifyNoOtherInteractions(Arsse::$lang);
// clean up // clean up
$this->clearData(true); $this->clearData(true);
} }

View file

@ -1,7 +1,8 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse; namespace JKingWeb\Arsse;
Use Phake; use JKingWeb\Arsse\Misc\Date;
use Phake;
class TestFeed extends Test\AbstractTest { class TestFeed extends Test\AbstractTest {
@ -82,8 +83,8 @@ class TestFeed extends Test\AbstractTest {
} }
$this->base = self::$host."Feed/"; $this->base = self::$host."Feed/";
$this->clearData(); $this->clearData();
Data::$conf = new Conf(); Arsse::$conf = new Conf();
Data::$db = Phake::mock(Database::class); Arsse::$db = Phake::mock(Database::class);
} }
function testParseAFeed() { function testParseAFeed() {
@ -180,16 +181,16 @@ class TestFeed extends Test\AbstractTest {
// upon 304, the client should re-use the caching header values it supplied the server // upon 304, the client should re-use the caching header values it supplied the server
$t = time(); $t = time();
$e = "78567a"; $e = "78567a";
$f = new Feed(null, $this->base."Caching/304Random", $this->dateTransform($t, "http"), $e); $f = new Feed(null, $this->base."Caching/304Random", Date::transform($t, "http"), $e);
$this->assertTime($t, $f->lastModified); $this->assertTime($t, $f->lastModified);
$this->assertSame($e, $f->resource->getETag()); $this->assertSame($e, $f->resource->getETag());
$f = new Feed(null, $this->base."Caching/304ETagOnly", $this->dateTransform($t, "http"), $e); $f = new Feed(null, $this->base."Caching/304ETagOnly", Date::transform($t, "http"), $e);
$this->assertTime($t, $f->lastModified); $this->assertTime($t, $f->lastModified);
$this->assertSame($e, $f->resource->getETag()); $this->assertSame($e, $f->resource->getETag());
$f = new Feed(null, $this->base."Caching/304LastModOnly", $this->dateTransform($t, "http"), $e); $f = new Feed(null, $this->base."Caching/304LastModOnly", Date::transform($t, "http"), $e);
$this->assertTime($t, $f->lastModified); $this->assertTime($t, $f->lastModified);
$this->assertSame($e, $f->resource->getETag()); $this->assertSame($e, $f->resource->getETag());
$f = new Feed(null, $this->base."Caching/304None", $this->dateTransform($t, "http"), $e); $f = new Feed(null, $this->base."Caching/304None", Date::transform($t, "http"), $e);
$this->assertTime($t, $f->lastModified); $this->assertTime($t, $f->lastModified);
$this->assertSame($e, $f->resource->getETag()); $this->assertSame($e, $f->resource->getETag());
} }
@ -201,7 +202,7 @@ class TestFeed extends Test\AbstractTest {
$this->assertTime($t, $f->lastModified); $this->assertTime($t, $f->lastModified);
$this->assertNotEmpty($f->resource->getETag()); $this->assertNotEmpty($f->resource->getETag());
$t = time() - 2000; $t = time() - 2000;
$f = new Feed(null, $this->base."Caching/200Past", $this->dateTransform(time(), "http")); $f = new Feed(null, $this->base."Caching/200Past", Date::transform(time(), "http"));
$this->assertTime($t, $f->lastModified); $this->assertTime($t, $f->lastModified);
$this->assertNotEmpty($f->resource->getETag()); $this->assertNotEmpty($f->resource->getETag());
$t = time() + 2000; $t = time() + 2000;
@ -237,47 +238,47 @@ class TestFeed extends Test\AbstractTest {
function testComputeNextFetchFrom304() { 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");
$f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", $this->dateTransform($t, "http")); $f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", Date::transform($t, "http"));
$exp = strtotime("now + 15 minutes"); $exp = strtotime("now + 15 minutes");
$this->assertTime($exp, $f->nextFetch); $this->assertTime($exp, $f->nextFetch);
$t = strtotime("now - 29 minutes"); $t = strtotime("now - 29 minutes");
$f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", $this->dateTransform($t, "http")); $f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", Date::transform($t, "http"));
$exp = strtotime("now + 15 minutes"); $exp = strtotime("now + 15 minutes");
$this->assertTime($exp, $f->nextFetch); $this->assertTime($exp, $f->nextFetch);
// if less than an hour, check in 30 minutes // if less than an hour, check in 30 minutes
$t = strtotime("now - 30 minutes"); $t = strtotime("now - 30 minutes");
$f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", $this->dateTransform($t, "http")); $f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", Date::transform($t, "http"));
$exp = strtotime("now + 30 minutes"); $exp = strtotime("now + 30 minutes");
$this->assertTime($exp, $f->nextFetch); $this->assertTime($exp, $f->nextFetch);
$t = strtotime("now - 59 minutes"); $t = strtotime("now - 59 minutes");
$f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", $this->dateTransform($t, "http")); $f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", Date::transform($t, "http"));
$exp = strtotime("now + 30 minutes"); $exp = strtotime("now + 30 minutes");
$this->assertTime($exp, $f->nextFetch); $this->assertTime($exp, $f->nextFetch);
// if less than three hours, check in an hour // if less than three hours, check in an hour
$t = strtotime("now - 1 hour"); $t = strtotime("now - 1 hour");
$f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", $this->dateTransform($t, "http")); $f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", Date::transform($t, "http"));
$exp = strtotime("now + 1 hour"); $exp = strtotime("now + 1 hour");
$this->assertTime($exp, $f->nextFetch); $this->assertTime($exp, $f->nextFetch);
$t = strtotime("now - 2 hours 59 minutes"); $t = strtotime("now - 2 hours 59 minutes");
$f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", $this->dateTransform($t, "http")); $f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", Date::transform($t, "http"));
$exp = strtotime("now + 1 hour"); $exp = strtotime("now + 1 hour");
$this->assertTime($exp, $f->nextFetch); $this->assertTime($exp, $f->nextFetch);
// if more than 36 hours, check in 24 hours // if more than 36 hours, check in 24 hours
$t = strtotime("now - 36 hours"); $t = strtotime("now - 36 hours");
$f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", $this->dateTransform($t, "http")); $f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", Date::transform($t, "http"));
$exp = strtotime("now + 1 day"); $exp = strtotime("now + 1 day");
$this->assertTime($exp, $f->nextFetch); $this->assertTime($exp, $f->nextFetch);
$t = strtotime("now - 2 years"); $t = strtotime("now - 2 years");
$f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", $this->dateTransform($t, "http")); $f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", Date::transform($t, "http"));
$exp = strtotime("now + 1 day"); $exp = strtotime("now + 1 day");
$this->assertTime($exp, $f->nextFetch); $this->assertTime($exp, $f->nextFetch);
// otherwise check in three hours // otherwise check in three hours
$t = strtotime("now - 3 hours"); $t = strtotime("now - 3 hours");
$f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", $this->dateTransform($t, "http")); $f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", Date::transform($t, "http"));
$exp = strtotime("now + 3 hours"); $exp = strtotime("now + 3 hours");
$this->assertTime($exp, $f->nextFetch); $this->assertTime($exp, $f->nextFetch);
$t = strtotime("now - 35 hours"); $t = strtotime("now - 35 hours");
$f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", $this->dateTransform($t, "http")); $f = new Feed(null, $this->base."NextFetch/NotModified?t=$t", Date::transform($t, "http"));
$exp = strtotime("now + 3 hours"); $exp = strtotime("now + 3 hours");
$this->assertTime($exp, $f->nextFetch); $this->assertTime($exp, $f->nextFetch);
} }
@ -310,7 +311,7 @@ class TestFeed extends Test\AbstractTest {
} }
function testMatchLatestArticles() { function testMatchLatestArticles() {
Phake::when(Data::$db)->feedMatchLatest(1, $this->anything())->thenReturn(new Test\Result($this->latest)); Phake::when(Arsse::$db)->feedMatchLatest(1, $this->anything())->thenReturn(new Test\Result($this->latest));
$f = new Feed(1, $this->base."Matching/1"); $f = new Feed(1, $this->base."Matching/1");
$this->assertCount(0, $f->newItems); $this->assertCount(0, $f->newItems);
$this->assertCount(0, $f->changedItems); $this->assertCount(0, $f->changedItems);
@ -326,8 +327,8 @@ class TestFeed extends Test\AbstractTest {
} }
function testMatchHistoricalArticles() { function testMatchHistoricalArticles() {
Phake::when(Data::$db)->feedMatchLatest(1, $this->anything())->thenReturn(new Test\Result($this->latest)); Phake::when(Arsse::$db)->feedMatchLatest(1, $this->anything())->thenReturn(new Test\Result($this->latest));
Phake::when(Data::$db)->feedMatchIds(1, $this->anything(), $this->anything(), $this->anything(), $this->anything())->thenReturn(new Test\Result($this->others)); Phake::when(Arsse::$db)->feedMatchIds(1, $this->anything(), $this->anything(), $this->anything(), $this->anything())->thenReturn(new Test\Result($this->others));
$f = new Feed(1, $this->base."Matching/5"); $f = new Feed(1, $this->base."Matching/5");
$this->assertCount(0, $f->newItems); $this->assertCount(0, $f->newItems);
$this->assertCount(0, $f->changedItems); $this->assertCount(0, $f->changedItems);

View file

@ -16,7 +16,7 @@ class TestFeedFetching extends Test\AbstractTest {
} }
$this->base = self::$host."Feed/"; $this->base = self::$host."Feed/";
$this->clearData(); $this->clearData();
Data::$conf = new Conf(); Arsse::$conf = new Conf();
} }
function testHandle400() { function testHandle400() {
@ -50,13 +50,13 @@ class TestFeedFetching extends Test\AbstractTest {
} }
function testHandleATimeout() { function testHandleATimeout() {
Data::$conf->fetchTimeout = 1; Arsse::$conf->fetchTimeout = 1;
$this->assertException("timeout", "Feed"); $this->assertException("timeout", "Feed");
new Feed(null, $this->base."Fetching/Timeout"); new Feed(null, $this->base."Fetching/Timeout");
} }
function testHandleAnOverlyLargeFeed() { function testHandleAnOverlyLargeFeed() {
Data::$conf->fetchSizeLimit = 512; Arsse::$conf->fetchSizeLimit = 512;
$this->assertException("maxSize", "Feed"); $this->assertException("maxSize", "Feed");
new Feed(null, $this->base."Fetching/TooLarge"); new Feed(null, $this->base."Fetching/TooLarge");
} }

View file

@ -261,13 +261,13 @@ class TestNCNV1_2 extends Test\AbstractTest {
function setUp() { function setUp() {
$this->clearData(); $this->clearData();
// create a mock user manager // create a mock user manager
Data::$user = Phake::mock(User::class); Arsse::$user = Phake::mock(User::class);
Phake::when(Data::$user)->authHTTP->thenReturn(true); Phake::when(Arsse::$user)->authHTTP->thenReturn(true);
Phake::when(Data::$user)->rightsGet->thenReturn(100); Phake::when(Arsse::$user)->rightsGet->thenReturn(100);
Data::$user->id = "john.doe@example.com"; Arsse::$user->id = "john.doe@example.com";
// create a mock database interface // create a mock database interface
Data::$db = Phake::mock(Database::Class); Arsse::$db = Phake::mock(Database::Class);
Phake::when(Data::$db)->begin->thenReturn(Phake::mock(Transaction::class)); Phake::when(Arsse::$db)->begin->thenReturn(Phake::mock(Transaction::class));
$this->h = new REST\NextCloudNews\V1_2(); $this->h = new REST\NextCloudNews\V1_2();
} }
@ -322,7 +322,7 @@ class TestNCNV1_2 extends Test\AbstractTest {
} }
function testReceiveAuthenticationChallenge() { function testReceiveAuthenticationChallenge() {
Phake::when(Data::$user)->authHTTP->thenReturn(false); Phake::when(Arsse::$user)->authHTTP->thenReturn(false);
$exp = new Response(401, "", "", ['WWW-Authenticate: Basic realm="'.REST\NextCloudNews\V1_2::REALM.'"']); $exp = new Response(401, "", "", ['WWW-Authenticate: Basic realm="'.REST\NextCloudNews\V1_2::REALM.'"']);
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/"))); $this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/")));
} }
@ -332,7 +332,7 @@ class TestNCNV1_2 extends Test\AbstractTest {
['id' => 1, 'name' => "Software", 'parent' => null], ['id' => 1, 'name' => "Software", 'parent' => null],
['id' => 12, 'name' => "Hardware", 'parent' => null], ['id' => 12, 'name' => "Hardware", 'parent' => null],
]; ];
Phake::when(Data::$db)->folderList(Data::$user->id, null, false)->thenReturn(new Result([]))->thenReturn(new Result($list)); Phake::when(Arsse::$db)->folderList(Arsse::$user->id, null, false)->thenReturn(new Result([]))->thenReturn(new Result($list));
$exp = new Response(200, ['folders' => []]); $exp = new Response(200, ['folders' => []]);
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/folders"))); $this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/folders")));
$exp = new Response(200, ['folders' => $list]); $exp = new Response(200, ['folders' => $list]);
@ -349,23 +349,23 @@ class TestNCNV1_2 extends Test\AbstractTest {
['id' => 2, 'name' => "Hardware", 'parent' => null], ['id' => 2, 'name' => "Hardware", 'parent' => null],
]; ];
// set of various mocks for testing // set of various mocks for testing
Phake::when(Data::$db)->folderAdd(Data::$user->id, $in[0])->thenReturn(1)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call Phake::when(Arsse::$db)->folderAdd(Arsse::$user->id, $in[0])->thenReturn(1)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call
Phake::when(Data::$db)->folderAdd(Data::$user->id, $in[1])->thenReturn(2)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call Phake::when(Arsse::$db)->folderAdd(Arsse::$user->id, $in[1])->thenReturn(2)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call
Phake::when(Data::$db)->folderPropertiesGet(Data::$user->id, 1)->thenReturn($out[0]); Phake::when(Arsse::$db)->folderPropertiesGet(Arsse::$user->id, 1)->thenReturn($out[0]);
Phake::when(Data::$db)->folderPropertiesGet(Data::$user->id, 2)->thenReturn($out[1]); Phake::when(Arsse::$db)->folderPropertiesGet(Arsse::$user->id, 2)->thenReturn($out[1]);
// set up mocks that produce errors // set up mocks that produce errors
Phake::when(Data::$db)->folderAdd(Data::$user->id, [])->thenThrow(new ExceptionInput("missing")); Phake::when(Arsse::$db)->folderAdd(Arsse::$user->id, [])->thenThrow(new ExceptionInput("missing"));
Phake::when(Data::$db)->folderAdd(Data::$user->id, ['name' => ""])->thenThrow(new ExceptionInput("missing")); Phake::when(Arsse::$db)->folderAdd(Arsse::$user->id, ['name' => ""])->thenThrow(new ExceptionInput("missing"));
Phake::when(Data::$db)->folderAdd(Data::$user->id, ['name' => " "])->thenThrow(new ExceptionInput("whitespace")); Phake::when(Arsse::$db)->folderAdd(Arsse::$user->id, ['name' => " "])->thenThrow(new ExceptionInput("whitespace"));
// correctly add two folders, using different means // correctly add two folders, using different means
$exp = new Response(200, ['folders' => [$out[0]]]); $exp = new Response(200, ['folders' => [$out[0]]]);
$this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders", json_encode($in[0]), 'application/json'))); $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders", json_encode($in[0]), 'application/json')));
$exp = new Response(200, ['folders' => [$out[1]]]); $exp = new Response(200, ['folders' => [$out[1]]]);
$this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders?name=Hardware"))); $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders?name=Hardware")));
Phake::verify(Data::$db)->folderAdd(Data::$user->id, $in[0]); Phake::verify(Arsse::$db)->folderAdd(Arsse::$user->id, $in[0]);
Phake::verify(Data::$db)->folderAdd(Data::$user->id, $in[1]); Phake::verify(Arsse::$db)->folderAdd(Arsse::$user->id, $in[1]);
Phake::verify(Data::$db)->folderPropertiesGet(Data::$user->id, 1); Phake::verify(Arsse::$db)->folderPropertiesGet(Arsse::$user->id, 1);
Phake::verify(Data::$db)->folderPropertiesGet(Data::$user->id, 2); Phake::verify(Arsse::$db)->folderPropertiesGet(Arsse::$user->id, 2);
// test bad folder names // test bad folder names
$exp = new Response(422); $exp = new Response(422);
$this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders"))); $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/folders")));
@ -379,13 +379,13 @@ class TestNCNV1_2 extends Test\AbstractTest {
} }
function testRemoveAFolder() { function testRemoveAFolder() {
Phake::when(Data::$db)->folderRemove(Data::$user->id, 1)->thenReturn(true)->thenThrow(new ExceptionInput("subjectMissing")); Phake::when(Arsse::$db)->folderRemove(Arsse::$user->id, 1)->thenReturn(true)->thenThrow(new ExceptionInput("subjectMissing"));
$exp = new Response(204); $exp = new Response(204);
$this->assertEquals($exp, $this->h->dispatch(new Request("DELETE", "/folders/1"))); $this->assertEquals($exp, $this->h->dispatch(new Request("DELETE", "/folders/1")));
// fail on the second invocation because it no longer exists // fail on the second invocation because it no longer exists
$exp = new Response(404); $exp = new Response(404);
$this->assertEquals($exp, $this->h->dispatch(new Request("DELETE", "/folders/1"))); $this->assertEquals($exp, $this->h->dispatch(new Request("DELETE", "/folders/1")));
Phake::verify(Data::$db, Phake::times(2))->folderRemove(Data::$user->id, 1); Phake::verify(Arsse::$db, Phake::times(2))->folderRemove(Arsse::$user->id, 1);
} }
function testRenameAFolder() { function testRenameAFolder() {
@ -396,12 +396,12 @@ class TestNCNV1_2 extends Test\AbstractTest {
["name" => " "], ["name" => " "],
[], [],
]; ];
Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 1, $in[0])->thenReturn(true); Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 1, $in[0])->thenReturn(true);
Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 2, $in[1])->thenThrow(new ExceptionInput("constraintViolation")); Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 2, $in[1])->thenThrow(new ExceptionInput("constraintViolation"));
Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 1, $in[2])->thenThrow(new ExceptionInput("missing")); Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 1, $in[2])->thenThrow(new ExceptionInput("missing"));
Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 1, $in[3])->thenThrow(new ExceptionInput("whitespace")); Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 1, $in[3])->thenThrow(new ExceptionInput("whitespace"));
Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 1, $in[4])->thenReturn(true); // this should be stopped by the handler before the request gets to the database Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 1, $in[4])->thenReturn(true); // this should be stopped by the handler before the request gets to the database
Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 3, $this->anything())->thenThrow(new ExceptionInput("subjectMissing")); // folder ID 3 does not exist Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 3, $this->anything())->thenThrow(new ExceptionInput("subjectMissing")); // folder ID 3 does not exist
$exp = new Response(204); $exp = new Response(204);
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[0]), 'application/json'))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[0]), 'application/json')));
$exp = new Response(409); $exp = new Response(409);
@ -434,9 +434,9 @@ class TestNCNV1_2 extends Test\AbstractTest {
'starredCount' => 5, 'starredCount' => 5,
'newestItemId' => 4758915, 'newestItemId' => 4758915,
]; ];
Phake::when(Data::$db)->subscriptionList(Data::$user->id)->thenReturn(new Result([]))->thenReturn(new Result($this->feeds['db'])); Phake::when(Arsse::$db)->subscriptionList(Arsse::$user->id)->thenReturn(new Result([]))->thenReturn(new Result($this->feeds['db']));
Phake::when(Data::$db)->articleStarredCount(Data::$user->id)->thenReturn(0)->thenReturn(5); Phake::when(Arsse::$db)->articleStarredCount(Arsse::$user->id)->thenReturn(0)->thenReturn(5);
Phake::when(Data::$db)->editionLatest(Data::$user->id)->thenReturn(0)->thenReturn(4758915); Phake::when(Arsse::$db)->editionLatest(Arsse::$user->id)->thenReturn(0)->thenReturn(4758915);
$exp = new Response(200, $exp1); $exp = new Response(200, $exp1);
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/feeds"))); $this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/feeds")));
$exp = new Response(200, $exp2); $exp = new Response(200, $exp2);
@ -455,16 +455,16 @@ class TestNCNV1_2 extends Test\AbstractTest {
[], [],
]; ];
// set up the necessary mocks // set up the necessary mocks
Phake::when(Data::$db)->subscriptionAdd(Data::$user->id, "http://example.com/news.atom")->thenReturn(2112)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call Phake::when(Arsse::$db)->subscriptionAdd(Arsse::$user->id, "http://example.com/news.atom")->thenReturn(2112)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call
Phake::when(Data::$db)->subscriptionAdd(Data::$user->id, "http://example.org/news.atom")->thenReturn( 42 )->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call Phake::when(Arsse::$db)->subscriptionAdd(Arsse::$user->id, "http://example.org/news.atom")->thenReturn( 42 )->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call
Phake::when(Data::$db)->subscriptionPropertiesGet(Data::$user->id, 2112)->thenReturn($this->feeds['db'][0]); Phake::when(Arsse::$db)->subscriptionPropertiesGet(Arsse::$user->id, 2112)->thenReturn($this->feeds['db'][0]);
Phake::when(Data::$db)->subscriptionPropertiesGet(Data::$user->id, 42)->thenReturn($this->feeds['db'][1]); Phake::when(Arsse::$db)->subscriptionPropertiesGet(Arsse::$user->id, 42)->thenReturn($this->feeds['db'][1]);
Phake::when(Data::$db)->editionLatest(Data::$user->id, (new Context)->subscription(2112))->thenReturn(0); Phake::when(Arsse::$db)->editionLatest(Arsse::$user->id, (new Context)->subscription(2112))->thenReturn(0);
Phake::when(Data::$db)->editionLatest(Data::$user->id, (new Context)->subscription( 42))->thenReturn(4758915); Phake::when(Arsse::$db)->editionLatest(Arsse::$user->id, (new Context)->subscription( 42))->thenReturn(4758915);
Phake::when(Data::$db)->subscriptionPropertiesSet(Data::$user->id, 2112, ['folder' => 3])->thenThrow(new ExceptionInput("idMissing")); // folder ID 3 does not exist Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 2112, ['folder' => 3])->thenThrow(new ExceptionInput("idMissing")); // folder ID 3 does not exist
Phake::when(Data::$db)->subscriptionPropertiesSet(Data::$user->id, 42, ['folder' => 8])->thenReturn(true); Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 42, ['folder' => 8])->thenReturn(true);
// set up a mock for a bad feed // set up a mock for a bad feed
Phake::when(Data::$db)->subscriptionAdd(Data::$user->id, "http://example.net/news.atom")->thenThrow(new \JKingWeb\Arsse\Feed\Exception("http://example.net/news.atom", new \PicoFeed\Client\InvalidUrlException())); Phake::when(Arsse::$db)->subscriptionAdd(Arsse::$user->id, "http://example.net/news.atom")->thenThrow(new \JKingWeb\Arsse\Feed\Exception("http://example.net/news.atom", new \PicoFeed\Client\InvalidUrlException()));
// add the subscriptions // add the subscriptions
$exp = new Response(200, $out[0]); $exp = new Response(200, $out[0]);
$this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[0]), 'application/json'))); $this->assertEquals($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[0]), 'application/json')));
@ -481,13 +481,13 @@ class TestNCNV1_2 extends Test\AbstractTest {
} }
function testRemoveASubscription() { function testRemoveASubscription() {
Phake::when(Data::$db)->subscriptionRemove(Data::$user->id, 1)->thenReturn(true)->thenThrow(new ExceptionInput("subjectMissing")); Phake::when(Arsse::$db)->subscriptionRemove(Arsse::$user->id, 1)->thenReturn(true)->thenThrow(new ExceptionInput("subjectMissing"));
$exp = new Response(204); $exp = new Response(204);
$this->assertEquals($exp, $this->h->dispatch(new Request("DELETE", "/feeds/1"))); $this->assertEquals($exp, $this->h->dispatch(new Request("DELETE", "/feeds/1")));
// fail on the second invocation because it no longer exists // fail on the second invocation because it no longer exists
$exp = new Response(404); $exp = new Response(404);
$this->assertEquals($exp, $this->h->dispatch(new Request("DELETE", "/feeds/1"))); $this->assertEquals($exp, $this->h->dispatch(new Request("DELETE", "/feeds/1")));
Phake::verify(Data::$db, Phake::times(2))->subscriptionRemove(Data::$user->id, 1); Phake::verify(Arsse::$db, Phake::times(2))->subscriptionRemove(Arsse::$user->id, 1);
} }
function testMoveASubscription() { function testMoveASubscription() {
@ -497,10 +497,10 @@ class TestNCNV1_2 extends Test\AbstractTest {
['folderId' => 2112], ['folderId' => 2112],
['folderId' => 42], ['folderId' => 42],
]; ];
Phake::when(Data::$db)->subscriptionPropertiesSet(Data::$user->id, 1, ['folder' => 42])->thenReturn(true); Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, ['folder' => 42])->thenReturn(true);
Phake::when(Data::$db)->subscriptionPropertiesSet(Data::$user->id, 1, ['folder' => null])->thenReturn(true); Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, ['folder' => null])->thenReturn(true);
Phake::when(Data::$db)->subscriptionPropertiesSet(Data::$user->id, 1, ['folder' => 2112])->thenThrow(new ExceptionInput("idMissing")); // folder does not exist Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, ['folder' => 2112])->thenThrow(new ExceptionInput("idMissing")); // folder does not exist
Phake::when(Data::$db)->subscriptionPropertiesSet(Data::$user->id, 42, $this->anything())->thenThrow(new ExceptionInput("subjectMissing")); // subscription does not exist Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 42, $this->anything())->thenThrow(new ExceptionInput("subjectMissing")); // subscription does not exist
$exp = new Response(204); $exp = new Response(204);
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/move", json_encode($in[0]), 'application/json'))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/move", json_encode($in[0]), 'application/json')));
$exp = new Response(204); $exp = new Response(204);
@ -520,12 +520,12 @@ class TestNCNV1_2 extends Test\AbstractTest {
['feedTitle' => false], ['feedTitle' => false],
['feedTitle' => "Feed does not exist"], ['feedTitle' => "Feed does not exist"],
]; ];
Phake::when(Data::$db)->subscriptionPropertiesSet(Data::$user->id, 1, $this->identicalTo(['title' => null]))->thenReturn(true); Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, $this->identicalTo(['title' => null]))->thenReturn(true);
Phake::when(Data::$db)->subscriptionPropertiesSet(Data::$user->id, 1, $this->identicalTo(['title' => "Ook"]))->thenReturn(true); Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, $this->identicalTo(['title' => "Ook"]))->thenReturn(true);
Phake::when(Data::$db)->subscriptionPropertiesSet(Data::$user->id, 1, $this->identicalTo(['title' => " "]))->thenThrow(new ExceptionInput("whitespace")); Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, $this->identicalTo(['title' => " "]))->thenThrow(new ExceptionInput("whitespace"));
Phake::when(Data::$db)->subscriptionPropertiesSet(Data::$user->id, 1, $this->identicalTo(['title' => ""]))->thenThrow(new ExceptionInput("missing")); Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, $this->identicalTo(['title' => ""]))->thenThrow(new ExceptionInput("missing"));
Phake::when(Data::$db)->subscriptionPropertiesSet(Data::$user->id, 1, $this->identicalTo(['title' => false]))->thenThrow(new ExceptionInput("missing")); Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, $this->identicalTo(['title' => false]))->thenThrow(new ExceptionInput("missing"));
Phake::when(Data::$db)->subscriptionPropertiesSet(Data::$user->id, 42, $this->anything())->thenThrow(new ExceptionInput("subjectMissing")); Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 42, $this->anything())->thenThrow(new ExceptionInput("subjectMissing"));
$exp = new Response(204); $exp = new Response(204);
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/rename", json_encode($in[0]), 'application/json'))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/rename", json_encode($in[0]), 'application/json')));
$exp = new Response(204); $exp = new Response(204);
@ -549,11 +549,11 @@ class TestNCNV1_2 extends Test\AbstractTest {
'userId' => "", 'userId' => "",
], ],
]; ];
Phake::when(Data::$db)->feedListStale->thenReturn(array_column($out,"id")); Phake::when(Arsse::$db)->feedListStale->thenReturn(array_column($out,"id"));
$exp = new Response(200, ['feeds' => $out]); $exp = new Response(200, ['feeds' => $out]);
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/feeds/all"))); $this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/feeds/all")));
// retrieving the list when not an admin fails // retrieving the list when not an admin fails
Phake::when(Data::$user)->rightsGet->thenReturn(0); Phake::when(Arsse::$user)->rightsGet->thenReturn(0);
$exp = new Response(403); $exp = new Response(403);
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/feeds/all"))); $this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/feeds/all")));
} }
@ -565,8 +565,8 @@ class TestNCNV1_2 extends Test\AbstractTest {
['feedId' => "ook"], // invalid ID ['feedId' => "ook"], // invalid ID
['feed' => 42], // invalid input ['feed' => 42], // invalid input
]; ];
Phake::when(Data::$db)->feedUpdate( 42)->thenReturn(true); Phake::when(Arsse::$db)->feedUpdate( 42)->thenReturn(true);
Phake::when(Data::$db)->feedUpdate(2112)->thenThrow(new ExceptionInput("subjectMissing")); Phake::when(Arsse::$db)->feedUpdate(2112)->thenThrow(new ExceptionInput("subjectMissing"));
$exp = new Response(204); $exp = new Response(204);
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[0]), 'application/json'))); $this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[0]), 'application/json')));
$exp = new Response(404); $exp = new Response(404);
@ -576,7 +576,7 @@ class TestNCNV1_2 extends Test\AbstractTest {
$exp = new Response(422); $exp = new Response(422);
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[3]), 'application/json'))); $this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[3]), 'application/json')));
// updating a feed when not an admin fails // updating a feed when not an admin fails
Phake::when(Data::$user)->rightsGet->thenReturn(0); Phake::when(Arsse::$user)->rightsGet->thenReturn(0);
$exp = new Response(403); $exp = new Response(403);
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[0]), 'application/json'))); $this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[0]), 'application/json')));
} }
@ -596,9 +596,9 @@ class TestNCNV1_2 extends Test\AbstractTest {
['lastModified' => $t->getTimestamp()], ['lastModified' => $t->getTimestamp()],
['oldestFirst' => false, 'batchSize' => 5, 'offset' => 0], // offset=0 should not set the latestEdition context ['oldestFirst' => false, 'batchSize' => 5, 'offset' => 0], // offset=0 should not set the latestEdition context
]; ];
Phake::when(Data::$db)->articleList(Data::$user->id, $this->anything())->thenReturn($res); Phake::when(Arsse::$db)->articleList(Arsse::$user->id, $this->anything())->thenReturn($res);
Phake::when(Data::$db)->articleList(Data::$user->id, (new Context)->reverse(true)->subscription(42))->thenThrow(new ExceptionInput("idMissing")); Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->subscription(42))->thenThrow(new ExceptionInput("idMissing"));
Phake::when(Data::$db)->articleList(Data::$user->id, (new Context)->reverse(true)->folder(2112))->thenThrow(new ExceptionInput("idMissing")); Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->folder(2112))->thenThrow(new ExceptionInput("idMissing"));
$exp = new Response(200, ['items' => $this->articles['rest']]); $exp = new Response(200, ['items' => $this->articles['rest']]);
// check the contents of the response // check the contents of the response
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/items"))); // first instance of base context $this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/items"))); // first instance of base context
@ -617,22 +617,22 @@ class TestNCNV1_2 extends Test\AbstractTest {
$this->h->dispatch(new Request("GET", "/items", json_encode($in[8]), 'application/json')); $this->h->dispatch(new Request("GET", "/items", json_encode($in[8]), 'application/json'));
$this->h->dispatch(new Request("GET", "/items", json_encode($in[9]), 'application/json')); $this->h->dispatch(new Request("GET", "/items", json_encode($in[9]), 'application/json'));
// perform method verifications // perform method verifications
Phake::verify(Data::$db, Phake::times(4))->articleList(Data::$user->id, (new Context)->reverse(true)); Phake::verify(Arsse::$db, Phake::times(4))->articleList(Arsse::$user->id, (new Context)->reverse(true));
Phake::verify(Data::$db)->articleList(Data::$user->id, (new Context)->reverse(true)->subscription(42)); Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->subscription(42));
Phake::verify(Data::$db)->articleList(Data::$user->id, (new Context)->reverse(true)->folder(2112)); Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->folder(2112));
Phake::verify(Data::$db)->articleList(Data::$user->id, (new Context)->reverse(true)->starred(true)); Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->starred(true));
Phake::verify(Data::$db)->articleList(Data::$user->id, (new Context)->reverse(false)->limit(10)->oldestEdition(6)); Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(false)->limit(10)->oldestEdition(6));
Phake::verify(Data::$db)->articleList(Data::$user->id, (new Context)->reverse(true)->limit(5)->latestEdition(4)); Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->limit(5)->latestEdition(4));
Phake::verify(Data::$db)->articleList(Data::$user->id, (new Context)->reverse(true)->unread(true)); Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->unread(true));
Phake::verify(Data::$db)->articleList(Data::$user->id, (new Context)->reverse(true)->modifiedSince($t)); Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->modifiedSince($t));
Phake::verify(Data::$db)->articleList(Data::$user->id, (new Context)->reverse(true)->limit(5)); Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->limit(5));
} }
function testMarkAFolderRead() { function testMarkAFolderRead() {
$read = ['read' => true]; $read = ['read' => true];
$in = json_encode(['newestItemId' => 2112]); $in = json_encode(['newestItemId' => 2112]);
Phake::when(Data::$db)->articleMark(Data::$user->id, $read, (new Context)->folder(1)->latestEdition(2112))->thenReturn(true); Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->folder(1)->latestEdition(2112))->thenReturn(true);
Phake::when(Data::$db)->articleMark(Data::$user->id, $read, (new Context)->folder(42)->latestEdition(2112))->thenThrow(new ExceptionInput("idMissing")); // folder doesn't exist Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->folder(42)->latestEdition(2112))->thenThrow(new ExceptionInput("idMissing")); // folder doesn't exist
$exp = new Response(204); $exp = new Response(204);
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1/read", $in, 'application/json'))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1/read", $in, 'application/json')));
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1/read?newestItemId=2112"))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1/read?newestItemId=2112")));
@ -646,8 +646,8 @@ class TestNCNV1_2 extends Test\AbstractTest {
function testMarkASubscriptionRead() { function testMarkASubscriptionRead() {
$read = ['read' => true]; $read = ['read' => true];
$in = json_encode(['newestItemId' => 2112]); $in = json_encode(['newestItemId' => 2112]);
Phake::when(Data::$db)->articleMark(Data::$user->id, $read, (new Context)->subscription(1)->latestEdition(2112))->thenReturn(true); Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->subscription(1)->latestEdition(2112))->thenReturn(true);
Phake::when(Data::$db)->articleMark(Data::$user->id, $read, (new Context)->subscription(42)->latestEdition(2112))->thenThrow(new ExceptionInput("idMissing")); // subscription doesn't exist Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->subscription(42)->latestEdition(2112))->thenThrow(new ExceptionInput("idMissing")); // subscription doesn't exist
$exp = new Response(204); $exp = new Response(204);
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/read", $in, 'application/json'))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/read", $in, 'application/json')));
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/read?newestItemId=2112"))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/read?newestItemId=2112")));
@ -661,7 +661,7 @@ class TestNCNV1_2 extends Test\AbstractTest {
function testMarkAllItemsRead() { function testMarkAllItemsRead() {
$read = ['read' => true]; $read = ['read' => true];
$in = json_encode(['newestItemId' => 2112]); $in = json_encode(['newestItemId' => 2112]);
Phake::when(Data::$db)->articleMark(Data::$user->id, $read, (new Context)->latestEdition(2112))->thenReturn(true); Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->latestEdition(2112))->thenReturn(true);
$exp = new Response(204); $exp = new Response(204);
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/read", $in, 'application/json'))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/read", $in, 'application/json')));
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/read?newestItemId=2112"))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/read?newestItemId=2112")));
@ -675,14 +675,14 @@ class TestNCNV1_2 extends Test\AbstractTest {
$unread = ['read' => false]; $unread = ['read' => false];
$star = ['starred' => true]; $star = ['starred' => true];
$unstar = ['starred' => false]; $unstar = ['starred' => false];
Phake::when(Data::$db)->articleMark(Data::$user->id, $read, (new Context)->edition(1))->thenReturn(true); Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->edition(1))->thenReturn(true);
Phake::when(Data::$db)->articleMark(Data::$user->id, $read, (new Context)->edition(42))->thenThrow(new ExceptionInput("subjectMissing")); // edition doesn't exist doesn't exist Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->edition(42))->thenThrow(new ExceptionInput("subjectMissing")); // edition doesn't exist doesn't exist
Phake::when(Data::$db)->articleMark(Data::$user->id, $unread, (new Context)->edition(2))->thenReturn(true); Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $unread, (new Context)->edition(2))->thenReturn(true);
Phake::when(Data::$db)->articleMark(Data::$user->id, $unread, (new Context)->edition(47))->thenThrow(new ExceptionInput("subjectMissing")); // edition doesn't exist doesn't exist Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $unread, (new Context)->edition(47))->thenThrow(new ExceptionInput("subjectMissing")); // edition doesn't exist doesn't exist
Phake::when(Data::$db)->articleMark(Data::$user->id, $star, (new Context)->article(3))->thenReturn(true); Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $star, (new Context)->article(3))->thenReturn(true);
Phake::when(Data::$db)->articleMark(Data::$user->id, $star, (new Context)->article(2112))->thenThrow(new ExceptionInput("subjectMissing")); // article doesn't exist doesn't exist Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $star, (new Context)->article(2112))->thenThrow(new ExceptionInput("subjectMissing")); // article doesn't exist doesn't exist
Phake::when(Data::$db)->articleMark(Data::$user->id, $unstar, (new Context)->article(4))->thenReturn(true); Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->article(4))->thenReturn(true);
Phake::when(Data::$db)->articleMark(Data::$user->id, $unstar, (new Context)->article(1337))->thenThrow(new ExceptionInput("subjectMissing")); // article doesn't exist doesn't exist Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->article(1337))->thenThrow(new ExceptionInput("subjectMissing")); // article doesn't exist doesn't exist
$exp = new Response(204); $exp = new Response(204);
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/1/read"))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/1/read")));
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/2/unread"))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/2/unread")));
@ -693,7 +693,7 @@ class TestNCNV1_2 extends Test\AbstractTest {
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/47/unread"))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/47/unread")));
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/1/2112/star"))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/1/2112/star")));
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/4400/1337/unstar"))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/4400/1337/unstar")));
Phake::verify(Data::$db, Phake::times(8))->articleMark(Data::$user->id, $this->anything(), $this->anything()); Phake::verify(Arsse::$db, Phake::times(8))->articleMark(Arsse::$user->id, $this->anything(), $this->anything());
} }
function testChangeMarksOfMultipleArticles() { function testChangeMarksOfMultipleArticles() {
@ -713,9 +713,9 @@ class TestNCNV1_2 extends Test\AbstractTest {
$inStar[$a][$b] = ['feedId' => 2112, 'guidHash' => $inStar[$a][$b]]; $inStar[$a][$b] = ['feedId' => 2112, 'guidHash' => $inStar[$a][$b]];
} }
} }
Phake::when(Data::$db)->articleMark(Data::$user->id, $this->anything(), $this->anything())->thenReturn(true); Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), $this->anything())->thenReturn(true);
Phake::when(Data::$db)->articleMark(Data::$user->id, $this->anything(), (new Context)->editions([]))->thenThrow(new ExceptionInput("tooShort")); // data model function requires one valid integer for multiples Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), (new Context)->editions([]))->thenThrow(new ExceptionInput("tooShort")); // data model function requires one valid integer for multiples
Phake::when(Data::$db)->articleMark(Data::$user->id, $this->anything(), (new Context)->editions($in[1]))->thenThrow(new ExceptionInput("tooLong")); // data model function for limited to 50 items for multiples Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), (new Context)->editions($in[1]))->thenThrow(new ExceptionInput("tooLong")); // data model function for limited to 50 items for multiples
$exp = new Response(422); $exp = new Response(422);
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/read/multiple"))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/read/multiple")));
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/unread/multiple"))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/unread/multiple")));
@ -740,26 +740,26 @@ class TestNCNV1_2 extends Test\AbstractTest {
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/star/multiple", json_encode(['items' => $inStar[1]]), 'application/json'))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/star/multiple", json_encode(['items' => $inStar[1]]), 'application/json')));
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/unstar/multiple", json_encode(['items' => $inStar[1]]), 'application/json'))); $this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/unstar/multiple", json_encode(['items' => $inStar[1]]), 'application/json')));
// ensure the data model was queried appropriately for read/unread // ensure the data model was queried appropriately for read/unread
Phake::verify(Data::$db)->articleMark(Data::$user->id, $read, (new Context)->editions([])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->editions([]));
Phake::verify(Data::$db)->articleMark(Data::$user->id, $read, (new Context)->editions($in[0])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->editions($in[0]));
Phake::verify(Data::$db, Phake::times(0))->articleMark(Data::$user->id, $read, (new Context)->editions($in[1])); Phake::verify(Arsse::$db, Phake::times(0))->articleMark(Arsse::$user->id, $read, (new Context)->editions($in[1]));
Phake::verify(Data::$db)->articleMark(Data::$user->id, $read, (new Context)->editions($in[2])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->editions($in[2]));
Phake::verify(Data::$db)->articleMark(Data::$user->id, $read, (new Context)->editions($in[3])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->editions($in[3]));
Phake::verify(Data::$db)->articleMark(Data::$user->id, $unread, (new Context)->editions([])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $unread, (new Context)->editions([]));
Phake::verify(Data::$db)->articleMark(Data::$user->id, $unread, (new Context)->editions($in[0])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $unread, (new Context)->editions($in[0]));
Phake::verify(Data::$db, Phake::times(0))->articleMark(Data::$user->id, $unread, (new Context)->editions($in[1])); Phake::verify(Arsse::$db, Phake::times(0))->articleMark(Arsse::$user->id, $unread, (new Context)->editions($in[1]));
Phake::verify(Data::$db)->articleMark(Data::$user->id, $unread, (new Context)->editions($in[2])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $unread, (new Context)->editions($in[2]));
Phake::verify(Data::$db)->articleMark(Data::$user->id, $unread, (new Context)->editions($in[3])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $unread, (new Context)->editions($in[3]));
// ensure the data model was queried appropriately for star/unstar // ensure the data model was queried appropriately for star/unstar
Phake::verify(Data::$db)->articleMark(Data::$user->id, $star, (new Context)->articles([])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $star, (new Context)->articles([]));
Phake::verify(Data::$db)->articleMark(Data::$user->id, $star, (new Context)->articles($in[0])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $star, (new Context)->articles($in[0]));
Phake::verify(Data::$db, Phake::times(0))->articleMark(Data::$user->id, $star, (new Context)->articles($in[1])); Phake::verify(Arsse::$db, Phake::times(0))->articleMark(Arsse::$user->id, $star, (new Context)->articles($in[1]));
Phake::verify(Data::$db)->articleMark(Data::$user->id, $star, (new Context)->articles($in[2])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $star, (new Context)->articles($in[2]));
Phake::verify(Data::$db)->articleMark(Data::$user->id, $star, (new Context)->articles($in[3])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $star, (new Context)->articles($in[3]));
Phake::verify(Data::$db)->articleMark(Data::$user->id, $unstar, (new Context)->articles([])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->articles([]));
Phake::verify(Data::$db)->articleMark(Data::$user->id, $unstar, (new Context)->articles($in[0])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->articles($in[0]));
Phake::verify(Data::$db, Phake::times(0))->articleMark(Data::$user->id, $unstar, (new Context)->articles($in[1])); Phake::verify(Arsse::$db, Phake::times(0))->articleMark(Arsse::$user->id, $unstar, (new Context)->articles($in[1]));
Phake::verify(Data::$db)->articleMark(Data::$user->id, $unstar, (new Context)->articles($in[2])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->articles($in[2]));
Phake::verify(Data::$db)->articleMark(Data::$user->id, $unstar, (new Context)->articles($in[3])); Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->articles($in[3]));
} }
} }

View file

@ -50,17 +50,17 @@ class TestAuthorization extends Test\AbstractTest {
$conf->userDriver = $drv; $conf->userDriver = $drv;
$conf->userPreAuth = false; $conf->userPreAuth = false;
$conf->userComposeNames = true; $conf->userComposeNames = true;
Data::$conf = $conf; Arsse::$conf = $conf;
if($db !== null) { if($db !== null) {
Data::$db = new $db(); Arsse::$db = new $db();
} }
Data::$user = Phake::PartialMock(User::class); Arsse::$user = Phake::PartialMock(User::class);
Phake::when(Data::$user)->authorize->thenReturn(true); Phake::when(Arsse::$user)->authorize->thenReturn(true);
foreach(self::USERS as $user => $level) { foreach(self::USERS as $user => $level) {
Data::$user->add($user, ""); Arsse::$user->add($user, "");
Data::$user->rightsSet($user, $level); Arsse::$user->rightsSet($user, $level);
} }
Phake::reset(Data::$user); Phake::reset(Arsse::$user);
} }
function tearDown() { function tearDown() {
@ -68,44 +68,44 @@ class TestAuthorization extends Test\AbstractTest {
} }
function testToggleLogic() { function testToggleLogic() {
$this->assertTrue(Data::$user->authorizationEnabled()); $this->assertTrue(Arsse::$user->authorizationEnabled());
$this->assertTrue(Data::$user->authorizationEnabled(true)); $this->assertTrue(Arsse::$user->authorizationEnabled(true));
$this->assertFalse(Data::$user->authorizationEnabled(false)); $this->assertFalse(Arsse::$user->authorizationEnabled(false));
$this->assertFalse(Data::$user->authorizationEnabled(false)); $this->assertFalse(Arsse::$user->authorizationEnabled(false));
$this->assertFalse(Data::$user->authorizationEnabled(true)); $this->assertFalse(Arsse::$user->authorizationEnabled(true));
$this->assertTrue(Data::$user->authorizationEnabled(true)); $this->assertTrue(Arsse::$user->authorizationEnabled(true));
} }
function testSelfActionLogic() { function testSelfActionLogic() {
foreach(array_keys(self::USERS) as $user) { foreach(array_keys(self::USERS) as $user) {
Data::$user->auth($user, ""); Arsse::$user->auth($user, "");
// users should be able to do basic actions for themselves // users should be able to do basic actions for themselves
$this->assertTrue(Data::$user->authorize($user, "userExists"), "User $user could not act for themselves."); $this->assertTrue(Arsse::$user->authorize($user, "userExists"), "User $user could not act for themselves.");
$this->assertTrue(Data::$user->authorize($user, "userRemove"), "User $user could not act for themselves."); $this->assertTrue(Arsse::$user->authorize($user, "userRemove"), "User $user could not act for themselves.");
} }
} }
function testRegularUserLogic() { function testRegularUserLogic() {
foreach(self::USERS as $actor => $rights) { foreach(self::USERS as $actor => $rights) {
if($rights != User\Driver::RIGHTS_NONE) continue; if($rights != User\Driver::RIGHTS_NONE) continue;
Data::$user->auth($actor, ""); Arsse::$user->auth($actor, "");
foreach(array_keys(self::USERS) as $affected) { foreach(array_keys(self::USERS) as $affected) {
// regular users should only be able to act for themselves // regular users should only be able to act for themselves
if($actor==$affected) { if($actor==$affected) {
$this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
$this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
} else { } else {
$this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed.");
$this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed.");
} }
// they should never be able to set rights // they should never be able to set rights
foreach(self::LEVELS as $level) { foreach(self::LEVELS as $level) {
$this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
} }
} }
// they should not be able to list users // they should not be able to list users
foreach(self::DOMAINS as $domain) { foreach(self::DOMAINS as $domain) {
$this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
} }
} }
} }
@ -114,36 +114,36 @@ class TestAuthorization extends Test\AbstractTest {
foreach(self::USERS as $actor => $actorRights) { foreach(self::USERS as $actor => $actorRights) {
if($actorRights != User\Driver::RIGHTS_DOMAIN_MANAGER) continue; if($actorRights != User\Driver::RIGHTS_DOMAIN_MANAGER) continue;
$actorDomain = substr($actor,strrpos($actor,"@")+1); $actorDomain = substr($actor,strrpos($actor,"@")+1);
Data::$user->auth($actor, ""); Arsse::$user->auth($actor, "");
foreach(self::USERS as $affected => $affectedRights) { foreach(self::USERS as $affected => $affectedRights) {
$affectedDomain = substr($affected,strrpos($affected,"@")+1); $affectedDomain = substr($affected,strrpos($affected,"@")+1);
// domain managers should be able to check any user on the same domain // domain managers should be able to check any user on the same domain
if($actorDomain==$affectedDomain) { if($actorDomain==$affectedDomain) {
$this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
} else { } else {
$this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed.");
} }
// they should only be able to act for regular users on the same domain // they should only be able to act for regular users on the same domain
if($actor==$affected || ($actorDomain==$affectedDomain && $affectedRights==User\Driver::RIGHTS_NONE)) { if($actor==$affected || ($actorDomain==$affectedDomain && $affectedRights==User\Driver::RIGHTS_NONE)) {
$this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
} else { } else {
$this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed.");
} }
// and they should only be able to set their own rights to regular user // and they should only be able to set their own rights to regular user
foreach(self::LEVELS as $level) { foreach(self::LEVELS as $level) {
if($actor==$affected && in_array($level, [User\Driver::RIGHTS_NONE, User\Driver::RIGHTS_DOMAIN_MANAGER])) { if($actor==$affected && in_array($level, [User\Driver::RIGHTS_NONE, User\Driver::RIGHTS_DOMAIN_MANAGER])) {
$this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
} else { } else {
$this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
} }
} }
} }
// they should also be able to list all users on their own domain // they should also be able to list all users on their own domain
foreach(self::DOMAINS as $domain) { foreach(self::DOMAINS as $domain) {
if($domain=="@".$actorDomain) { if($domain=="@".$actorDomain) {
$this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); $this->assertTrue(Arsse::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
} else { } else {
$this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
} }
} }
} }
@ -153,37 +153,37 @@ class TestAuthorization extends Test\AbstractTest {
foreach(self::USERS as $actor => $actorRights) { foreach(self::USERS as $actor => $actorRights) {
if($actorRights != User\Driver::RIGHTS_DOMAIN_ADMIN) continue; if($actorRights != User\Driver::RIGHTS_DOMAIN_ADMIN) continue;
$actorDomain = substr($actor,strrpos($actor,"@")+1); $actorDomain = substr($actor,strrpos($actor,"@")+1);
Data::$user->auth($actor, ""); Arsse::$user->auth($actor, "");
$allowed = [User\Driver::RIGHTS_NONE,User\Driver::RIGHTS_DOMAIN_MANAGER,User\Driver::RIGHTS_DOMAIN_ADMIN]; $allowed = [User\Driver::RIGHTS_NONE,User\Driver::RIGHTS_DOMAIN_MANAGER,User\Driver::RIGHTS_DOMAIN_ADMIN];
foreach(self::USERS as $affected => $affectedRights) { foreach(self::USERS as $affected => $affectedRights) {
$affectedDomain = substr($affected,strrpos($affected,"@")+1); $affectedDomain = substr($affected,strrpos($affected,"@")+1);
// domain admins should be able to check any user on the same domain // domain admins should be able to check any user on the same domain
if($actorDomain==$affectedDomain) { if($actorDomain==$affectedDomain) {
$this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
} else { } else {
$this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed.");
} }
// they should be able to act for any user on the same domain who is not a global manager or admin // they should be able to act for any user on the same domain who is not a global manager or admin
if($actorDomain==$affectedDomain && in_array($affectedRights, $allowed)) { if($actorDomain==$affectedDomain && in_array($affectedRights, $allowed)) {
$this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
} else { } else {
$this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed.");
} }
// they should be able to set rights for any user on their domain who is not a global manager or admin, up to domain admin level // they should be able to set rights for any user on their domain who is not a global manager or admin, up to domain admin level
foreach(self::LEVELS as $level) { foreach(self::LEVELS as $level) {
if($actorDomain==$affectedDomain && in_array($affectedRights, $allowed) && in_array($level, $allowed)) { if($actorDomain==$affectedDomain && in_array($affectedRights, $allowed) && in_array($level, $allowed)) {
$this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
} else { } else {
$this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
} }
} }
} }
// they should also be able to list all users on their own domain // they should also be able to list all users on their own domain
foreach(self::DOMAINS as $domain) { foreach(self::DOMAINS as $domain) {
if($domain=="@".$actorDomain) { if($domain=="@".$actorDomain) {
$this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); $this->assertTrue(Arsse::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
} else { } else {
$this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
} }
} }
} }
@ -193,29 +193,29 @@ class TestAuthorization extends Test\AbstractTest {
foreach(self::USERS as $actor => $actorRights) { foreach(self::USERS as $actor => $actorRights) {
if($actorRights != User\Driver::RIGHTS_GLOBAL_MANAGER) continue; if($actorRights != User\Driver::RIGHTS_GLOBAL_MANAGER) continue;
$actorDomain = substr($actor,strrpos($actor,"@")+1); $actorDomain = substr($actor,strrpos($actor,"@")+1);
Data::$user->auth($actor, ""); Arsse::$user->auth($actor, "");
foreach(self::USERS as $affected => $affectedRights) { foreach(self::USERS as $affected => $affectedRights) {
$affectedDomain = substr($affected,strrpos($affected,"@")+1); $affectedDomain = substr($affected,strrpos($affected,"@")+1);
// global managers should be able to check any user // global managers should be able to check any user
$this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
// they should only be able to act for regular users // they should only be able to act for regular users
if($actor==$affected || $affectedRights==User\Driver::RIGHTS_NONE) { if($actor==$affected || $affectedRights==User\Driver::RIGHTS_NONE) {
$this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
} else { } else {
$this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed.");
} }
// and they should only be able to set their own rights to regular user // and they should only be able to set their own rights to regular user
foreach(self::LEVELS as $level) { foreach(self::LEVELS as $level) {
if($actor==$affected && in_array($level, [User\Driver::RIGHTS_NONE, User\Driver::RIGHTS_GLOBAL_MANAGER])) { if($actor==$affected && in_array($level, [User\Driver::RIGHTS_NONE, User\Driver::RIGHTS_GLOBAL_MANAGER])) {
$this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
} else { } else {
$this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
} }
} }
} }
// they should also be able to list all users // they should also be able to list all users
foreach(self::DOMAINS as $domain) { foreach(self::DOMAINS as $domain) {
$this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); $this->assertTrue(Arsse::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
} }
} }
} }
@ -223,17 +223,17 @@ class TestAuthorization extends Test\AbstractTest {
function testGlobalAdministratorLogic() { function testGlobalAdministratorLogic() {
foreach(self::USERS as $actor => $actorRights) { foreach(self::USERS as $actor => $actorRights) {
if($actorRights != User\Driver::RIGHTS_GLOBAL_ADMIN) continue; if($actorRights != User\Driver::RIGHTS_GLOBAL_ADMIN) continue;
Data::$user->auth($actor, ""); Arsse::$user->auth($actor, "");
// global admins can do anything // global admins can do anything
foreach(self::USERS as $affected => $affectedRights) { foreach(self::USERS as $affected => $affectedRights) {
$this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
$this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
foreach(self::LEVELS as $level) { foreach(self::LEVELS as $level) {
$this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
} }
} }
foreach(self::DOMAINS as $domain) { foreach(self::DOMAINS as $domain) {
$this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); $this->assertTrue(Arsse::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
} }
} }
} }
@ -241,24 +241,24 @@ class TestAuthorization extends Test\AbstractTest {
function testInvalidLevelLogic() { function testInvalidLevelLogic() {
foreach(self::USERS as $actor => $rights) { foreach(self::USERS as $actor => $rights) {
if(in_array($rights, self::LEVELS)) continue; if(in_array($rights, self::LEVELS)) continue;
Data::$user->auth($actor, ""); Arsse::$user->auth($actor, "");
foreach(array_keys(self::USERS) as $affected) { foreach(array_keys(self::USERS) as $affected) {
// users with unknown/invalid rights should be treated just like regular users and only be able to act for themselves // users with unknown/invalid rights should be treated just like regular users and only be able to act for themselves
if($actor==$affected) { if($actor==$affected) {
$this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
$this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); $this->assertTrue(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
} else { } else {
$this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed.");
$this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed.");
} }
// they should never be able to set rights // they should never be able to set rights
foreach(self::LEVELS as $level) { foreach(self::LEVELS as $level) {
$this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
} }
} }
// they should not be able to list users // they should not be able to list users
foreach(self::DOMAINS as $domain) { foreach(self::DOMAINS as $domain) {
$this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); $this->assertFalse(Arsse::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
} }
} }
} }
@ -277,10 +277,10 @@ class TestAuthorization extends Test\AbstractTest {
'list' => [], 'list' => [],
]; ];
// try first with a global admin (there should be no exception) // try first with a global admin (there should be no exception)
Data::$user->auth("gadm@example.com", ""); Arsse::$user->auth("gadm@example.com", "");
$this->assertCount(0, $this->checkExceptions("user@example.org", $tests)); $this->assertCount(0, $this->checkExceptions("user@example.org", $tests));
// next try with a regular user acting on another user (everything should fail) // next try with a regular user acting on another user (everything should fail)
Data::$user->auth("user@example.com", ""); Arsse::$user->auth("user@example.com", "");
$this->assertCount(sizeof($tests), $this->checkExceptions("user@example.org", $tests)); $this->assertCount(sizeof($tests), $this->checkExceptions("user@example.org", $tests));
} }
@ -299,7 +299,7 @@ class TestAuthorization extends Test\AbstractTest {
// list method does not take an affected user, so do not unshift for that one // list method does not take an affected user, so do not unshift for that one
if($func != "list") array_unshift($args, $user); if($func != "list") array_unshift($args, $user);
try { try {
call_user_func_array(array(Data::$user, $func), $args); call_user_func_array(array(Arsse::$user, $func), $args);
} catch(User\ExceptionAuthz $e) { } catch(User\ExceptionAuthz $e) {
$err[] = $func; $err[] = $func;
} }
@ -308,9 +308,9 @@ class TestAuthorization extends Test\AbstractTest {
} }
function testMissingUserLogic() { function testMissingUserLogic() {
Data::$user->auth("gadm@example.com", ""); Arsse::$user->auth("gadm@example.com", "");
$this->assertTrue(Data::$user->authorize("user@example.com", "someFunction")); $this->assertTrue(Arsse::$user->authorize("user@example.com", "someFunction"));
$this->assertException("doesNotExist", "User"); $this->assertException("doesNotExist", "User");
Data::$user->authorize("this_user_does_not_exist@example.org", "someFunction"); Arsse::$user->authorize("this_user_does_not_exist@example.org", "someFunction");
} }
} }

View file

@ -12,6 +12,6 @@ class TestUserMockInternal extends Test\AbstractTest {
public $drv = Test\User\DriverInternalMock::class; public $drv = Test\User\DriverInternalMock::class;
function setUpSeries() { function setUpSeries() {
Data::$db = null; Arsse::$db = null;
} }
} }

View file

@ -2,10 +2,10 @@
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Test; namespace JKingWeb\Arsse\Test;
use JKingWeb\Arsse\Exception; use JKingWeb\Arsse\Exception;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\Misc\Date;
abstract class AbstractTest extends \PHPUnit\Framework\TestCase { abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
use \JKingWeb\Arsse\Misc\DateFormatter;
function assertException(string $msg = "", string $prefix = "", string $type = "Exception") { function assertException(string $msg = "", string $prefix = "", string $type = "Exception") {
if(func_num_args()) { if(func_num_args()) {
@ -25,19 +25,19 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
} }
function assertTime($exp, $test) { function assertTime($exp, $test) {
$exp = $this->dateTransform($exp, "iso8601"); $exp = Date::transform($exp, "iso8601");
$test = $this->dateTransform($test, "iso8601"); $test = Date::transform($test, "iso8601");
$this->assertSame($exp, $test); $this->assertSame($exp, $test);
} }
function clearData(bool $loadLang = true): bool { function clearData(bool $loadLang = true): bool {
$r = new \ReflectionClass(\JKingWeb\Arsse\Data::class); $r = new \ReflectionClass(\JKingWeb\Arsse\Arsse::class);
$props = array_keys($r->getStaticProperties()); $props = array_keys($r->getStaticProperties());
foreach($props as $prop) { foreach($props as $prop) {
Data::$$prop = null; Arsse::$$prop = null;
} }
if($loadLang) { if($loadLang) {
Data::$lang = new \JKingWeb\Arsse\Lang(); Arsse::$lang = new \JKingWeb\Arsse\Lang();
} }
return true; return true;
} }

View file

@ -1,7 +1,7 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Test\Database; namespace JKingWeb\Arsse\Test\Database;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\Db\SQLite3\Driver; use JKingWeb\Arsse\Db\SQLite3\Driver;
trait DriverSQLite3 { trait DriverSQLite3 {
@ -9,7 +9,7 @@ trait DriverSQLite3 {
if(!extension_loaded("sqlite3")) { if(!extension_loaded("sqlite3")) {
$this->markTestSkipped("SQLite extension not loaded"); $this->markTestSkipped("SQLite extension not loaded");
} }
Data::$conf->dbSQLite3File = ":memory:"; Arsse::$conf->dbSQLite3File = ":memory:";
$this->drv = new Driver(true); $this->drv = new Driver(true);
} }

View file

@ -1,12 +1,13 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Test\Database; namespace JKingWeb\Arsse\Test\Database;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\Feed; use JKingWeb\Arsse\Feed;
use JKingWeb\Arsse\Test\Database; use JKingWeb\Arsse\Test\Database;
use JKingWeb\Arsse\User\Driver as UserDriver; use JKingWeb\Arsse\User\Driver as UserDriver;
use JKingWeb\Arsse\Feed\Exception as FeedException; use JKingWeb\Arsse\Feed\Exception as FeedException;
use JKingWeb\Arsse\Misc\Context; use JKingWeb\Arsse\Misc\Context;
use JKingWeb\Arsse\Misc\Date;
use Phake; use Phake;
trait SeriesArticle { trait SeriesArticle {
@ -277,7 +278,7 @@ trait SeriesArticle {
} }
protected function compareIds(array $exp, Context $c) { protected function compareIds(array $exp, Context $c) {
$ids = array_column($ids = Data::$db->articleList($this->user, $c)->getAll(), "id"); $ids = array_column($ids = Arsse::$db->articleList($this->user, $c)->getAll(), "id");
sort($ids); sort($ids);
sort($exp); sort($exp);
$this->assertEquals($exp, $ids); $this->assertEquals($exp, $ids);
@ -330,28 +331,28 @@ trait SeriesArticle {
function testListArticlesOfAMissingFolder() { function testListArticlesOfAMissingFolder() {
$this->assertException("idMissing", "Db", "ExceptionInput"); $this->assertException("idMissing", "Db", "ExceptionInput");
Data::$db->articleList($this->user, (new Context)->folder(1)); Arsse::$db->articleList($this->user, (new Context)->folder(1));
} }
function testListArticlesOfAMissingSubscription() { function testListArticlesOfAMissingSubscription() {
$this->assertException("idMissing", "Db", "ExceptionInput"); $this->assertException("idMissing", "Db", "ExceptionInput");
Data::$db->articleList($this->user, (new Context)->subscription(1)); Arsse::$db->articleList($this->user, (new Context)->subscription(1));
} }
function testListArticlesCheckingProperties() { function testListArticlesCheckingProperties() {
$this->user = "john.doe@example.org"; $this->user = "john.doe@example.org";
$this->assertResult($this->matches, Data::$db->articleList($this->user)); $this->assertResult($this->matches, Arsse::$db->articleList($this->user));
} }
function testListArticlesWithoutAuthority() { function testListArticlesWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->articleList($this->user); Arsse::$db->articleList($this->user);
} }
function testMarkAllArticlesUnread() { function testMarkAllArticlesUnread() {
Data::$db->articleMark($this->user, ['read'=>false]); Arsse::$db->articleMark($this->user, ['read'=>false]);
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][9][2] = 0; $state['arsse_marks']['rows'][9][2] = 0;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
@ -361,8 +362,8 @@ trait SeriesArticle {
} }
function testMarkAllArticlesRead() { function testMarkAllArticlesRead() {
Data::$db->articleMark($this->user, ['read'=>true]); Arsse::$db->articleMark($this->user, ['read'=>true]);
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][8][2] = 1; $state['arsse_marks']['rows'][8][2] = 1;
$state['arsse_marks']['rows'][8][4] = $now; $state['arsse_marks']['rows'][8][4] = $now;
@ -376,8 +377,8 @@ trait SeriesArticle {
} }
function testMarkAllArticlesUnstarred() { function testMarkAllArticlesUnstarred() {
Data::$db->articleMark($this->user, ['starred'=>false]); Arsse::$db->articleMark($this->user, ['starred'=>false]);
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][10][3] = 0; $state['arsse_marks']['rows'][10][3] = 0;
$state['arsse_marks']['rows'][10][4] = $now; $state['arsse_marks']['rows'][10][4] = $now;
@ -387,8 +388,8 @@ trait SeriesArticle {
} }
function testMarkAllArticlesStarred() { function testMarkAllArticlesStarred() {
Data::$db->articleMark($this->user, ['starred'=>true]); Arsse::$db->articleMark($this->user, ['starred'=>true]);
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][8][3] = 1; $state['arsse_marks']['rows'][8][3] = 1;
$state['arsse_marks']['rows'][8][4] = $now; $state['arsse_marks']['rows'][8][4] = $now;
@ -402,8 +403,8 @@ trait SeriesArticle {
} }
function testMarkAllArticlesUnreadAndUnstarred() { function testMarkAllArticlesUnreadAndUnstarred() {
Data::$db->articleMark($this->user, ['read'=>false,'starred'=>false]); Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>false]);
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][9][2] = 0; $state['arsse_marks']['rows'][9][2] = 0;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
@ -416,8 +417,8 @@ trait SeriesArticle {
} }
function testMarkAllArticlesReadAndStarred() { function testMarkAllArticlesReadAndStarred() {
Data::$db->articleMark($this->user, ['read'=>true,'starred'=>true]); Arsse::$db->articleMark($this->user, ['read'=>true,'starred'=>true]);
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][8][2] = 1; $state['arsse_marks']['rows'][8][2] = 1;
$state['arsse_marks']['rows'][8][3] = 1; $state['arsse_marks']['rows'][8][3] = 1;
@ -434,8 +435,8 @@ trait SeriesArticle {
} }
function testMarkAllArticlesUnreadAndStarred() { function testMarkAllArticlesUnreadAndStarred() {
Data::$db->articleMark($this->user, ['read'=>false,'starred'=>true]); Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>true]);
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][8][3] = 1; $state['arsse_marks']['rows'][8][3] = 1;
$state['arsse_marks']['rows'][8][4] = $now; $state['arsse_marks']['rows'][8][4] = $now;
@ -452,8 +453,8 @@ trait SeriesArticle {
} }
function testMarkAllArticlesReadAndUnstarred() { function testMarkAllArticlesReadAndUnstarred() {
Data::$db->articleMark($this->user, ['read'=>true,'starred'=>false]); Arsse::$db->articleMark($this->user, ['read'=>true,'starred'=>false]);
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][8][2] = 1; $state['arsse_marks']['rows'][8][2] = 1;
$state['arsse_marks']['rows'][8][4] = $now; $state['arsse_marks']['rows'][8][4] = $now;
@ -470,8 +471,8 @@ trait SeriesArticle {
} }
function testMarkATreeFolder() { function testMarkATreeFolder() {
Data::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(7)); Arsse::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(7));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][] = [$this->user,5,1,0,$now]; $state['arsse_marks']['rows'][] = [$this->user,5,1,0,$now];
$state['arsse_marks']['rows'][] = [$this->user,6,1,0,$now]; $state['arsse_marks']['rows'][] = [$this->user,6,1,0,$now];
@ -481,8 +482,8 @@ trait SeriesArticle {
} }
function testMarkALeafFolder() { function testMarkALeafFolder() {
Data::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(8)); Arsse::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(8));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][] = [$this->user,5,1,0,$now]; $state['arsse_marks']['rows'][] = [$this->user,5,1,0,$now];
$state['arsse_marks']['rows'][] = [$this->user,6,1,0,$now]; $state['arsse_marks']['rows'][] = [$this->user,6,1,0,$now];
@ -491,12 +492,12 @@ trait SeriesArticle {
function testMarkAMissingFolder() { function testMarkAMissingFolder() {
$this->assertException("idMissing", "Db", "ExceptionInput"); $this->assertException("idMissing", "Db", "ExceptionInput");
Data::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(42)); Arsse::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(42));
} }
function testMarkASubscription() { function testMarkASubscription() {
Data::$db->articleMark($this->user, ['read'=>true], (new Context)->subscription(13)); Arsse::$db->articleMark($this->user, ['read'=>true], (new Context)->subscription(13));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][] = [$this->user,5,1,0,$now]; $state['arsse_marks']['rows'][] = [$this->user,5,1,0,$now];
$state['arsse_marks']['rows'][] = [$this->user,6,1,0,$now]; $state['arsse_marks']['rows'][] = [$this->user,6,1,0,$now];
@ -505,12 +506,12 @@ trait SeriesArticle {
function testMarkAMissingSubscription() { function testMarkAMissingSubscription() {
$this->assertException("idMissing", "Db", "ExceptionInput"); $this->assertException("idMissing", "Db", "ExceptionInput");
Data::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(2112)); Arsse::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(2112));
} }
function testMarkAnArticle() { function testMarkAnArticle() {
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->article(20)); Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->article(20));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
@ -518,8 +519,8 @@ trait SeriesArticle {
} }
function testMarkMultipleArticles() { function testMarkMultipleArticles() {
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->articles([2,4,7,20])); Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->articles([2,4,7,20]));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
@ -528,8 +529,8 @@ trait SeriesArticle {
} }
function testMarkMultipleArticlessUnreadAndStarred() { function testMarkMultipleArticlessUnreadAndStarred() {
Data::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->articles([2,4,7,20])); Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->articles([2,4,7,20]));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][9][2] = 0; $state['arsse_marks']['rows'][9][2] = 0;
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
@ -542,22 +543,22 @@ trait SeriesArticle {
function testMarkTooFewMultipleArticles() { function testMarkTooFewMultipleArticles() {
$this->assertException("tooShort", "Db", "ExceptionInput"); $this->assertException("tooShort", "Db", "ExceptionInput");
Data::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->articles([])); Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->articles([]));
} }
function testMarkTooManyMultipleArticles() { function testMarkTooManyMultipleArticles() {
$this->assertException("tooLong", "Db", "ExceptionInput"); $this->assertException("tooLong", "Db", "ExceptionInput");
Data::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->articles(range(1,51))); Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->articles(range(1,51)));
} }
function testMarkAMissingArticle() { function testMarkAMissingArticle() {
$this->assertException("subjectMissing", "Db", "ExceptionInput"); $this->assertException("subjectMissing", "Db", "ExceptionInput");
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->article(1)); Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->article(1));
} }
function testMarkAnEdition() { function testMarkAnEdition() {
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->edition(1001)); Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->edition(1001));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
@ -565,8 +566,8 @@ trait SeriesArticle {
} }
function testMarkMultipleEditions() { function testMarkMultipleEditions() {
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->editions([2,4,7,20])); Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->editions([2,4,7,20]));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
@ -575,8 +576,8 @@ trait SeriesArticle {
} }
function testMarkMultipleEditionsUnread() { function testMarkMultipleEditionsUnread() {
Data::$db->articleMark($this->user, ['read'=>false], (new Context)->editions([2,4,7,1001])); Arsse::$db->articleMark($this->user, ['read'=>false], (new Context)->editions([2,4,7,1001]));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][9][2] = 0; $state['arsse_marks']['rows'][9][2] = 0;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
@ -586,8 +587,8 @@ trait SeriesArticle {
} }
function testMarkMultipleEditionsUnreadWithStale() { function testMarkMultipleEditionsUnreadWithStale() {
Data::$db->articleMark($this->user, ['read'=>false], (new Context)->editions([2,4,7,20])); Arsse::$db->articleMark($this->user, ['read'=>false], (new Context)->editions([2,4,7,20]));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][11][2] = 0; $state['arsse_marks']['rows'][11][2] = 0;
$state['arsse_marks']['rows'][11][4] = $now; $state['arsse_marks']['rows'][11][4] = $now;
@ -595,8 +596,8 @@ trait SeriesArticle {
} }
function testMarkMultipleEditionsUnreadAndStarredWithStale() { function testMarkMultipleEditionsUnreadAndStarredWithStale() {
Data::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->editions([2,4,7,20])); Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->editions([2,4,7,20]));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
@ -608,23 +609,23 @@ trait SeriesArticle {
function testMarkTooFewMultipleEditions() { function testMarkTooFewMultipleEditions() {
$this->assertException("tooShort", "Db", "ExceptionInput"); $this->assertException("tooShort", "Db", "ExceptionInput");
Data::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->editions([])); Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->editions([]));
} }
function testMarkTooManyMultipleEditions() { function testMarkTooManyMultipleEditions() {
$this->assertException("tooLong", "Db", "ExceptionInput"); $this->assertException("tooLong", "Db", "ExceptionInput");
Data::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->editions(range(1,51))); Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->editions(range(1,51)));
} }
function testMarkAStaleEditionUnread() { function testMarkAStaleEditionUnread() {
Data::$db->articleMark($this->user, ['read'=>false], (new Context)->edition(20)); // no changes occur Arsse::$db->articleMark($this->user, ['read'=>false], (new Context)->edition(20)); // no changes occur
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$this->compareExpectations($state); $this->compareExpectations($state);
} }
function testMarkAStaleEditionStarred() { function testMarkAStaleEditionStarred() {
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->edition(20)); Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->edition(20));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
@ -632,8 +633,8 @@ trait SeriesArticle {
} }
function testMarkAStaleEditionUnreadAndStarred() { function testMarkAStaleEditionUnreadAndStarred() {
Data::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->edition(20)); // only starred is changed Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->edition(20)); // only starred is changed
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
@ -641,19 +642,19 @@ trait SeriesArticle {
} }
function testMarkAStaleEditionUnreadAndUnstarred() { function testMarkAStaleEditionUnreadAndUnstarred() {
Data::$db->articleMark($this->user, ['read'=>false,'starred'=>false], (new Context)->edition(20)); // no changes occur Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>false], (new Context)->edition(20)); // no changes occur
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$this->compareExpectations($state); $this->compareExpectations($state);
} }
function testMarkAMissingEdition() { function testMarkAMissingEdition() {
$this->assertException("subjectMissing", "Db", "ExceptionInput"); $this->assertException("subjectMissing", "Db", "ExceptionInput");
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->edition(2)); Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->edition(2));
} }
function testMarkByOldestEdition() { function testMarkByOldestEdition() {
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->oldestEdition(19)); Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->oldestEdition(19));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][8][3] = 1; $state['arsse_marks']['rows'][8][3] = 1;
$state['arsse_marks']['rows'][8][4] = $now; $state['arsse_marks']['rows'][8][4] = $now;
@ -663,8 +664,8 @@ trait SeriesArticle {
} }
function testMarkByLatestEdition() { function testMarkByLatestEdition() {
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->latestEdition(20)); Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->latestEdition(20));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][8][3] = 1; $state['arsse_marks']['rows'][8][3] = 1;
$state['arsse_marks']['rows'][8][4] = $now; $state['arsse_marks']['rows'][8][4] = $now;
@ -676,8 +677,8 @@ trait SeriesArticle {
} }
function testMarkByLastModified() { function testMarkByLastModified() {
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->modifiedSince('2017-01-01T00:00:00Z')); Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->modifiedSince('2017-01-01T00:00:00Z'));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][8][3] = 1; $state['arsse_marks']['rows'][8][3] = 1;
$state['arsse_marks']['rows'][8][4] = $now; $state['arsse_marks']['rows'][8][4] = $now;
@ -687,8 +688,8 @@ trait SeriesArticle {
} }
function testMarkByNotLastModified() { function testMarkByNotLastModified() {
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->notModifiedSince('2000-01-01T00:00:00Z')); Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->notModifiedSince('2000-01-01T00:00:00Z'));
$now = $this->dateTransform(time(), "sql"); $now = Date::transform(time(), "sql");
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][] = [$this->user,5,0,1,$now]; $state['arsse_marks']['rows'][] = [$this->user,5,0,1,$now];
$state['arsse_marks']['rows'][] = [$this->user,7,0,1,$now]; $state['arsse_marks']['rows'][] = [$this->user,7,0,1,$now];
@ -696,37 +697,37 @@ trait SeriesArticle {
} }
function testMarkArticlesWithoutAuthority() { function testMarkArticlesWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->articleMark($this->user, ['read'=>false]); Arsse::$db->articleMark($this->user, ['read'=>false]);
} }
function testCountStarredArticles() { function testCountStarredArticles() {
$this->assertSame(2, Data::$db->articleStarredCount("john.doe@example.com")); $this->assertSame(2, Arsse::$db->articleStarredCount("john.doe@example.com"));
$this->assertSame(2, Data::$db->articleStarredCount("john.doe@example.org")); $this->assertSame(2, Arsse::$db->articleStarredCount("john.doe@example.org"));
$this->assertSame(2, Data::$db->articleStarredCount("john.doe@example.net")); $this->assertSame(2, Arsse::$db->articleStarredCount("john.doe@example.net"));
$this->assertSame(0, Data::$db->articleStarredCount("jane.doe@example.com")); $this->assertSame(0, Arsse::$db->articleStarredCount("jane.doe@example.com"));
} }
function testCountStarredArticlesWithoutAuthority() { function testCountStarredArticlesWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->articleStarredCount($this->user); Arsse::$db->articleStarredCount($this->user);
} }
function testFetchLatestEdition() { function testFetchLatestEdition() {
$this->assertSame(1001, Data::$db->editionLatest($this->user)); $this->assertSame(1001, Arsse::$db->editionLatest($this->user));
$this->assertSame(4, Data::$db->editionLatest($this->user, (new Context)->subscription(12))); $this->assertSame(4, Arsse::$db->editionLatest($this->user, (new Context)->subscription(12)));
} }
function testFetchLatestEditionOfMissingSubscription() { function testFetchLatestEditionOfMissingSubscription() {
$this->assertException("idMissing", "Db", "ExceptionInput"); $this->assertException("idMissing", "Db", "ExceptionInput");
Data::$db->editionLatest($this->user, (new Context)->subscription(1)); Arsse::$db->editionLatest($this->user, (new Context)->subscription(1));
} }
function testFetchLatestEditionWithoutAuthority() { function testFetchLatestEditionWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->editionLatest($this->user); Arsse::$db->editionLatest($this->user);
} }
} }

View file

@ -1,7 +1,7 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Test\Database; namespace JKingWeb\Arsse\Test\Database;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\Feed; use JKingWeb\Arsse\Feed;
use JKingWeb\Arsse\Test\Database; use JKingWeb\Arsse\Test\Database;
use JKingWeb\Arsse\User\Driver as UserDriver; use JKingWeb\Arsse\User\Driver as UserDriver;
@ -142,23 +142,23 @@ trait SeriesFeed {
} }
function testListLatestItems() { function testListLatestItems() {
$this->assertResult($this->matches, Data::$db->feedMatchLatest(1,2)); $this->assertResult($this->matches, Arsse::$db->feedMatchLatest(1,2));
} }
function testMatchItemsById() { function testMatchItemsById() {
$this->assertResult($this->matches, Data::$db->feedMatchIds(1, ['804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180','db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41'])); $this->assertResult($this->matches, Arsse::$db->feedMatchIds(1, ['804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180','db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41']));
foreach($this->matches as $m) { foreach($this->matches as $m) {
$exp = [$m]; $exp = [$m];
$this->assertResult($exp, Data::$db->feedMatchIds(1, [], [$m['url_title_hash']])); $this->assertResult($exp, Arsse::$db->feedMatchIds(1, [], [$m['url_title_hash']]));
$this->assertResult($exp, Data::$db->feedMatchIds(1, [], [], [$m['url_content_hash']])); $this->assertResult($exp, Arsse::$db->feedMatchIds(1, [], [], [$m['url_content_hash']]));
$this->assertResult($exp, Data::$db->feedMatchIds(1, [], [], [], [$m['title_content_hash']])); $this->assertResult($exp, Arsse::$db->feedMatchIds(1, [], [], [], [$m['title_content_hash']]));
} }
$this->assertResult([['id' => 1]], Data::$db->feedMatchIds(1, ['e433653cef2e572eee4215fa299a4a5af9137b2cefd6283c85bd69a32915beda'])); // this ID appears in both feed 1 and feed 2; only one result should be returned $this->assertResult([['id' => 1]], Arsse::$db->feedMatchIds(1, ['e433653cef2e572eee4215fa299a4a5af9137b2cefd6283c85bd69a32915beda'])); // this ID appears in both feed 1 and feed 2; only one result should be returned
} }
function testUpdateAFeed() { function testUpdateAFeed() {
// update a valid feed with both new and changed items // update a valid feed with both new and changed items
Data::$db->feedUpdate(1); Arsse::$db->feedUpdate(1);
$now = gmdate("Y-m-d H:i:s"); $now = gmdate("Y-m-d H:i:s");
$state = $this->primeExpectations($this->data, [ $state = $this->primeExpectations($this->data, [
'arsse_articles' => ["id", "feed","url","title","author","published","edited","content","guid","url_title_hash","url_content_hash","title_content_hash","modified"], 'arsse_articles' => ["id", "feed","url","title","author","published","edited","content","guid","url_title_hash","url_content_hash","title_content_hash","modified"],
@ -178,9 +178,9 @@ trait SeriesFeed {
$state['arsse_marks']['rows'][6] = [10,3,0,0,$now]; $state['arsse_marks']['rows'][6] = [10,3,0,0,$now];
$this->compareExpectations($state); $this->compareExpectations($state);
// update a valid feed which previously had an error // update a valid feed which previously had an error
Data::$db->feedUpdate(2); Arsse::$db->feedUpdate(2);
// update an erroneous feed which previously had no errors // update an erroneous feed which previously had no errors
Data::$db->feedUpdate(3); Arsse::$db->feedUpdate(3);
$state = $this->primeExpectations($this->data, [ $state = $this->primeExpectations($this->data, [
'arsse_feeds' => ["id","err_count","err_msg"], 'arsse_feeds' => ["id","err_count","err_msg"],
]); ]);
@ -188,19 +188,19 @@ trait SeriesFeed {
$state['arsse_feeds']['rows'][2] = [3,1,'Feed URL "http://localhost:8000/Feed/Fetching/Error?code=404" is invalid']; $state['arsse_feeds']['rows'][2] = [3,1,'Feed URL "http://localhost:8000/Feed/Fetching/Error?code=404" is invalid'];
$this->compareExpectations($state); $this->compareExpectations($state);
// update the bad feed again, twice // update the bad feed again, twice
Data::$db->feedUpdate(3); Arsse::$db->feedUpdate(3);
Data::$db->feedUpdate(3); Arsse::$db->feedUpdate(3);
$state['arsse_feeds']['rows'][2] = [3,3,'Feed URL "http://localhost:8000/Feed/Fetching/Error?code=404" is invalid']; $state['arsse_feeds']['rows'][2] = [3,3,'Feed URL "http://localhost:8000/Feed/Fetching/Error?code=404" is invalid'];
$this->compareExpectations($state); $this->compareExpectations($state);
} }
function testUpdateAFeedThrowingExceptions() { function testUpdateAFeedThrowingExceptions() {
$this->assertException("invalidUrl", "Feed"); $this->assertException("invalidUrl", "Feed");
Data::$db->feedUpdate(3, true); Arsse::$db->feedUpdate(3, true);
} }
function testUpdateAFeedWithEnclosuresAndCategories() { function testUpdateAFeedWithEnclosuresAndCategories() {
Data::$db->feedUpdate(5); Arsse::$db->feedUpdate(5);
$state = $this->primeExpectations($this->data, [ $state = $this->primeExpectations($this->data, [
'arsse_enclosures' => ["url","type"], 'arsse_enclosures' => ["url","type"],
'arsse_categories' => ["name"], 'arsse_categories' => ["name"],
@ -216,9 +216,9 @@ trait SeriesFeed {
} }
function testListStaleFeeds() { function testListStaleFeeds() {
$this->assertSame([1,3,4], Data::$db->feedListStale()); $this->assertSame([1,3,4], Arsse::$db->feedListStale());
Data::$db->feedUpdate(3); Arsse::$db->feedUpdate(3);
Data::$db->feedUpdate(4); Arsse::$db->feedUpdate(4);
$this->assertSame([1], Data::$db->feedListStale()); $this->assertSame([1], Arsse::$db->feedListStale());
} }
} }

View file

@ -1,7 +1,7 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Test\Database; namespace JKingWeb\Arsse\Test\Database;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\User\Driver as UserDriver; use JKingWeb\Arsse\User\Driver as UserDriver;
use Phake; use Phake;
@ -50,8 +50,8 @@ trait SeriesFolder {
function testAddARootFolder() { function testAddARootFolder() {
$user = "john.doe@example.com"; $user = "john.doe@example.com";
$folderID = $this->nextID("arsse_folders"); $folderID = $this->nextID("arsse_folders");
$this->assertSame($folderID, Data::$db->folderAdd($user, ['name' => "Entertainment"])); $this->assertSame($folderID, Arsse::$db->folderAdd($user, ['name' => "Entertainment"]));
Phake::verify(Data::$user)->authorize($user, "folderAdd"); Phake::verify(Arsse::$user)->authorize($user, "folderAdd");
$state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]); $state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]);
$state['arsse_folders']['rows'][] = [$folderID, $user, null, "Entertainment"]; $state['arsse_folders']['rows'][] = [$folderID, $user, null, "Entertainment"];
$this->compareExpectations($state); $this->compareExpectations($state);
@ -59,14 +59,14 @@ trait SeriesFolder {
function testAddADuplicateRootFolder() { function testAddADuplicateRootFolder() {
$this->assertException("constraintViolation", "Db", "ExceptionInput"); $this->assertException("constraintViolation", "Db", "ExceptionInput");
Data::$db->folderAdd("john.doe@example.com", ['name' => "Politics"]); Arsse::$db->folderAdd("john.doe@example.com", ['name' => "Politics"]);
} }
function testAddANestedFolder() { function testAddANestedFolder() {
$user = "john.doe@example.com"; $user = "john.doe@example.com";
$folderID = $this->nextID("arsse_folders"); $folderID = $this->nextID("arsse_folders");
$this->assertSame($folderID, Data::$db->folderAdd($user, ['name' => "GNOME", 'parent' => 2])); $this->assertSame($folderID, Arsse::$db->folderAdd($user, ['name' => "GNOME", 'parent' => 2]));
Phake::verify(Data::$user)->authorize($user, "folderAdd"); Phake::verify(Arsse::$user)->authorize($user, "folderAdd");
$state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]); $state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]);
$state['arsse_folders']['rows'][] = [$folderID, $user, 2, "GNOME"]; $state['arsse_folders']['rows'][] = [$folderID, $user, 2, "GNOME"];
$this->compareExpectations($state); $this->compareExpectations($state);
@ -74,33 +74,33 @@ trait SeriesFolder {
function testAddANestedFolderToAMissingParent() { function testAddANestedFolderToAMissingParent() {
$this->assertException("idMissing", "Db", "ExceptionInput"); $this->assertException("idMissing", "Db", "ExceptionInput");
Data::$db->folderAdd("john.doe@example.com", ['name' => "Sociology", 'parent' => 2112]); Arsse::$db->folderAdd("john.doe@example.com", ['name' => "Sociology", 'parent' => 2112]);
} }
function testAddANestedFolderForTheWrongOwner() { function testAddANestedFolderForTheWrongOwner() {
$this->assertException("idMissing", "Db", "ExceptionInput"); $this->assertException("idMissing", "Db", "ExceptionInput");
Data::$db->folderAdd("john.doe@example.com", ['name' => "Sociology", 'parent' => 4]); // folder ID 4 belongs to Jane Arsse::$db->folderAdd("john.doe@example.com", ['name' => "Sociology", 'parent' => 4]); // folder ID 4 belongs to Jane
} }
function testAddAFolderWithAMissingName() { function testAddAFolderWithAMissingName() {
$this->assertException("missing", "Db", "ExceptionInput"); $this->assertException("missing", "Db", "ExceptionInput");
Data::$db->folderAdd("john.doe@example.com", []); Arsse::$db->folderAdd("john.doe@example.com", []);
} }
function testAddAFolderWithABlankName() { function testAddAFolderWithABlankName() {
$this->assertException("missing", "Db", "ExceptionInput"); $this->assertException("missing", "Db", "ExceptionInput");
Data::$db->folderAdd("john.doe@example.com", ['name' => ""]); Arsse::$db->folderAdd("john.doe@example.com", ['name' => ""]);
} }
function testAddAFolderWithAWhitespaceName() { function testAddAFolderWithAWhitespaceName() {
$this->assertException("whitespace", "Db", "ExceptionInput"); $this->assertException("whitespace", "Db", "ExceptionInput");
Data::$db->folderAdd("john.doe@example.com", ['name' => " "]); Arsse::$db->folderAdd("john.doe@example.com", ['name' => " "]);
} }
function testAddAFolderWithoutAuthority() { function testAddAFolderWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->folderAdd("john.doe@example.com", ['name' => "Sociology"]); Arsse::$db->folderAdd("john.doe@example.com", ['name' => "Sociology"]);
} }
function testListRootFolders() { function testListRootFolders() {
@ -108,16 +108,16 @@ trait SeriesFolder {
['id' => 5, 'name' => "Politics", 'parent' => null], ['id' => 5, 'name' => "Politics", 'parent' => null],
['id' => 1, 'name' => "Technology", 'parent' => null], ['id' => 1, 'name' => "Technology", 'parent' => null],
]; ];
$this->assertSame($exp, Data::$db->folderList("john.doe@example.com", null, false)->getAll()); $this->assertSame($exp, Arsse::$db->folderList("john.doe@example.com", null, false)->getAll());
$exp = [ $exp = [
['id' => 4, 'name' => "Politics", 'parent' => null], ['id' => 4, 'name' => "Politics", 'parent' => null],
]; ];
$this->assertSame($exp, Data::$db->folderList("jane.doe@example.com", null, false)->getAll()); $this->assertSame($exp, Arsse::$db->folderList("jane.doe@example.com", null, false)->getAll());
$exp = []; $exp = [];
$this->assertSame($exp, Data::$db->folderList("admin@example.net", null, false)->getAll()); $this->assertSame($exp, Arsse::$db->folderList("admin@example.net", null, false)->getAll());
Phake::verify(Data::$user)->authorize("john.doe@example.com", "folderList"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "folderList");
Phake::verify(Data::$user)->authorize("jane.doe@example.com", "folderList"); Phake::verify(Arsse::$user)->authorize("jane.doe@example.com", "folderList");
Phake::verify(Data::$user)->authorize("admin@example.net", "folderList"); Phake::verify(Arsse::$user)->authorize("admin@example.net", "folderList");
} }
function testListFoldersRecursively() { function testListFoldersRecursively() {
@ -128,46 +128,46 @@ trait SeriesFolder {
['id' => 2, 'name' => "Software", 'parent' => 1], ['id' => 2, 'name' => "Software", 'parent' => 1],
['id' => 1, 'name' => "Technology", 'parent' => null], ['id' => 1, 'name' => "Technology", 'parent' => null],
]; ];
$this->assertSame($exp, Data::$db->folderList("john.doe@example.com", null, true)->getAll()); $this->assertSame($exp, Arsse::$db->folderList("john.doe@example.com", null, true)->getAll());
$exp = [ $exp = [
['id' => 6, 'name' => "Politics", 'parent' => 2], ['id' => 6, 'name' => "Politics", 'parent' => 2],
['id' => 3, 'name' => "Rocketry", 'parent' => 1], ['id' => 3, 'name' => "Rocketry", 'parent' => 1],
['id' => 2, 'name' => "Software", 'parent' => 1], ['id' => 2, 'name' => "Software", 'parent' => 1],
]; ];
$this->assertSame($exp, Data::$db->folderList("john.doe@example.com", 1, true)->getAll()); $this->assertSame($exp, Arsse::$db->folderList("john.doe@example.com", 1, true)->getAll());
$exp = []; $exp = [];
$this->assertSame($exp, Data::$db->folderList("jane.doe@example.com", 4, true)->getAll()); $this->assertSame($exp, Arsse::$db->folderList("jane.doe@example.com", 4, true)->getAll());
Phake::verify(Data::$user, Phake::times(2))->authorize("john.doe@example.com", "folderList"); Phake::verify(Arsse::$user, Phake::times(2))->authorize("john.doe@example.com", "folderList");
Phake::verify(Data::$user)->authorize("jane.doe@example.com", "folderList"); Phake::verify(Arsse::$user)->authorize("jane.doe@example.com", "folderList");
} }
function testListFoldersOfAMissingParent() { function testListFoldersOfAMissingParent() {
$this->assertException("idMissing", "Db", "ExceptionInput"); $this->assertException("idMissing", "Db", "ExceptionInput");
Data::$db->folderList("john.doe@example.com", 2112); Arsse::$db->folderList("john.doe@example.com", 2112);
} }
function testListFoldersOfTheWrongOwner() { function testListFoldersOfTheWrongOwner() {
$this->assertException("idMissing", "Db", "ExceptionInput"); $this->assertException("idMissing", "Db", "ExceptionInput");
Data::$db->folderList("john.doe@example.com", 4); // folder ID 4 belongs to Jane Arsse::$db->folderList("john.doe@example.com", 4); // folder ID 4 belongs to Jane
} }
function testListFoldersWithoutAuthority() { function testListFoldersWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->folderList("john.doe@example.com"); Arsse::$db->folderList("john.doe@example.com");
} }
function testRemoveAFolder() { function testRemoveAFolder() {
$this->assertTrue(Data::$db->folderRemove("john.doe@example.com", 6)); $this->assertTrue(Arsse::$db->folderRemove("john.doe@example.com", 6));
Phake::verify(Data::$user)->authorize("john.doe@example.com", "folderRemove"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "folderRemove");
$state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]); $state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]);
array_pop($state['arsse_folders']['rows']); array_pop($state['arsse_folders']['rows']);
$this->compareExpectations($state); $this->compareExpectations($state);
} }
function testRemoveAFolderTree() { function testRemoveAFolderTree() {
$this->assertTrue(Data::$db->folderRemove("john.doe@example.com", 1)); $this->assertTrue(Arsse::$db->folderRemove("john.doe@example.com", 1));
Phake::verify(Data::$user)->authorize("john.doe@example.com", "folderRemove"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "folderRemove");
$state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]); $state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]);
foreach([0,1,2,5] as $index) { foreach([0,1,2,5] as $index) {
unset($state['arsse_folders']['rows'][$index]); unset($state['arsse_folders']['rows'][$index]);
@ -177,18 +177,18 @@ trait SeriesFolder {
function testRemoveAMissingFolder() { function testRemoveAMissingFolder() {
$this->assertException("subjectMissing", "Db", "ExceptionInput"); $this->assertException("subjectMissing", "Db", "ExceptionInput");
Data::$db->folderRemove("john.doe@example.com", 2112); Arsse::$db->folderRemove("john.doe@example.com", 2112);
} }
function testRemoveAFolderOfTheWrongOwner() { function testRemoveAFolderOfTheWrongOwner() {
$this->assertException("subjectMissing", "Db", "ExceptionInput"); $this->assertException("subjectMissing", "Db", "ExceptionInput");
Data::$db->folderRemove("john.doe@example.com", 4); // folder ID 4 belongs to Jane Arsse::$db->folderRemove("john.doe@example.com", 4); // folder ID 4 belongs to Jane
} }
function testRemoveAFolderWithoutAuthority() { function testRemoveAFolderWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->folderRemove("john.doe@example.com", 1); Arsse::$db->folderRemove("john.doe@example.com", 1);
} }
function testGetThePropertiesOfAFolder() { function testGetThePropertiesOfAFolder() {
@ -197,37 +197,37 @@ trait SeriesFolder {
'name' => "Politics", 'name' => "Politics",
'parent' => 2, 'parent' => 2,
]; ];
$this->assertArraySubset($exp, Data::$db->folderPropertiesGet("john.doe@example.com", 6)); $this->assertArraySubset($exp, Arsse::$db->folderPropertiesGet("john.doe@example.com", 6));
Phake::verify(Data::$user)->authorize("john.doe@example.com", "folderPropertiesGet"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "folderPropertiesGet");
} }
function testGetThePropertiesOfAMissingFolder() { function testGetThePropertiesOfAMissingFolder() {
$this->assertException("subjectMissing", "Db", "ExceptionInput"); $this->assertException("subjectMissing", "Db", "ExceptionInput");
Data::$db->folderPropertiesGet("john.doe@example.com", 2112); Arsse::$db->folderPropertiesGet("john.doe@example.com", 2112);
} }
function testGetThePropertiesOfAFolderOfTheWrongOwner() { function testGetThePropertiesOfAFolderOfTheWrongOwner() {
$this->assertException("subjectMissing", "Db", "ExceptionInput"); $this->assertException("subjectMissing", "Db", "ExceptionInput");
Data::$db->folderPropertiesGet("john.doe@example.com", 4); // folder ID 4 belongs to Jane Arsse::$db->folderPropertiesGet("john.doe@example.com", 4); // folder ID 4 belongs to Jane
} }
function testGetThePropertiesOfAFolderWithoutAuthority() { function testGetThePropertiesOfAFolderWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->folderPropertiesGet("john.doe@example.com", 1); Arsse::$db->folderPropertiesGet("john.doe@example.com", 1);
} }
function testRenameAFolder() { function testRenameAFolder() {
$this->assertTrue(Data::$db->folderPropertiesSet("john.doe@example.com", 6, ['name' => "Opinion"])); $this->assertTrue(Arsse::$db->folderPropertiesSet("john.doe@example.com", 6, ['name' => "Opinion"]));
Phake::verify(Data::$user)->authorize("john.doe@example.com", "folderPropertiesSet"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "folderPropertiesSet");
$state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]); $state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]);
$state['arsse_folders']['rows'][5][3] = "Opinion"; $state['arsse_folders']['rows'][5][3] = "Opinion";
$this->compareExpectations($state); $this->compareExpectations($state);
} }
function testMoveAFolder() { function testMoveAFolder() {
$this->assertTrue(Data::$db->folderPropertiesSet("john.doe@example.com", 6, ['parent' => 5])); $this->assertTrue(Arsse::$db->folderPropertiesSet("john.doe@example.com", 6, ['parent' => 5]));
Phake::verify(Data::$user)->authorize("john.doe@example.com", "folderPropertiesSet"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "folderPropertiesSet");
$state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]); $state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]);
$state['arsse_folders']['rows'][5][2] = 5; // parent should have changed $state['arsse_folders']['rows'][5][2] = 5; // parent should have changed
$this->compareExpectations($state); $this->compareExpectations($state);
@ -235,37 +235,37 @@ trait SeriesFolder {
function testMoveAFolderToItsDescendant() { function testMoveAFolderToItsDescendant() {
$this->assertException("circularDependence", "Db", "ExceptionInput"); $this->assertException("circularDependence", "Db", "ExceptionInput");
Data::$db->folderPropertiesSet("john.doe@example.com", 1, ['parent' => 3]); Arsse::$db->folderPropertiesSet("john.doe@example.com", 1, ['parent' => 3]);
} }
function testMoveAFolderToItself() { function testMoveAFolderToItself() {
$this->assertException("circularDependence", "Db", "ExceptionInput"); $this->assertException("circularDependence", "Db", "ExceptionInput");
Data::$db->folderPropertiesSet("john.doe@example.com", 1, ['parent' => 1]); Arsse::$db->folderPropertiesSet("john.doe@example.com", 1, ['parent' => 1]);
} }
function testMoveAFolderToAMissingParent() { function testMoveAFolderToAMissingParent() {
$this->assertException("idMissing", "Db", "ExceptionInput"); $this->assertException("idMissing", "Db", "ExceptionInput");
Data::$db->folderPropertiesSet("john.doe@example.com", 1, ['parent' => 2112]); Arsse::$db->folderPropertiesSet("john.doe@example.com", 1, ['parent' => 2112]);
} }
function testCauseAFolderCollision() { function testCauseAFolderCollision() {
$this->assertException("constraintViolation", "Db", "ExceptionInput"); $this->assertException("constraintViolation", "Db", "ExceptionInput");
Data::$db->folderPropertiesSet("john.doe@example.com", 6, ['parent' => null]); Arsse::$db->folderPropertiesSet("john.doe@example.com", 6, ['parent' => null]);
} }
function testSetThePropertiesOfAMissingFolder() { function testSetThePropertiesOfAMissingFolder() {
$this->assertException("subjectMissing", "Db", "ExceptionInput"); $this->assertException("subjectMissing", "Db", "ExceptionInput");
Data::$db->folderPropertiesSet("john.doe@example.com", 2112, ['parent' => null]); Arsse::$db->folderPropertiesSet("john.doe@example.com", 2112, ['parent' => null]);
} }
function testSetThePropertiesOfAFolderForTheWrongOwner() { function testSetThePropertiesOfAFolderForTheWrongOwner() {
$this->assertException("subjectMissing", "Db", "ExceptionInput"); $this->assertException("subjectMissing", "Db", "ExceptionInput");
Data::$db->folderPropertiesSet("john.doe@example.com", 4, ['parent' => null]); // folder ID 4 belongs to Jane Arsse::$db->folderPropertiesSet("john.doe@example.com", 4, ['parent' => null]); // folder ID 4 belongs to Jane
} }
function testSetThePropertiesOfAFolderWithoutAuthority() { function testSetThePropertiesOfAFolderWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->folderPropertiesSet("john.doe@example.com", 1, ['parent' => null]); Arsse::$db->folderPropertiesSet("john.doe@example.com", 1, ['parent' => null]);
} }
} }

View file

@ -1,7 +1,7 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Test\Database; namespace JKingWeb\Arsse\Test\Database;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\Test\Database; use JKingWeb\Arsse\Test\Database;
use JKingWeb\Arsse\User\Driver as UserDriver; use JKingWeb\Arsse\User\Driver as UserDriver;
use JKingWeb\Arsse\Feed\Exception as FeedException; use JKingWeb\Arsse\Feed\Exception as FeedException;
@ -114,17 +114,17 @@ trait SeriesSubscription {
[3,"http://example.com/feed3", "Ack", "", "",strtotime("now + 1 hour")], [3,"http://example.com/feed3", "Ack", "", "",strtotime("now + 1 hour")],
]; ];
// initialize a partial mock of the Database object to later manipulate the feedUpdate method // initialize a partial mock of the Database object to later manipulate the feedUpdate method
Data::$db = Phake::PartialMock(Database::class, $this->drv); Arsse::$db = Phake::PartialMock(Database::class, $this->drv);
$this->user = "john.doe@example.com"; $this->user = "john.doe@example.com";
} }
function testAddASubscriptionToAnExistingFeed() { function testAddASubscriptionToAnExistingFeed() {
$url = "http://example.com/feed1"; $url = "http://example.com/feed1";
$subID = $this->nextID("arsse_subscriptions"); $subID = $this->nextID("arsse_subscriptions");
Phake::when(Data::$db)->feedUpdate->thenReturn(true); Phake::when(Arsse::$db)->feedUpdate->thenReturn(true);
$this->assertSame($subID,Data::$db->subscriptionAdd($this->user, $url)); $this->assertSame($subID,Arsse::$db->subscriptionAdd($this->user, $url));
Phake::verify(Data::$user)->authorize($this->user, "subscriptionAdd"); Phake::verify(Arsse::$user)->authorize($this->user, "subscriptionAdd");
Phake::verify(Data::$db, Phake::times(0))->feedUpdate(1, true); Phake::verify(Arsse::$db, Phake::times(0))->feedUpdate(1, true);
$state = $this->primeExpectations($this->data, [ $state = $this->primeExpectations($this->data, [
'arsse_feeds' => ['id','url','username','password'], 'arsse_feeds' => ['id','url','username','password'],
'arsse_subscriptions' => ['id','owner','feed'], 'arsse_subscriptions' => ['id','owner','feed'],
@ -137,10 +137,10 @@ trait SeriesSubscription {
$url = "http://example.org/feed1"; $url = "http://example.org/feed1";
$feedID = $this->nextID("arsse_feeds"); $feedID = $this->nextID("arsse_feeds");
$subID = $this->nextID("arsse_subscriptions"); $subID = $this->nextID("arsse_subscriptions");
Phake::when(Data::$db)->feedUpdate->thenReturn(true); Phake::when(Arsse::$db)->feedUpdate->thenReturn(true);
$this->assertSame($subID,Data::$db->subscriptionAdd($this->user, $url)); $this->assertSame($subID,Arsse::$db->subscriptionAdd($this->user, $url));
Phake::verify(Data::$user)->authorize($this->user, "subscriptionAdd"); Phake::verify(Arsse::$user)->authorize($this->user, "subscriptionAdd");
Phake::verify(Data::$db)->feedUpdate($feedID, true); Phake::verify(Arsse::$db)->feedUpdate($feedID, true);
$state = $this->primeExpectations($this->data, [ $state = $this->primeExpectations($this->data, [
'arsse_feeds' => ['id','url','username','password'], 'arsse_feeds' => ['id','url','username','password'],
'arsse_subscriptions' => ['id','owner','feed'], 'arsse_subscriptions' => ['id','owner','feed'],
@ -153,12 +153,12 @@ trait SeriesSubscription {
function testAddASubscriptionToAnInvalidFeed() { function testAddASubscriptionToAnInvalidFeed() {
$url = "http://example.org/feed1"; $url = "http://example.org/feed1";
$feedID = $this->nextID("arsse_feeds"); $feedID = $this->nextID("arsse_feeds");
Phake::when(Data::$db)->feedUpdate->thenThrow(new FeedException($url, new \PicoFeed\Client\InvalidUrlException())); Phake::when(Arsse::$db)->feedUpdate->thenThrow(new FeedException($url, new \PicoFeed\Client\InvalidUrlException()));
try { try {
Data::$db->subscriptionAdd($this->user, $url); Arsse::$db->subscriptionAdd($this->user, $url);
} catch(FeedException $e) { } catch(FeedException $e) {
Phake::verify(Data::$user)->authorize($this->user, "subscriptionAdd"); Phake::verify(Arsse::$user)->authorize($this->user, "subscriptionAdd");
Phake::verify(Data::$db)->feedUpdate($feedID, true); Phake::verify(Arsse::$db)->feedUpdate($feedID, true);
$state = $this->primeExpectations($this->data, [ $state = $this->primeExpectations($this->data, [
'arsse_feeds' => ['id','url','username','password'], 'arsse_feeds' => ['id','url','username','password'],
'arsse_subscriptions' => ['id','owner','feed'], 'arsse_subscriptions' => ['id','owner','feed'],
@ -172,19 +172,19 @@ trait SeriesSubscription {
function testAddADuplicateSubscription() { function testAddADuplicateSubscription() {
$url = "http://example.com/feed2"; $url = "http://example.com/feed2";
$this->assertException("constraintViolation", "Db", "ExceptionInput"); $this->assertException("constraintViolation", "Db", "ExceptionInput");
Data::$db->subscriptionAdd($this->user, $url); Arsse::$db->subscriptionAdd($this->user, $url);
} }
function testAddASubscriptionWithoutAuthority() { function testAddASubscriptionWithoutAuthority() {
$url = "http://example.com/feed1"; $url = "http://example.com/feed1";
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->subscriptionAdd($this->user, $url); Arsse::$db->subscriptionAdd($this->user, $url);
} }
function testRemoveASubscription() { function testRemoveASubscription() {
$this->assertTrue(Data::$db->subscriptionRemove($this->user, 1)); $this->assertTrue(Arsse::$db->subscriptionRemove($this->user, 1));
Phake::verify(Data::$user)->authorize($this->user, "subscriptionRemove"); Phake::verify(Arsse::$user)->authorize($this->user, "subscriptionRemove");
$state = $this->primeExpectations($this->data, [ $state = $this->primeExpectations($this->data, [
'arsse_feeds' => ['id','url','username','password'], 'arsse_feeds' => ['id','url','username','password'],
'arsse_subscriptions' => ['id','owner','feed'], 'arsse_subscriptions' => ['id','owner','feed'],
@ -195,19 +195,19 @@ trait SeriesSubscription {
function testRemoveAMissingSubscription() { function testRemoveAMissingSubscription() {
$this->assertException("subjectMissing", "Db", "ExceptionInput"); $this->assertException("subjectMissing", "Db", "ExceptionInput");
Data::$db->subscriptionRemove($this->user, 2112); Arsse::$db->subscriptionRemove($this->user, 2112);
} }
function testRemoveASubscriptionForTheWrongOwner() { function testRemoveASubscriptionForTheWrongOwner() {
$this->user = "jane.doe@example.com"; $this->user = "jane.doe@example.com";
$this->assertException("subjectMissing", "Db", "ExceptionInput"); $this->assertException("subjectMissing", "Db", "ExceptionInput");
Data::$db->subscriptionRemove($this->user, 1); Arsse::$db->subscriptionRemove($this->user, 1);
} }
function testRemoveASubscriptionWithoutAuthority() { function testRemoveASubscriptionWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->subscriptionRemove($this->user, 1); Arsse::$db->subscriptionRemove($this->user, 1);
} }
function testListSubscriptions() { function testListSubscriptions() {
@ -231,11 +231,11 @@ trait SeriesSubscription {
'order_type' => 1, 'order_type' => 1,
], ],
]; ];
$this->assertResult($exp, Data::$db->subscriptionList($this->user)); $this->assertResult($exp, Arsse::$db->subscriptionList($this->user));
Phake::verify(Data::$user)->authorize($this->user, "subscriptionList"); Phake::verify(Arsse::$user)->authorize($this->user, "subscriptionList");
$this->assertArraySubset($exp[0], Data::$db->subscriptionPropertiesGet($this->user, 1)); $this->assertArraySubset($exp[0], Arsse::$db->subscriptionPropertiesGet($this->user, 1));
Phake::verify(Data::$user)->authorize($this->user, "subscriptionPropertiesGet"); Phake::verify(Arsse::$user)->authorize($this->user, "subscriptionPropertiesGet");
$this->assertArraySubset($exp[1], Data::$db->subscriptionPropertiesGet($this->user, 3)); $this->assertArraySubset($exp[1], Arsse::$db->subscriptionPropertiesGet($this->user, 3));
} }
function testListSubscriptionsInAFolder() { function testListSubscriptionsInAFolder() {
@ -250,35 +250,35 @@ trait SeriesSubscription {
'order_type' => 1, 'order_type' => 1,
], ],
]; ];
$this->assertResult($exp, Data::$db->subscriptionList($this->user, 2)); $this->assertResult($exp, Arsse::$db->subscriptionList($this->user, 2));
} }
function testListSubscriptionsInAMissingFolder() { function testListSubscriptionsInAMissingFolder() {
$this->assertException("idMissing", "Db", "ExceptionInput"); $this->assertException("idMissing", "Db", "ExceptionInput");
Data::$db->subscriptionList($this->user, 4); Arsse::$db->subscriptionList($this->user, 4);
} }
function testListSubscriptionsWithoutAuthority() { function testListSubscriptionsWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->subscriptionList($this->user); Arsse::$db->subscriptionList($this->user);
} }
function testSetThePropertiesOfASubscription() { function testSetThePropertiesOfASubscription() {
Data::$db->subscriptionPropertiesSet($this->user, 1,[ Arsse::$db->subscriptionPropertiesSet($this->user, 1,[
'title' => "Ook Ook", 'title' => "Ook Ook",
'folder' => 3, 'folder' => 3,
'pinned' => false, 'pinned' => false,
'order_type' => 0, 'order_type' => 0,
]); ]);
Phake::verify(Data::$user)->authorize($this->user, "subscriptionPropertiesSet"); Phake::verify(Arsse::$user)->authorize($this->user, "subscriptionPropertiesSet");
$state = $this->primeExpectations($this->data, [ $state = $this->primeExpectations($this->data, [
'arsse_feeds' => ['id','url','username','password','title'], 'arsse_feeds' => ['id','url','username','password','title'],
'arsse_subscriptions' => ['id','owner','feed','title','folder','pinned','order_type'], 'arsse_subscriptions' => ['id','owner','feed','title','folder','pinned','order_type'],
]); ]);
$state['arsse_subscriptions']['rows'][0] = [1,"john.doe@example.com",2,"Ook Ook",3,0,0]; $state['arsse_subscriptions']['rows'][0] = [1,"john.doe@example.com",2,"Ook Ook",3,0,0];
$this->compareExpectations($state); $this->compareExpectations($state);
Data::$db->subscriptionPropertiesSet($this->user, 1,[ Arsse::$db->subscriptionPropertiesSet($this->user, 1,[
'title' => null, 'title' => null,
]); ]);
$state['arsse_subscriptions']['rows'][0] = [1,"john.doe@example.com",2,null,3,0,0]; $state['arsse_subscriptions']['rows'][0] = [1,"john.doe@example.com",2,null,3,0,0];
@ -287,36 +287,36 @@ trait SeriesSubscription {
function testMoveASubscriptionToAMissingFolder() { function testMoveASubscriptionToAMissingFolder() {
$this->assertException("idMissing", "Db", "ExceptionInput"); $this->assertException("idMissing", "Db", "ExceptionInput");
Data::$db->subscriptionPropertiesSet($this->user, 1, ['folder' => 4]); Arsse::$db->subscriptionPropertiesSet($this->user, 1, ['folder' => 4]);
} }
function testRenameASubscriptionToABlankTitle() { function testRenameASubscriptionToABlankTitle() {
$this->assertException("missing", "Db", "ExceptionInput"); $this->assertException("missing", "Db", "ExceptionInput");
Data::$db->subscriptionPropertiesSet($this->user, 1, ['title' => ""]); Arsse::$db->subscriptionPropertiesSet($this->user, 1, ['title' => ""]);
} }
function testRenameASubscriptionToAWhitespaceTitle() { function testRenameASubscriptionToAWhitespaceTitle() {
$this->assertException("whitespace", "Db", "ExceptionInput"); $this->assertException("whitespace", "Db", "ExceptionInput");
Data::$db->subscriptionPropertiesSet($this->user, 1, ['title' => " "]); Arsse::$db->subscriptionPropertiesSet($this->user, 1, ['title' => " "]);
} }
function testRenameASubscriptionToFalse() { function testRenameASubscriptionToFalse() {
$this->assertException("missing", "Db", "ExceptionInput"); $this->assertException("missing", "Db", "ExceptionInput");
Data::$db->subscriptionPropertiesSet($this->user, 1, ['title' => false]); Arsse::$db->subscriptionPropertiesSet($this->user, 1, ['title' => false]);
} }
function testRenameASubscriptionToZero() { function testRenameASubscriptionToZero() {
$this->assertTrue(Data::$db->subscriptionPropertiesSet($this->user, 1, ['title' => 0])); $this->assertTrue(Arsse::$db->subscriptionPropertiesSet($this->user, 1, ['title' => 0]));
} }
function testSetThePropertiesOfAMissingSubscription() { function testSetThePropertiesOfAMissingSubscription() {
$this->assertException("subjectMissing", "Db", "ExceptionInput"); $this->assertException("subjectMissing", "Db", "ExceptionInput");
Data::$db->subscriptionPropertiesSet($this->user, 2112, ['folder' => null]); Arsse::$db->subscriptionPropertiesSet($this->user, 2112, ['folder' => null]);
} }
function testSetThePropertiesOfASubscriptionWithoutAuthority() { function testSetThePropertiesOfASubscriptionWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->subscriptionPropertiesSet($this->user, 1, ['folder' => null]); Arsse::$db->subscriptionPropertiesSet($this->user, 1, ['folder' => null]);
} }
} }

View file

@ -1,7 +1,7 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Test\Database; namespace JKingWeb\Arsse\Test\Database;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\User\Driver as UserDriver; use JKingWeb\Arsse\User\Driver as UserDriver;
use Phake; use Phake;
@ -23,35 +23,35 @@ trait SeriesUser {
]; ];
function testCheckThatAUserExists() { function testCheckThatAUserExists() {
$this->assertTrue(Data::$db->userExists("jane.doe@example.com")); $this->assertTrue(Arsse::$db->userExists("jane.doe@example.com"));
$this->assertFalse(Data::$db->userExists("jane.doe@example.org")); $this->assertFalse(Arsse::$db->userExists("jane.doe@example.org"));
Phake::verify(Data::$user)->authorize("jane.doe@example.com", "userExists"); Phake::verify(Arsse::$user)->authorize("jane.doe@example.com", "userExists");
Phake::verify(Data::$user)->authorize("jane.doe@example.org", "userExists"); Phake::verify(Arsse::$user)->authorize("jane.doe@example.org", "userExists");
$this->compareExpectations($this->data); $this->compareExpectations($this->data);
} }
function testCheckThatAUserExistsWithoutAuthority() { function testCheckThatAUserExistsWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->userExists("jane.doe@example.com"); Arsse::$db->userExists("jane.doe@example.com");
} }
function testGetAPassword() { function testGetAPassword() {
$hash = Data::$db->userPasswordGet("admin@example.net"); $hash = Arsse::$db->userPasswordGet("admin@example.net");
$this->assertSame('$2y$10$PbcG2ZR3Z8TuPzM7aHTF8.v61dtCjzjK78gdZJcp4UePE8T9jEgBW', $hash); $this->assertSame('$2y$10$PbcG2ZR3Z8TuPzM7aHTF8.v61dtCjzjK78gdZJcp4UePE8T9jEgBW', $hash);
Phake::verify(Data::$user)->authorize("admin@example.net", "userPasswordGet"); Phake::verify(Arsse::$user)->authorize("admin@example.net", "userPasswordGet");
$this->assertTrue(password_verify("secret", $hash)); $this->assertTrue(password_verify("secret", $hash));
} }
function testGetAPasswordWithoutAuthority() { function testGetAPasswordWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->userPasswordGet("admin@example.net"); Arsse::$db->userPasswordGet("admin@example.net");
} }
function testAddANewUser() { function testAddANewUser() {
$this->assertSame("", Data::$db->userAdd("john.doe@example.org", "")); $this->assertSame("", Arsse::$db->userAdd("john.doe@example.org", ""));
Phake::verify(Data::$user)->authorize("john.doe@example.org", "userAdd"); Phake::verify(Arsse::$user)->authorize("john.doe@example.org", "userAdd");
$state = $this->primeExpectations($this->data, ['arsse_users' => ['id','name','rights']]); $state = $this->primeExpectations($this->data, ['arsse_users' => ['id','name','rights']]);
$state['arsse_users']['rows'][] = ["john.doe@example.org", null, UserDriver::RIGHTS_NONE]; $state['arsse_users']['rows'][] = ["john.doe@example.org", null, UserDriver::RIGHTS_NONE];
$this->compareExpectations($state); $this->compareExpectations($state);
@ -64,35 +64,35 @@ trait SeriesUser {
function testAddANewUserWithARandomPassword() { function testAddANewUserWithARandomPassword() {
$user1 = "john.doe@example.org"; $user1 = "john.doe@example.org";
$user2 = "john.doe@example.net"; $user2 = "john.doe@example.net";
$pass1 = Data::$db->userAdd($user1); $pass1 = Arsse::$db->userAdd($user1);
$pass2 = Data::$db->userAdd($user2); $pass2 = Arsse::$db->userAdd($user2);
$this->assertSame(Data::$conf->userTempPasswordLength, strlen($pass1)); $this->assertSame(Arsse::$conf->userTempPasswordLength, strlen($pass1));
$this->assertSame(Data::$conf->userTempPasswordLength, strlen($pass2)); $this->assertSame(Arsse::$conf->userTempPasswordLength, strlen($pass2));
$this->assertNotEquals($pass1, $pass2); $this->assertNotEquals($pass1, $pass2);
$hash1 = Data::$db->userPasswordGet($user1); $hash1 = Arsse::$db->userPasswordGet($user1);
$hash2 = Data::$db->userPasswordGet($user2); $hash2 = Arsse::$db->userPasswordGet($user2);
Phake::verify(Data::$user)->authorize($user1, "userAdd"); Phake::verify(Arsse::$user)->authorize($user1, "userAdd");
Phake::verify(Data::$user)->authorize($user2, "userAdd"); Phake::verify(Arsse::$user)->authorize($user2, "userAdd");
Phake::verify(Data::$user)->authorize($user1, "userPasswordGet"); Phake::verify(Arsse::$user)->authorize($user1, "userPasswordGet");
Phake::verify(Data::$user)->authorize($user2, "userPasswordGet"); Phake::verify(Arsse::$user)->authorize($user2, "userPasswordGet");
$this->assertTrue(password_verify($pass1, $hash1), "Failed verifying password of $user1 '$pass1' against hash '$hash1'."); $this->assertTrue(password_verify($pass1, $hash1), "Failed verifying password of $user1 '$pass1' against hash '$hash1'.");
$this->assertTrue(password_verify($pass2, $hash2), "Failed verifying password of $user2 '$pass2' against hash '$hash2'."); $this->assertTrue(password_verify($pass2, $hash2), "Failed verifying password of $user2 '$pass2' against hash '$hash2'.");
} }
function testAddAnExistingUser() { function testAddAnExistingUser() {
$this->assertException("alreadyExists", "User"); $this->assertException("alreadyExists", "User");
Data::$db->userAdd("john.doe@example.com", ""); Arsse::$db->userAdd("john.doe@example.com", "");
} }
function testAddANewUserWithoutAuthority() { function testAddANewUserWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->userAdd("john.doe@example.org", ""); Arsse::$db->userAdd("john.doe@example.org", "");
} }
function testRemoveAUser() { function testRemoveAUser() {
$this->assertTrue(Data::$db->userRemove("admin@example.net")); $this->assertTrue(Arsse::$db->userRemove("admin@example.net"));
Phake::verify(Data::$user)->authorize("admin@example.net", "userRemove"); Phake::verify(Arsse::$user)->authorize("admin@example.net", "userRemove");
$state = $this->primeExpectations($this->data, ['arsse_users' => ['id']]); $state = $this->primeExpectations($this->data, ['arsse_users' => ['id']]);
array_shift($state['arsse_users']['rows']); array_shift($state['arsse_users']['rows']);
$this->compareExpectations($state); $this->compareExpectations($state);
@ -100,37 +100,37 @@ trait SeriesUser {
function testRemoveAMissingUser() { function testRemoveAMissingUser() {
$this->assertException("doesNotExist", "User"); $this->assertException("doesNotExist", "User");
Data::$db->userRemove("john.doe@example.org"); Arsse::$db->userRemove("john.doe@example.org");
} }
function testRemoveAUserWithoutAuthority() { function testRemoveAUserWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->userRemove("admin@example.net"); Arsse::$db->userRemove("admin@example.net");
} }
function testListAllUsers() { function testListAllUsers() {
$users = ["admin@example.net", "jane.doe@example.com", "john.doe@example.com"]; $users = ["admin@example.net", "jane.doe@example.com", "john.doe@example.com"];
$this->assertSame($users, Data::$db->userList()); $this->assertSame($users, Arsse::$db->userList());
Phake::verify(Data::$user)->authorize("", "userList"); Phake::verify(Arsse::$user)->authorize("", "userList");
} }
function testListUsersOnADomain() { function testListUsersOnADomain() {
$users = ["jane.doe@example.com", "john.doe@example.com"]; $users = ["jane.doe@example.com", "john.doe@example.com"];
$this->assertSame($users, Data::$db->userList("example.com")); $this->assertSame($users, Arsse::$db->userList("example.com"));
Phake::verify(Data::$user)->authorize("@example.com", "userList"); Phake::verify(Arsse::$user)->authorize("@example.com", "userList");
} }
function testListAllUsersWithoutAuthority() { function testListAllUsersWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->userList(); Arsse::$db->userList();
} }
function testListUsersOnADomainWithoutAuthority() { function testListUsersOnADomainWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->userList("example.com"); Arsse::$db->userList("example.com");
} }
/** /**
@ -138,23 +138,23 @@ trait SeriesUser {
*/ */
function testSetAPassword() { function testSetAPassword() {
$user = "john.doe@example.com"; $user = "john.doe@example.com";
$this->assertEquals("", Data::$db->userPasswordGet($user)); $this->assertEquals("", Arsse::$db->userPasswordGet($user));
$pass = Data::$db->userPasswordSet($user, "secret"); $pass = Arsse::$db->userPasswordSet($user, "secret");
$hash = Data::$db->userPasswordGet($user); $hash = Arsse::$db->userPasswordGet($user);
$this->assertNotEquals("", $hash); $this->assertNotEquals("", $hash);
Phake::verify(Data::$user)->authorize($user, "userPasswordSet"); Phake::verify(Arsse::$user)->authorize($user, "userPasswordSet");
$this->assertTrue(password_verify($pass, $hash), "Failed verifying password of $user '$pass' against hash '$hash'."); $this->assertTrue(password_verify($pass, $hash), "Failed verifying password of $user '$pass' against hash '$hash'.");
} }
function testSetThePasswordOfAMissingUser() { function testSetThePasswordOfAMissingUser() {
$this->assertException("doesNotExist", "User"); $this->assertException("doesNotExist", "User");
Data::$db->userPasswordSet("john.doe@example.org", "secret"); Arsse::$db->userPasswordSet("john.doe@example.org", "secret");
} }
function testSetAPasswordWithoutAuthority() { function testSetAPasswordWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->userPasswordSet("john.doe@example.com", "secret"); Arsse::$db->userPasswordSet("john.doe@example.com", "secret");
} }
function testGetUserProperties() { function testGetUserProperties() {
@ -162,21 +162,21 @@ trait SeriesUser {
'name' => 'Hard Lip Herbert', 'name' => 'Hard Lip Herbert',
'rights' => UserDriver::RIGHTS_GLOBAL_ADMIN, 'rights' => UserDriver::RIGHTS_GLOBAL_ADMIN,
]; ];
$props = Data::$db->userPropertiesGet("admin@example.net"); $props = Arsse::$db->userPropertiesGet("admin@example.net");
Phake::verify(Data::$user)->authorize("admin@example.net", "userPropertiesGet"); Phake::verify(Arsse::$user)->authorize("admin@example.net", "userPropertiesGet");
$this->assertArraySubset($exp, $props); $this->assertArraySubset($exp, $props);
$this->assertArrayNotHasKey("password", $props); $this->assertArrayNotHasKey("password", $props);
} }
function testGetThePropertiesOfAMissingUser() { function testGetThePropertiesOfAMissingUser() {
$this->assertException("doesNotExist", "User"); $this->assertException("doesNotExist", "User");
Data::$db->userPropertiesGet("john.doe@example.org"); Arsse::$db->userPropertiesGet("john.doe@example.org");
} }
function testGetUserPropertiesWithoutAuthority() { function testGetUserPropertiesWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->userPropertiesGet("john.doe@example.com"); Arsse::$db->userPropertiesGet("john.doe@example.com");
} }
function testSetUserProperties() { function testSetUserProperties() {
@ -190,8 +190,8 @@ trait SeriesUser {
'name' => 'James Kirk', 'name' => 'James Kirk',
'rights' => UserDriver::RIGHTS_GLOBAL_ADMIN, 'rights' => UserDriver::RIGHTS_GLOBAL_ADMIN,
]; ];
$props = Data::$db->userPropertiesSet("admin@example.net", $try); $props = Arsse::$db->userPropertiesSet("admin@example.net", $try);
Phake::verify(Data::$user)->authorize("admin@example.net", "userPropertiesSet"); Phake::verify(Arsse::$user)->authorize("admin@example.net", "userPropertiesSet");
$this->assertArraySubset($exp, $props); $this->assertArraySubset($exp, $props);
$this->assertArrayNotHasKey("password", $props); $this->assertArrayNotHasKey("password", $props);
$state = $this->primeExpectations($this->data, ['arsse_users' => ['id','password','name','rights']]); $state = $this->primeExpectations($this->data, ['arsse_users' => ['id','password','name','rights']]);
@ -202,41 +202,41 @@ trait SeriesUser {
function testSetThePropertiesOfAMissingUser() { function testSetThePropertiesOfAMissingUser() {
$try = ['name' => 'John Doe']; $try = ['name' => 'John Doe'];
$this->assertException("doesNotExist", "User"); $this->assertException("doesNotExist", "User");
Data::$db->userPropertiesSet("john.doe@example.org", $try); Arsse::$db->userPropertiesSet("john.doe@example.org", $try);
} }
function testSetUserPropertiesWithoutAuthority() { function testSetUserPropertiesWithoutAuthority() {
$try = ['name' => 'John Doe']; $try = ['name' => 'John Doe'];
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->userPropertiesSet("john.doe@example.com", $try); Arsse::$db->userPropertiesSet("john.doe@example.com", $try);
} }
function testGetUserRights() { function testGetUserRights() {
$user1 = "john.doe@example.com"; $user1 = "john.doe@example.com";
$user2 = "admin@example.net"; $user2 = "admin@example.net";
$this->assertSame(UserDriver::RIGHTS_NONE, Data::$db->userRightsGet($user1)); $this->assertSame(UserDriver::RIGHTS_NONE, Arsse::$db->userRightsGet($user1));
$this->assertSame(UserDriver::RIGHTS_GLOBAL_ADMIN, Data::$db->userRightsGet($user2)); $this->assertSame(UserDriver::RIGHTS_GLOBAL_ADMIN, Arsse::$db->userRightsGet($user2));
Phake::verify(Data::$user)->authorize($user1, "userRightsGet"); Phake::verify(Arsse::$user)->authorize($user1, "userRightsGet");
Phake::verify(Data::$user)->authorize($user2, "userRightsGet"); Phake::verify(Arsse::$user)->authorize($user2, "userRightsGet");
} }
function testGetTheRightsOfAMissingUser() { function testGetTheRightsOfAMissingUser() {
$this->assertSame(UserDriver::RIGHTS_NONE, Data::$db->userRightsGet("john.doe@example.org")); $this->assertSame(UserDriver::RIGHTS_NONE, Arsse::$db->userRightsGet("john.doe@example.org"));
Phake::verify(Data::$user)->authorize("john.doe@example.org", "userRightsGet"); Phake::verify(Arsse::$user)->authorize("john.doe@example.org", "userRightsGet");
} }
function testGetUserRightsWithoutAuthority() { function testGetUserRightsWithoutAuthority() {
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->userRightsGet("john.doe@example.com"); Arsse::$db->userRightsGet("john.doe@example.com");
} }
function testSetUserRights() { function testSetUserRights() {
$user = "john.doe@example.com"; $user = "john.doe@example.com";
$rights = UserDriver::RIGHTS_GLOBAL_ADMIN; $rights = UserDriver::RIGHTS_GLOBAL_ADMIN;
$this->assertTrue(Data::$db->userRightsSet($user, $rights)); $this->assertTrue(Arsse::$db->userRightsSet($user, $rights));
Phake::verify(Data::$user)->authorize($user, "userRightsSet", $rights); Phake::verify(Arsse::$user)->authorize($user, "userRightsSet", $rights);
$state = $this->primeExpectations($this->data, ['arsse_users' => ['id','rights']]); $state = $this->primeExpectations($this->data, ['arsse_users' => ['id','rights']]);
$state['arsse_users']['rows'][2][1] = $rights; $state['arsse_users']['rows'][2][1] = $rights;
$this->compareExpectations($state); $this->compareExpectations($state);
@ -245,13 +245,13 @@ trait SeriesUser {
function testSetTheRightsOfAMissingUser() { function testSetTheRightsOfAMissingUser() {
$rights = UserDriver::RIGHTS_GLOBAL_ADMIN; $rights = UserDriver::RIGHTS_GLOBAL_ADMIN;
$this->assertException("doesNotExist", "User"); $this->assertException("doesNotExist", "User");
Data::$db->userRightsSet("john.doe@example.org", $rights); Arsse::$db->userRightsSet("john.doe@example.org", $rights);
} }
function testSetUserRightsWithoutAuthority() { function testSetUserRightsWithoutAuthority() {
$rights = UserDriver::RIGHTS_GLOBAL_ADMIN; $rights = UserDriver::RIGHTS_GLOBAL_ADMIN;
Phake::when(Data::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); $this->assertException("notAuthorized", "User", "ExceptionAuthz");
Data::$db->userRightsSet("john.doe@example.com", $rights); Arsse::$db->userRightsSet("john.doe@example.com", $rights);
} }
} }

View file

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Test\Database; namespace JKingWeb\Arsse\Test\Database;
use JKingWeb\Arsse\User\Driver as UserDriver; use JKingWeb\Arsse\User\Driver as UserDriver;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\Conf; use JKingWeb\Arsse\Conf;
use JKingWeb\Arsse\User; use JKingWeb\Arsse\User;
use JKingWeb\Arsse\Test\Database; use JKingWeb\Arsse\Test\Database;
@ -16,15 +16,15 @@ trait Setup {
// establish a clean baseline // establish a clean baseline
$this->clearData(); $this->clearData();
// create a default configuration // create a default configuration
Data::$conf = new Conf(); Arsse::$conf = new Conf();
// configure and create the relevant database driver // configure and create the relevant database driver
$this->setUpDriver(); $this->setUpDriver();
// create the database interface with the suitable driver // create the database interface with the suitable driver
Data::$db = new Database($this->drv); Arsse::$db = new Database($this->drv);
Data::$db->schemaUpdate(); Arsse::$db->schemaUpdate();
// create a mock user manager // create a mock user manager
Data::$user = Phake::mock(User::class); Arsse::$user = Phake::mock(User::class);
Phake::when(Data::$user)->authorize->thenReturn(true); Phake::when(Arsse::$user)->authorize->thenReturn(true);
// call the additional setup method if it exists // call the additional setup method if it exists
if(method_exists($this, "setUpSeries")) $this->setUpSeries(); if(method_exists($this, "setUpSeries")) $this->setUpSeries();
// prime the database with series data // prime the database with series data

View file

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Test\Lang; namespace JKingWeb\Arsse\Test\Lang;
use JKingWeb\Arsse\Lang; use JKingWeb\Arsse\Lang;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
use org\bovigo\vfs\vfsStream; use org\bovigo\vfs\vfsStream;
use Phake; use Phake;
@ -37,16 +37,16 @@ trait Setup {
$this->l = new TestLang($this->path); $this->l = new TestLang($this->path);
// create a mock Lang object so as not to create a dependency loop // create a mock Lang object so as not to create a dependency loop
$this->clearData(false); $this->clearData(false);
Data::$lang = Phake::mock(Lang::class); Arsse::$lang = Phake::mock(Lang::class);
Phake::when(Data::$lang)->msg->thenReturn(""); Phake::when(Arsse::$lang)->msg->thenReturn("");
// call the additional setup method if it exists // call the additional setup method if it exists
if(method_exists($this, "setUpSeries")) $this->setUpSeries(); if(method_exists($this, "setUpSeries")) $this->setUpSeries();
} }
function tearDown() { function tearDown() {
// verify calls to the mock Lang object // verify calls to the mock Lang object
Phake::verify(Data::$lang, Phake::atLeast(0))->msg($this->isType("string"), $this->anything()); Phake::verify(Arsse::$lang, Phake::atLeast(0))->msg($this->isType("string"), $this->anything());
Phake::verifyNoOtherInteractions(Data::$lang); Phake::verifyNoOtherInteractions(Arsse::$lang);
// clean up // clean up
$this->clearData(true); $this->clearData(true);
// call the additional teardiwn method if it exists // call the additional teardiwn method if it exists

View file

@ -1,7 +1,7 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Test\User; namespace JKingWeb\Arsse\Test\User;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\Conf; use JKingWeb\Arsse\Conf;
use JKingWeb\Arsse\User; use JKingWeb\Arsse\User;
use JKingWeb\Arsse\User\Driver; use JKingWeb\Arsse\User\Driver;
@ -14,10 +14,10 @@ trait CommonTests {
$conf = new Conf(); $conf = new Conf();
$conf->userDriver = $this->drv; $conf->userDriver = $this->drv;
$conf->userPreAuth = false; $conf->userPreAuth = false;
Data::$conf = $conf; Arsse::$conf = $conf;
Data::$db = new Database(); Arsse::$db = new Database();
Data::$user = Phake::PartialMock(User::class); Arsse::$user = Phake::PartialMock(User::class);
Phake::when(Data::$user)->authorize->thenReturn(true); Phake::when(Arsse::$user)->authorize->thenReturn(true);
$_SERVER['PHP_AUTH_USER'] = self::USER1; $_SERVER['PHP_AUTH_USER'] = self::USER1;
$_SERVER['PHP_AUTH_PW'] = "secret"; $_SERVER['PHP_AUTH_PW'] = "secret";
// call the additional setup method if it exists // call the additional setup method if it exists
@ -31,76 +31,76 @@ trait CommonTests {
} }
function testListUsers() { function testListUsers() {
$this->assertCount(0,Data::$user->list()); $this->assertCount(0,Arsse::$user->list());
} }
function testCheckIfAUserDoesNotExist() { function testCheckIfAUserDoesNotExist() {
$this->assertFalse(Data::$user->exists(self::USER1)); $this->assertFalse(Arsse::$user->exists(self::USER1));
} }
function testAddAUser() { function testAddAUser() {
Data::$user->add(self::USER1, ""); Arsse::$user->add(self::USER1, "");
$this->assertCount(1,Data::$user->list()); $this->assertCount(1,Arsse::$user->list());
} }
function testCheckIfAUserDoesExist() { function testCheckIfAUserDoesExist() {
Data::$user->add(self::USER1, ""); Arsse::$user->add(self::USER1, "");
$this->assertTrue(Data::$user->exists(self::USER1)); $this->assertTrue(Arsse::$user->exists(self::USER1));
} }
function testAddADuplicateUser() { function testAddADuplicateUser() {
Data::$user->add(self::USER1, ""); Arsse::$user->add(self::USER1, "");
$this->assertException("alreadyExists", "User"); $this->assertException("alreadyExists", "User");
Data::$user->add(self::USER1, ""); Arsse::$user->add(self::USER1, "");
} }
function testAddMultipleUsers() { function testAddMultipleUsers() {
Data::$user->add(self::USER1, ""); Arsse::$user->add(self::USER1, "");
Data::$user->add(self::USER2, ""); Arsse::$user->add(self::USER2, "");
$this->assertCount(2,Data::$user->list()); $this->assertCount(2,Arsse::$user->list());
} }
function testRemoveAUser() { function testRemoveAUser() {
Data::$user->add(self::USER1, ""); Arsse::$user->add(self::USER1, "");
$this->assertCount(1,Data::$user->list()); $this->assertCount(1,Arsse::$user->list());
Data::$user->remove(self::USER1); Arsse::$user->remove(self::USER1);
$this->assertCount(0,Data::$user->list()); $this->assertCount(0,Arsse::$user->list());
} }
function testRemoveAMissingUser() { function testRemoveAMissingUser() {
$this->assertException("doesNotExist", "User"); $this->assertException("doesNotExist", "User");
Data::$user->remove(self::USER1); Arsse::$user->remove(self::USER1);
} }
function testAuthenticateAUser() { function testAuthenticateAUser() {
$_SERVER['PHP_AUTH_USER'] = self::USER1; $_SERVER['PHP_AUTH_USER'] = self::USER1;
$_SERVER['PHP_AUTH_PW'] = "secret"; $_SERVER['PHP_AUTH_PW'] = "secret";
Data::$user->add(self::USER1, "secret"); Arsse::$user->add(self::USER1, "secret");
Data::$user->add(self::USER2, ""); Arsse::$user->add(self::USER2, "");
$this->assertTrue(Data::$user->auth()); $this->assertTrue(Arsse::$user->auth());
$this->assertTrue(Data::$user->auth(self::USER1, "secret")); $this->assertTrue(Arsse::$user->auth(self::USER1, "secret"));
$this->assertFalse(Data::$user->auth(self::USER1, "superman")); $this->assertFalse(Arsse::$user->auth(self::USER1, "superman"));
$this->assertTrue(Data::$user->auth(self::USER2, "")); $this->assertTrue(Arsse::$user->auth(self::USER2, ""));
} }
function testChangeAPassword() { function testChangeAPassword() {
Data::$user->add(self::USER1, "secret"); Arsse::$user->add(self::USER1, "secret");
$this->assertEquals("superman", Data::$user->passwordSet(self::USER1, "superman")); $this->assertEquals("superman", Arsse::$user->passwordSet(self::USER1, "superman"));
$this->assertTrue(Data::$user->auth(self::USER1, "superman")); $this->assertTrue(Arsse::$user->auth(self::USER1, "superman"));
$this->assertFalse(Data::$user->auth(self::USER1, "secret")); $this->assertFalse(Arsse::$user->auth(self::USER1, "secret"));
$this->assertEquals("", Data::$user->passwordSet(self::USER1, "")); $this->assertEquals("", Arsse::$user->passwordSet(self::USER1, ""));
$this->assertTrue(Data::$user->auth(self::USER1, "")); $this->assertTrue(Arsse::$user->auth(self::USER1, ""));
$this->assertEquals(Data::$conf->userTempPasswordLength, strlen(Data::$user->passwordSet(self::USER1))); $this->assertEquals(Arsse::$conf->userTempPasswordLength, strlen(Arsse::$user->passwordSet(self::USER1)));
} }
function testChangeAPasswordForAMissingUser() { function testChangeAPasswordForAMissingUser() {
$this->assertException("doesNotExist", "User"); $this->assertException("doesNotExist", "User");
Data::$user->passwordSet(self::USER1, "superman"); Arsse::$user->passwordSet(self::USER1, "superman");
} }
function testGetThePropertiesOfAUser() { function testGetThePropertiesOfAUser() {
Data::$user->add(self::USER1, "secret"); Arsse::$user->add(self::USER1, "secret");
$p = Data::$user->propertiesGet(self::USER1); $p = Arsse::$user->propertiesGet(self::USER1);
$this->assertArrayHasKey('id', $p); $this->assertArrayHasKey('id', $p);
$this->assertArrayHasKey('name', $p); $this->assertArrayHasKey('name', $p);
$this->assertArrayHasKey('domain', $p); $this->assertArrayHasKey('domain', $p);
@ -123,22 +123,22 @@ trait CommonTests {
'domain' => 'example.com', 'domain' => 'example.com',
'rights' => Driver::RIGHTS_NONE, 'rights' => Driver::RIGHTS_NONE,
]; ];
Data::$user->add(self::USER1, "secret"); Arsse::$user->add(self::USER1, "secret");
Data::$user->propertiesSet(self::USER1, $pSet); Arsse::$user->propertiesSet(self::USER1, $pSet);
$p = Data::$user->propertiesGet(self::USER1); $p = Arsse::$user->propertiesGet(self::USER1);
$this->assertArraySubset($pGet, $p); $this->assertArraySubset($pGet, $p);
$this->assertArrayNotHasKey('password', $p); $this->assertArrayNotHasKey('password', $p);
$this->assertFalse(Data::$user->auth(self::USER1, "superman")); $this->assertFalse(Arsse::$user->auth(self::USER1, "superman"));
} }
function testGetTheRightsOfAUser() { function testGetTheRightsOfAUser() {
Data::$user->add(self::USER1, ""); Arsse::$user->add(self::USER1, "");
$this->assertEquals(Driver::RIGHTS_NONE, Data::$user->rightsGet(self::USER1)); $this->assertEquals(Driver::RIGHTS_NONE, Arsse::$user->rightsGet(self::USER1));
} }
function testSetTheRightsOfAUser() { function testSetTheRightsOfAUser() {
Data::$user->add(self::USER1, ""); Arsse::$user->add(self::USER1, "");
Data::$user->rightsSet(self::USER1, Driver::RIGHTS_GLOBAL_ADMIN); Arsse::$user->rightsSet(self::USER1, Driver::RIGHTS_GLOBAL_ADMIN);
$this->assertEquals(Driver::RIGHTS_GLOBAL_ADMIN, Data::$user->rightsGet(self::USER1)); $this->assertEquals(Driver::RIGHTS_GLOBAL_ADMIN, Arsse::$user->rightsGet(self::USER1));
} }
} }

View file

@ -1,7 +1,7 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Test\User; namespace JKingWeb\Arsse\Test\User;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\User\Driver; use JKingWeb\Arsse\User\Driver;
use JKingWeb\Arsse\User\Exception; use JKingWeb\Arsse\User\Exception;
use JKingWeb\Arsse\User\ExceptionAuthz; use JKingWeb\Arsse\User\ExceptionAuthz;
@ -15,43 +15,43 @@ class Database extends DriverSkeleton {
} }
function userExists(string $user): bool { function userExists(string $user): bool {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
return parent::userExists($user); return parent::userExists($user);
} }
function userAdd(string $user, string $password = null): string { function userAdd(string $user, string $password = null): string {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
if($this->userExists($user)) throw new Exception("alreadyExists", ["action" => __FUNCTION__, "user" => $user]); if($this->userExists($user)) throw new Exception("alreadyExists", ["action" => __FUNCTION__, "user" => $user]);
if($password===null) $password = (new PassGen)->length(Data::$conf->userTempPasswordLength)->get(); if($password===null) $password = (new PassGen)->length(Arsse::$conf->userTempPasswordLength)->get();
return parent::userAdd($user, $password); return parent::userAdd($user, $password);
} }
function userRemove(string $user): bool { function userRemove(string $user): bool {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]);
return parent::userRemove($user); return parent::userRemove($user);
} }
function userList(string $domain = null): array { function userList(string $domain = null): array {
if($domain===null) { if($domain===null) {
if(!Data::$user->authorize("", __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => "global"]); if(!Arsse::$user->authorize("", __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => "global"]);
return parent::userList(); return parent::userList();
} else { } else {
$suffix = '@'.$domain; $suffix = '@'.$domain;
if(!Data::$user->authorize($suffix, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $domain]); if(!Arsse::$user->authorize($suffix, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $domain]);
return parent::userList($domain); return parent::userList($domain);
} }
} }
function userPasswordSet(string $user, string $newPassword = null, string $oldPassword = null): string { function userPasswordSet(string $user, string $newPassword = null, string $oldPassword = null): string {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]);
if($newPassword===null) $newPassword = (new PassGen)->length(Data::$conf->userTempPasswordLength)->get(); if($newPassword===null) $newPassword = (new PassGen)->length(Arsse::$conf->userTempPasswordLength)->get();
return parent::userPasswordSet($user, $newPassword); return parent::userPasswordSet($user, $newPassword);
} }
function userPropertiesGet(string $user): array { function userPropertiesGet(string $user): array {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]);
$out = parent::userPropertiesGet($user); $out = parent::userPropertiesGet($user);
unset($out['password']); unset($out['password']);
@ -59,20 +59,20 @@ class Database extends DriverSkeleton {
} }
function userPropertiesSet(string $user, array $properties): array { function userPropertiesSet(string $user, array $properties): array {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]);
parent::userPropertiesSet($user, $properties); parent::userPropertiesSet($user, $properties);
return $this->userPropertiesGet($user); return $this->userPropertiesGet($user);
} }
function userRightsGet(string $user): int { function userRightsGet(string $user): int {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]);
return parent::userRightsGet($user); return parent::userRightsGet($user);
} }
function userRightsSet(string $user, int $level): bool { function userRightsSet(string $user, int $level): bool {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]);
return parent::userRightsSet($user, $level); return parent::userRightsSet($user, $level);
} }
@ -80,7 +80,7 @@ class Database extends DriverSkeleton {
// specific to mock database // specific to mock database
function userPasswordGet(string $user): string { function userPasswordGet(string $user): string {
if(!Data::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); if(!Arsse::$user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]);
return $this->db[$user]['password']; return $this->db[$user]['password'];
} }

View file

@ -1,7 +1,7 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace JKingWeb\Arsse\Test\User; namespace JKingWeb\Arsse\Test\User;
use JKingWeb\Arsse\Data; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\User\Driver; use JKingWeb\Arsse\User\Driver;
use JKingWeb\Arsse\User\Exception; use JKingWeb\Arsse\User\Exception;
use PasswordGenerator\Generator as PassGen; use PasswordGenerator\Generator as PassGen;
@ -51,7 +51,7 @@ class DriverExternalMock extends DriverSkeleton implements Driver {
function userAdd(string $user, string $password = null): string { function userAdd(string $user, string $password = null): string {
if($this->userExists($user)) throw new Exception("alreadyExists", ["action" => __FUNCTION__, "user" => $user]); if($this->userExists($user)) throw new Exception("alreadyExists", ["action" => __FUNCTION__, "user" => $user]);
if($password===null) $password = (new PassGen)->length(Data::$conf->userTempPasswordLength)->get(); if($password===null) $password = (new PassGen)->length(Arsse::$conf->userTempPasswordLength)->get();
return parent::userAdd($user, $password); return parent::userAdd($user, $password);
} }
@ -70,7 +70,7 @@ class DriverExternalMock extends DriverSkeleton implements Driver {
function userPasswordSet(string $user, string $newPassword = null, string $oldPassword = null): string { function userPasswordSet(string $user, string $newPassword = null, string $oldPassword = null): string {
if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]);
if($newPassword===null) $newPassword = (new PassGen)->length(Data::$conf->userTempPasswordLength)->get(); if($newPassword===null) $newPassword = (new PassGen)->length(Arsse::$conf->userTempPasswordLength)->get();
return parent::userPasswordSet($user, $newPassword); return parent::userPasswordSet($user, $newPassword);
} }