diff --git a/lib/REST/NextCloudNews/V1_2.php b/lib/REST/NextCloudNews/V1_2.php
index 5badc2eb..5015aedb 100644
--- a/lib/REST/NextCloudNews/V1_2.php
+++ b/lib/REST/NextCloudNews/V1_2.php
@@ -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(),
]
]);
}
diff --git a/lib/Service.php b/lib/Service.php
index 2fed9a18..f5f0aab1 100644
--- a/lib/Service.php
+++ b/lib/Service.php
@@ -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 {
diff --git a/lib/User.php b/lib/User.php
index 13ab49f9..b8a89f59 100644
--- a/lib/User.php
+++ b/lib/User.php
@@ -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);
diff --git a/tests/REST/NextCloudNews/TestNCNV1_2.php b/tests/REST/NextCloudNews/TestNCNV1_2.php
index a745a564..4641a4e4 100644
--- a/tests/REST/NextCloudNews/TestNCNV1_2.php
+++ b/tests/REST/NextCloudNews/TestNCNV1_2.php
@@ -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")));
+ }
}
\ No newline at end of file
diff --git a/tests/Service/TestService.php b/tests/Service/TestService.php
new file mode 100644
index 00000000..a97516df
--- /dev/null
+++ b/tests/Service/TestService.php
@@ -0,0 +1,51 @@
+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());
+ }
+}
\ No newline at end of file
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
index 04178c48..5114ee88 100644
--- a/tests/phpunit.xml
+++ b/tests/phpunit.xml
@@ -53,5 +53,9 @@
REST/NextCloudNews/TestNCNVersionDiscovery.php
REST/NextCloudNews/TestNCNV1_2.php
+
+ Service/TestService.php
+
+
\ No newline at end of file