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:
J. King 2017-07-19 18:07:36 -04:00
parent 3a26c75044
commit 4cded011ff
6 changed files with 104 additions and 16 deletions

View file

@ -595,13 +595,22 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
}
protected function userStatus(array $url, array $data): Response {
// FIXME: stub
$data = Arsse::$db->userPropertiesGet(Arsse::$user->id);
$data = Arsse::$user::propertiesGet(Arsse::$user->id, true);
// 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 = [
'userId' => Arsse::$user->id,
'displayName' => $data['name'] ?? Arsse::$user->id,
'lastLoginTimestamp' => time(),
'avatar' => null,
'avatar' => $avatar,
];
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 {
// FIXME: stub
return new Response(200, [
'version' => self::VERSION,
'arsse_version' => \JKingWeb\Arsse\VERSION,
'warnings' => [
'improperlyConfiguredCron' => false,
'improperlyConfiguredCron' => !\JKingWeb\Arsse\Service::hasCheckedIn(),
]
]);
}

View file

@ -22,8 +22,12 @@ class Service {
return $classes;
}
protected static function interval(): \DateInterval {
return new \DateInterval(Arsse::$conf->serviceFrequency); // FIXME: this needs to fall back in case of incorrect input
public static function interval(): \DateInterval {
try{
return new \DateInterval(Arsse::$conf->serviceFrequency);
} catch(\Exception $e) {
return new \DateInterval("PT2M");
}
}
function __construct() {
@ -32,14 +36,13 @@ class Service {
$this->interval = static::interval();
}
function watch(bool $loop = true) {
function watch(bool $loop = true): \DateTimeInterface {
$t = new \DateTime();
do {
$this->checkIn();
static::cleanupPre();
$list = Arsse::$db->feedListStale();
if($list) {
echo date("H:i:s")." Updating feeds ".json_encode($list)."\n";
$this->drv->queue(...$list);
$this->drv->exec();
$this->drv->clean();
@ -47,10 +50,13 @@ class Service {
unset($list);
}
$t->add($this->interval);
do {
@time_sleep_until($t->getTimestamp());
} while($t->getTimestamp() > time());
if($loop) {
do {
@time_sleep_until($t->getTimestamp());
} while($t->getTimestamp() > time());
}
} while($loop);
return $t;
}
function checkIn(): bool {
@ -69,8 +75,8 @@ class Service {
$limit = new \DateTime();
$limit->sub($int);
$limit->sub($int);
// return whether the check-in time is less than the acceptable limit
return ($checkin < $limit);
// return whether the check-in time is within the acceptable limit
return ($checkin >= $limit);
}
static function cleanupPre(): bool {

View file

@ -245,7 +245,7 @@ class User {
}
}
public function propertiesGet(string $user): array {
public function propertiesGet(string $user, bool $withAvatar = false): array {
// prepare default values
$domain = null;
if(Arsse::$conf->userComposeNames) $domain = substr($user,strrpos($user,"@")+1);

View file

@ -4,6 +4,7 @@ namespace JKingWeb\Arsse;
use JKingWeb\Arsse\REST\Request;
use JKingWeb\Arsse\REST\Response;
use JKingWeb\Arsse\Test\Result;
use JKingWeb\Arsse\Misc\Date;
use JKingWeb\Arsse\Misc\Context;
use JKingWeb\Arsse\Db\ExceptionInput;
use JKingWeb\Arsse\Db\Transaction;
@ -260,6 +261,7 @@ class TestNCNV1_2 extends Test\AbstractTest {
function setUp() {
$this->clearData();
Arsse::$conf = new Conf();
// create a mock user manager
Arsse::$user = Phake::mock(User::class);
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(), (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);
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/items/read/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[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")));
}
}

View 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());
}
}

View file

@ -53,5 +53,9 @@
<file>REST/NextCloudNews/TestNCNVersionDiscovery.php</file>
<file>REST/NextCloudNews/TestNCNV1_2.php</file>
</testsuite>
<testsuite name="Refresh service">
<file>Service/TestService.php</file>
</testsuite>
</testsuites>
</phpunit>