mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-23 08:24:54 +00:00
Complete implementations of server status and user status REST calls
- Fixes #30 - Fixes #31 - Avatars are not yet supported by the data model; blocked by issue #52
This commit is contained in:
parent
3a26c75044
commit
4cded011ff
6 changed files with 104 additions and 16 deletions
|
@ -595,13 +595,22 @@ 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
|
$data = Arsse::$user::propertiesGet(Arsse::$user->id, true);
|
||||||
$data = Arsse::$db->userPropertiesGet(Arsse::$user->id);
|
// construct the avatar structure, if an image is available
|
||||||
|
if(isset($data['avatar'])) {
|
||||||
|
$avatar = [
|
||||||
|
'data' => base64_encode($data['avatar']['data']),
|
||||||
|
'mime' => $data['avatar']['type'],
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$avatar = null;
|
||||||
|
}
|
||||||
|
// construct the rest of the structure
|
||||||
$out = [
|
$out = [
|
||||||
'userId' => Arsse::$user->id,
|
'userId' => Arsse::$user->id,
|
||||||
'displayName' => $data['name'] ?? Arsse::$user->id,
|
'displayName' => $data['name'] ?? Arsse::$user->id,
|
||||||
'lastLoginTimestamp' => time(),
|
'lastLoginTimestamp' => time(),
|
||||||
'avatar' => null,
|
'avatar' => $avatar,
|
||||||
];
|
];
|
||||||
return new Response(200, $out);
|
return new Response(200, $out);
|
||||||
}
|
}
|
||||||
|
@ -629,12 +638,11 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function serverStatus(array $url, array $data): Response {
|
protected function serverStatus(array $url, array $data): Response {
|
||||||
// FIXME: stub
|
|
||||||
return new Response(200, [
|
return new Response(200, [
|
||||||
'version' => self::VERSION,
|
'version' => self::VERSION,
|
||||||
'arsse_version' => \JKingWeb\Arsse\VERSION,
|
'arsse_version' => \JKingWeb\Arsse\VERSION,
|
||||||
'warnings' => [
|
'warnings' => [
|
||||||
'improperlyConfiguredCron' => false,
|
'improperlyConfiguredCron' => !\JKingWeb\Arsse\Service::hasCheckedIn(),
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,12 @@ class Service {
|
||||||
return $classes;
|
return $classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function interval(): \DateInterval {
|
public static function interval(): \DateInterval {
|
||||||
return new \DateInterval(Arsse::$conf->serviceFrequency); // FIXME: this needs to fall back in case of incorrect input
|
try{
|
||||||
|
return new \DateInterval(Arsse::$conf->serviceFrequency);
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
return new \DateInterval("PT2M");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function __construct() {
|
function __construct() {
|
||||||
|
@ -32,14 +36,13 @@ class Service {
|
||||||
$this->interval = static::interval();
|
$this->interval = static::interval();
|
||||||
}
|
}
|
||||||
|
|
||||||
function watch(bool $loop = true) {
|
function watch(bool $loop = true): \DateTimeInterface {
|
||||||
$t = new \DateTime();
|
$t = new \DateTime();
|
||||||
do {
|
do {
|
||||||
$this->checkIn();
|
$this->checkIn();
|
||||||
static::cleanupPre();
|
static::cleanupPre();
|
||||||
$list = Arsse::$db->feedListStale();
|
$list = Arsse::$db->feedListStale();
|
||||||
if($list) {
|
if($list) {
|
||||||
echo date("H:i:s")." Updating feeds ".json_encode($list)."\n";
|
|
||||||
$this->drv->queue(...$list);
|
$this->drv->queue(...$list);
|
||||||
$this->drv->exec();
|
$this->drv->exec();
|
||||||
$this->drv->clean();
|
$this->drv->clean();
|
||||||
|
@ -47,10 +50,13 @@ class Service {
|
||||||
unset($list);
|
unset($list);
|
||||||
}
|
}
|
||||||
$t->add($this->interval);
|
$t->add($this->interval);
|
||||||
do {
|
if($loop) {
|
||||||
@time_sleep_until($t->getTimestamp());
|
do {
|
||||||
} while($t->getTimestamp() > time());
|
@time_sleep_until($t->getTimestamp());
|
||||||
|
} while($t->getTimestamp() > time());
|
||||||
|
}
|
||||||
} while($loop);
|
} while($loop);
|
||||||
|
return $t;
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkIn(): bool {
|
function checkIn(): bool {
|
||||||
|
@ -69,8 +75,8 @@ class Service {
|
||||||
$limit = new \DateTime();
|
$limit = new \DateTime();
|
||||||
$limit->sub($int);
|
$limit->sub($int);
|
||||||
$limit->sub($int);
|
$limit->sub($int);
|
||||||
// return whether the check-in time is less than the acceptable limit
|
// return whether the check-in time is within the acceptable limit
|
||||||
return ($checkin < $limit);
|
return ($checkin >= $limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function cleanupPre(): bool {
|
static function cleanupPre(): bool {
|
||||||
|
|
|
@ -245,7 +245,7 @@ class User {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function propertiesGet(string $user): array {
|
public function propertiesGet(string $user, bool $withAvatar = false): array {
|
||||||
// prepare default values
|
// prepare default values
|
||||||
$domain = null;
|
$domain = null;
|
||||||
if(Arsse::$conf->userComposeNames) $domain = substr($user,strrpos($user,"@")+1);
|
if(Arsse::$conf->userComposeNames) $domain = substr($user,strrpos($user,"@")+1);
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace JKingWeb\Arsse;
|
||||||
use JKingWeb\Arsse\REST\Request;
|
use JKingWeb\Arsse\REST\Request;
|
||||||
use JKingWeb\Arsse\REST\Response;
|
use JKingWeb\Arsse\REST\Response;
|
||||||
use JKingWeb\Arsse\Test\Result;
|
use JKingWeb\Arsse\Test\Result;
|
||||||
|
use JKingWeb\Arsse\Misc\Date;
|
||||||
use JKingWeb\Arsse\Misc\Context;
|
use JKingWeb\Arsse\Misc\Context;
|
||||||
use JKingWeb\Arsse\Db\ExceptionInput;
|
use JKingWeb\Arsse\Db\ExceptionInput;
|
||||||
use JKingWeb\Arsse\Db\Transaction;
|
use JKingWeb\Arsse\Db\Transaction;
|
||||||
|
@ -260,6 +261,7 @@ class TestNCNV1_2 extends Test\AbstractTest {
|
||||||
|
|
||||||
function setUp() {
|
function setUp() {
|
||||||
$this->clearData();
|
$this->clearData();
|
||||||
|
Arsse::$conf = new Conf();
|
||||||
// create a mock user manager
|
// create a mock user manager
|
||||||
Arsse::$user = Phake::mock(User::class);
|
Arsse::$user = Phake::mock(User::class);
|
||||||
Phake::when(Arsse::$user)->authHTTP->thenReturn(true);
|
Phake::when(Arsse::$user)->authHTTP->thenReturn(true);
|
||||||
|
@ -715,7 +717,7 @@ class TestNCNV1_2 extends Test\AbstractTest {
|
||||||
}
|
}
|
||||||
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), $this->anything())->thenReturn(true);
|
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), $this->anything())->thenReturn(true);
|
||||||
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(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(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
|
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), (new Context)->editions($in[1]))->thenThrow(new ExceptionInput("tooLong")); // data model function 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")));
|
||||||
|
@ -762,4 +764,21 @@ class TestNCNV1_2 extends Test\AbstractTest {
|
||||||
Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->articles($in[2]));
|
Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->articles($in[2]));
|
||||||
Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->articles($in[3]));
|
Phake::verify(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->articles($in[3]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testQueryTheServerStatus() {
|
||||||
|
$interval = Service::interval();
|
||||||
|
$valid = (new \DateTimeImmutable("now", new \DateTimezone("UTC")))->sub($interval);
|
||||||
|
$invalid = $valid->sub($interval)->sub($interval);
|
||||||
|
Phake::when(Arsse::$db)->metaGet("service_last_checkin")->thenReturn(Date::transform($valid, "sql"))->thenReturn(Date::transform($invalid, "sql"));
|
||||||
|
$arr1 = $arr2 = [
|
||||||
|
'version' => REST\NextCloudNews\V1_2::VERSION,
|
||||||
|
'arsse_version' => VERSION,
|
||||||
|
'warnings' => [
|
||||||
|
'improperlyConfiguredCron' => false,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
$arr2['warnings']['improperlyConfiguredCron'] = true;
|
||||||
|
$exp = new Response(200, $arr1);
|
||||||
|
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/status")));
|
||||||
|
}
|
||||||
}
|
}
|
51
tests/Service/TestService.php
Normal file
51
tests/Service/TestService.php
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
namespace JKingWeb\Arsse;
|
||||||
|
use JKingWeb\Arsse\Misc\Date;
|
||||||
|
use Phake;
|
||||||
|
|
||||||
|
|
||||||
|
class TestService extends Test\AbstractTest {
|
||||||
|
protected $srv;
|
||||||
|
|
||||||
|
function setUp() {
|
||||||
|
$this->clearData();
|
||||||
|
Arsse::$conf = new Conf();
|
||||||
|
Arsse::$db = Phake::mock(Database::class);
|
||||||
|
$this->srv = new Service();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testComputeInterval() {
|
||||||
|
$in = [
|
||||||
|
Arsse::$conf->serviceFrequency,
|
||||||
|
"PT2M",
|
||||||
|
"PT5M",
|
||||||
|
"P2M",
|
||||||
|
"5M",
|
||||||
|
"interval",
|
||||||
|
];
|
||||||
|
foreach($in as $index => $spec) {
|
||||||
|
try{$exp = new \DateInterval($spec);} catch(\Exception $e) {$exp = new \DateInterval("PT2M");}
|
||||||
|
Arsse::$conf->serviceFrequency = $spec;
|
||||||
|
$this->assertEquals($exp, Service::interval(), "Interval #$index '$spec' was not correctly calculated");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function testCheckIn() {
|
||||||
|
$now = time();
|
||||||
|
$this->srv->checkIn();
|
||||||
|
Phake::verify(Arsse::$db)->metaSet("service_last_checkin", Phake::capture($then), "datetime");
|
||||||
|
$this->assertTime($now, $then);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testReportHavingCheckedIn() {
|
||||||
|
// the mock's metaGet() returns null by default
|
||||||
|
$this->assertFalse(Service::hasCheckedIn());
|
||||||
|
$interval = Service::interval();
|
||||||
|
$valid = (new \DateTimeImmutable("now", new \DateTimezone("UTC")))->sub($interval);
|
||||||
|
$invalid = $valid->sub($interval)->sub($interval);
|
||||||
|
Phake::when(Arsse::$db)->metaGet("service_last_checkin")->thenReturn(Date::transform($valid, "sql"))->thenReturn(Date::transform($invalid, "sql"));
|
||||||
|
$this->assertTrue(Service::hasCheckedIn());
|
||||||
|
$this->assertFalse(Service::hasCheckedIn());
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,5 +53,9 @@
|
||||||
<file>REST/NextCloudNews/TestNCNVersionDiscovery.php</file>
|
<file>REST/NextCloudNews/TestNCNVersionDiscovery.php</file>
|
||||||
<file>REST/NextCloudNews/TestNCNV1_2.php</file>
|
<file>REST/NextCloudNews/TestNCNV1_2.php</file>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
|
<testsuite name="Refresh service">
|
||||||
|
<file>Service/TestService.php</file>
|
||||||
|
</testsuite>
|
||||||
|
|
||||||
</testsuites>
|
</testsuites>
|
||||||
</phpunit>
|
</phpunit>
|
Loading…
Reference in a new issue