mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 21:22:40 +00:00
parent
feadf51096
commit
3a26c75044
8 changed files with 114 additions and 23 deletions
|
@ -8,10 +8,6 @@ use JKingWeb\Arsse\Misc\Date;
|
|||
|
||||
class Database {
|
||||
const SCHEMA_VERSION = 1;
|
||||
const FORMAT_TS = "Y-m-d h:i:s";
|
||||
const FORMAT_DATE = "Y-m-d";
|
||||
const FORMAT_TIME = "h:i:s";
|
||||
|
||||
|
||||
/** @var Db\Driver */
|
||||
public $db;
|
||||
|
@ -29,7 +25,7 @@ class Database {
|
|||
return debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2]['function'];
|
||||
}
|
||||
|
||||
static public function listDrivers(): array {
|
||||
static public function driverList(): array {
|
||||
$sep = \DIRECTORY_SEPARATOR;
|
||||
$path = __DIR__.$sep."Db".$sep;
|
||||
$classes = [];
|
||||
|
@ -41,11 +37,11 @@ class Database {
|
|||
return $classes;
|
||||
}
|
||||
|
||||
public function schemaVersion(): int {
|
||||
public function driverSchemaVersion(): int {
|
||||
return $this->db->schemaVersion();
|
||||
}
|
||||
|
||||
public function schemaUpdate(): bool {
|
||||
public function driverSchemaUpdate(): bool {
|
||||
if($this->db->schemaVersion() < self::SCHEMA_VERSION) return $this->db->schemaUpdate(self::SCHEMA_VERSION);
|
||||
return false;
|
||||
}
|
||||
|
@ -86,17 +82,16 @@ class Database {
|
|||
return $this->db->prepare("SELECT value from arsse_meta where key is ?", "str")->run($key)->getValue();
|
||||
}
|
||||
|
||||
public function metaSet(string $key, string $value, string $type = "str"): bool {
|
||||
$out = !$this->db->prepare("UPDATE arsse_meta set value = ? where key is ?", $type, "str")->run($value, $key)->changes();
|
||||
public function metaSet(string $key, $value, string $type = "str"): bool {
|
||||
$out = $this->db->prepare("UPDATE arsse_meta set value = ? where key is ?", $type, "str")->run($value, $key)->changes();
|
||||
if(!$out) {
|
||||
$out = $this->db->prepare("INSERT INTO arsse_meta(key,value)", "str", $type)->run($key, $value)->changes();
|
||||
$out = $this->db->prepare("INSERT INTO arsse_meta(key,value) values(?,?)", "str", $type)->run($key, $value)->changes();
|
||||
}
|
||||
return (bool) $out;
|
||||
}
|
||||
|
||||
public function metaRemove(string $key): bool {
|
||||
$this->db->prepare("DELETE from arsse_meta where key is ?", "str")->run($key);
|
||||
return true;
|
||||
return (bool) $this->db->prepare("DELETE from arsse_meta where key is ?", "str")->run($key)->changes();
|
||||
}
|
||||
|
||||
public function userExists(string $user): bool {
|
||||
|
@ -776,7 +771,7 @@ class Database {
|
|||
return (bool) $out;
|
||||
}
|
||||
|
||||
public function articleValidateId(string $user, int $id): array {
|
||||
protected function articleValidateId(string $user, int $id): array {
|
||||
$out = $this->db->prepare(
|
||||
"SELECT
|
||||
arsse_articles.id as article,
|
||||
|
|
12
lib/Feed.php
12
lib/Feed.php
|
@ -52,7 +52,7 @@ class Feed {
|
|||
$this->nextFetch = $this->computeNextFetch();
|
||||
}
|
||||
|
||||
public function download(string $url, string $lastModified = '', string $etag = '', string $username = '', string $password = ''): bool {
|
||||
protected function download(string $url, string $lastModified = '', string $etag = '', string $username = '', string $password = ''): bool {
|
||||
try {
|
||||
$this->reader = new Reader($this->config);
|
||||
$this->resource = $this->reader->download($url, $lastModified, $etag, $username, $password);
|
||||
|
@ -62,7 +62,7 @@ class Feed {
|
|||
return true;
|
||||
}
|
||||
|
||||
public function parse(): bool {
|
||||
protected function parse(): bool {
|
||||
try {
|
||||
$this->parser = $this->reader->getParser(
|
||||
$this->resource->getUrl(),
|
||||
|
@ -192,7 +192,7 @@ class Feed {
|
|||
return $out;
|
||||
}
|
||||
|
||||
public function matchToDatabase(int $feedID = null): bool {
|
||||
protected function matchToDatabase(int $feedID = null): bool {
|
||||
// first perform deduplication on items
|
||||
$items = $this->deduplicateItems($this->data->items);
|
||||
// if we haven't been given a database feed ID to check against, all items are new
|
||||
|
@ -221,7 +221,7 @@ class Feed {
|
|||
return true;
|
||||
}
|
||||
|
||||
public function matchItems(array $items, array $articles): array {
|
||||
protected function matchItems(array $items, array $articles): array {
|
||||
$new = $edited = [];
|
||||
// iterate through the articles and for each determine whether it is existing, edited, or entirely new
|
||||
foreach($items as $i) {
|
||||
|
@ -260,7 +260,7 @@ class Feed {
|
|||
return [$new, $edited];
|
||||
}
|
||||
|
||||
public function computeNextFetch(): \DateTime {
|
||||
protected function computeNextFetch(): \DateTime {
|
||||
$now = Date::normalize(time());
|
||||
if(!$this->modified) {
|
||||
$diff = $now->getTimestamp() - $this->lastModified->getTimestamp();
|
||||
|
@ -318,7 +318,7 @@ class Feed {
|
|||
return $offset;
|
||||
}
|
||||
|
||||
public function computeLastModified() {
|
||||
protected function computeLastModified() {
|
||||
if(!$this->modified) return $this->lastModified;
|
||||
$dates = $this->gatherDates();
|
||||
if(sizeof($dates)) {
|
||||
|
|
|
@ -10,6 +10,18 @@ class Service {
|
|||
/** @var \DateInterval */
|
||||
protected $interval;
|
||||
|
||||
static public function driverList(): array {
|
||||
$sep = \DIRECTORY_SEPARATOR;
|
||||
$path = __DIR__.$sep."Service".$sep;
|
||||
$classes = [];
|
||||
foreach(glob($path."*".$sep."Driver.php") as $file) {
|
||||
$name = basename(dirname($file));
|
||||
$class = NS_BASE."User\\$name\\Driver";
|
||||
$classes[$class] = $class::driverName();
|
||||
}
|
||||
return $classes;
|
||||
}
|
||||
|
||||
protected static function interval(): \DateInterval {
|
||||
return new \DateInterval(Arsse::$conf->serviceFrequency); // FIXME: this needs to fall back in case of incorrect input
|
||||
}
|
||||
|
@ -32,6 +44,7 @@ class Service {
|
|||
$this->drv->exec();
|
||||
$this->drv->clean();
|
||||
static::cleanupPost();
|
||||
unset($list);
|
||||
}
|
||||
$t->add($this->interval);
|
||||
do {
|
||||
|
|
|
@ -19,7 +19,7 @@ class User {
|
|||
protected $authzSupported = 0;
|
||||
protected $actor = [];
|
||||
|
||||
static public function listDrivers(): array {
|
||||
static public function driverList(): array {
|
||||
$sep = \DIRECTORY_SEPARATOR;
|
||||
$path = __DIR__.$sep."User".$sep;
|
||||
$classes = [];
|
||||
|
|
9
tests/Db/SQLite3/Database/TestDatabaseMetaSQLite3.php
Normal file
9
tests/Db/SQLite3/Database/TestDatabaseMetaSQLite3.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace JKingWeb\Arsse;
|
||||
|
||||
class TestDatabaseMetaSQLite3 extends Test\AbstractTest {
|
||||
use Test\Database\Setup;
|
||||
use Test\Database\DriverSQLite3;
|
||||
use Test\Database\SeriesMeta;
|
||||
}
|
70
tests/lib/Database/SeriesMeta.php
Normal file
70
tests/lib/Database/SeriesMeta.php
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace JKingWeb\Arsse\Test\Database;
|
||||
use JKingWeb\Arsse\Test\Database;
|
||||
use JKingWeb\Arsse\Arsse;
|
||||
|
||||
trait SeriesMeta {
|
||||
protected $dataBare = [
|
||||
'arsse_meta' => [
|
||||
'columns' => [
|
||||
'key' => 'str',
|
||||
'value' => 'str',
|
||||
],
|
||||
'rows' => [
|
||||
//['schema_version', "".\JKingWeb\Arsse\Database::SCHEMA_VERSION],
|
||||
['album',"A Farewell to Kings"],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
function setUpSeries() {
|
||||
// the schema_version key is a special case, and to avoid jumping through hoops for every test we deal with it now
|
||||
$this->data = $this->dataBare;
|
||||
// as far as tests are concerned the schema version is part of the expectations primed into the database
|
||||
array_unshift($this->data['arsse_meta']['rows'], ['schema_version', "".Database::SCHEMA_VERSION]);
|
||||
// but it's already been inserted by the driver, so we prime without it
|
||||
$this->primeDatabase($this->dataBare);
|
||||
}
|
||||
|
||||
function testAddANewValue() {
|
||||
$this->assertTrue(Arsse::$db->metaSet("favourite", "Cygnus X-1"));
|
||||
$state = $this->primeExpectations($this->data, ['arsse_meta' => ['key','value']]);
|
||||
$state['arsse_meta']['rows'][] = ["favourite","Cygnus X-1"];
|
||||
$this->compareExpectations($state);
|
||||
}
|
||||
|
||||
function testAddANewTypedValue() {
|
||||
$this->assertTrue(Arsse::$db->metaSet("answer", 42, "int"));
|
||||
$this->assertTrue(Arsse::$db->metaSet("true", true, "bool"));
|
||||
$this->assertTrue(Arsse::$db->metaSet("false", false, "bool"));
|
||||
$this->assertTrue(Arsse::$db->metaSet("millennium", new \DateTime("2000-01-01T00:00:00Z"), "datetime"));
|
||||
$state = $this->primeExpectations($this->data, ['arsse_meta' => ['key','value']]);
|
||||
$state['arsse_meta']['rows'][] = ["answer","42"];
|
||||
$state['arsse_meta']['rows'][] = ["true","1"];
|
||||
$state['arsse_meta']['rows'][] = ["false","0"];
|
||||
$state['arsse_meta']['rows'][] = ["millennium","2000-01-01 00:00:00"];
|
||||
$this->compareExpectations($state);
|
||||
}
|
||||
|
||||
function testChangeAnExistingValue() {
|
||||
$this->assertTrue(Arsse::$db->metaSet("album", "Hemispheres"));
|
||||
$state = $this->primeExpectations($this->data, ['arsse_meta' => ['key','value']]);
|
||||
$state['arsse_meta']['rows'][1][1] = "Hemispheres";
|
||||
$this->compareExpectations($state);
|
||||
}
|
||||
|
||||
function testRemoveAValue() {
|
||||
$this->assertTrue(Arsse::$db->metaRemove("album"));
|
||||
$this->assertFalse(Arsse::$db->metaRemove("album"));
|
||||
$state = $this->primeExpectations($this->data, ['arsse_meta' => ['key','value']]);
|
||||
unset($state['arsse_meta']['rows'][1]);
|
||||
$this->compareExpectations($state);
|
||||
}
|
||||
|
||||
function testRetrieveAValue() {
|
||||
$this->assertSame("".Database::SCHEMA_VERSION, Arsse::$db->metaGet("schema_version"));
|
||||
$this->assertSame("A Farewell to Kings", Arsse::$db->metaGet("album"));
|
||||
$this->assertSame(null, Arsse::$db->metaGet("this_key_does_not_exist"));
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ use Phake;
|
|||
|
||||
trait Setup {
|
||||
protected $drv;
|
||||
protected $primed = false;
|
||||
|
||||
function setUp() {
|
||||
// establish a clean baseline
|
||||
|
@ -21,20 +22,21 @@ trait Setup {
|
|||
$this->setUpDriver();
|
||||
// create the database interface with the suitable driver
|
||||
Arsse::$db = new Database($this->drv);
|
||||
Arsse::$db->schemaUpdate();
|
||||
Arsse::$db->driverSchemaUpdate();
|
||||
// create a mock user manager
|
||||
Arsse::$user = Phake::mock(User::class);
|
||||
Phake::when(Arsse::$user)->authorize->thenReturn(true);
|
||||
// call the additional setup method if it exists
|
||||
if(method_exists($this, "setUpSeries")) $this->setUpSeries();
|
||||
// prime the database with series data
|
||||
if(isset($this->data)) $this->primeDatabase($this->data);
|
||||
// prime the database with series data if it hasn't already been done
|
||||
if(!$this->primed && isset($this->data)) $this->primeDatabase($this->data);
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
// call the additional teardiwn method if it exists
|
||||
if(method_exists($this, "tearDownSeries")) $this->tearDownSeries();
|
||||
// clean up
|
||||
$this->primed = false;
|
||||
$this->drv = null;
|
||||
$this->clearData();
|
||||
}
|
||||
|
@ -51,6 +53,7 @@ trait Setup {
|
|||
}
|
||||
}
|
||||
$tr->commit();
|
||||
$this->primed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
<file>Db/SQLite3/TestDbUpdateSQLite3.php</file>
|
||||
</testsuite>
|
||||
<testsuite name="Database functions">
|
||||
<file>Db/SQLite3/Database/TestDatabaseMetaSQLite3.php</file>
|
||||
<file>Db/SQLite3/Database/TestDatabaseUserSQLite3.php</file>
|
||||
<file>Db/SQLite3/Database/TestDatabaseFolderSQLite3.php</file>
|
||||
<file>Db/SQLite3/Database/TestDatabaseFeedSQLite3.php</file>
|
||||
|
|
Loading…
Reference in a new issue