df4e2dddec
Portable occ-based config, OCS endpoints for APK registration, notification relay, and server-side push dispatch.
147 lines
3.5 KiB
PHP
147 lines
3.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace OCA\F7Push\Service;
|
|
|
|
use OCA\F7Push\Db\Device;
|
|
use OCA\F7Push\Db\DeviceMapper;
|
|
use OCA\F7Push\Model\PushMessage;
|
|
use OCP\AppFramework\Db\DoesNotExistException;
|
|
use OCP\AppFramework\Utility\ITimeFactory;
|
|
use OCP\Notification\INotification;
|
|
use Psr\Log\LoggerInterface;
|
|
|
|
class PushDispatcher {
|
|
public function __construct(
|
|
private DeviceMapper $deviceMapper,
|
|
private FirebaseClient $firebaseClient,
|
|
private ConfigService $config,
|
|
private ITimeFactory $timeFactory,
|
|
private LoggerInterface $logger,
|
|
) {
|
|
}
|
|
|
|
public function registerDevice(
|
|
string $userId,
|
|
string $deviceId,
|
|
string $fcmToken,
|
|
string $platform,
|
|
string $clientApp,
|
|
): Device {
|
|
$now = $this->timeFactory->getTime();
|
|
try {
|
|
$device = $this->deviceMapper->findByUserAndDevice($userId, $deviceId);
|
|
$device->setFcmToken($fcmToken);
|
|
$device->setPlatform($platform);
|
|
$device->setClientApp($clientApp);
|
|
$device->setLastSeen($now);
|
|
return $this->deviceMapper->update($device);
|
|
} catch (DoesNotExistException) {
|
|
$device = new Device();
|
|
$device->setUserId($userId);
|
|
$device->setDeviceId($deviceId);
|
|
$device->setFcmToken($fcmToken);
|
|
$device->setPlatform($platform);
|
|
$device->setClientApp($clientApp);
|
|
$device->setCreatedAt($now);
|
|
$device->setLastSeen($now);
|
|
return $this->deviceMapper->insert($device);
|
|
}
|
|
}
|
|
|
|
public function unregisterDevice(string $userId, string $deviceId): void {
|
|
$this->deviceMapper->deleteByUserAndDevice($userId, $deviceId);
|
|
}
|
|
|
|
/**
|
|
* @return Device[]
|
|
*/
|
|
public function listDevices(string $userId): array {
|
|
return $this->deviceMapper->findByUser($userId);
|
|
}
|
|
|
|
public function dispatch(PushMessage $message): int {
|
|
if (!$this->config->isEnabled()) {
|
|
return 0;
|
|
}
|
|
if (!$this->config->isSourceEnabled($message->source)) {
|
|
return 0;
|
|
}
|
|
|
|
$devices = $this->deviceMapper->findByUser($message->userId);
|
|
if ($devices === []) {
|
|
return 0;
|
|
}
|
|
|
|
$url = $message->url ?? $this->config->getDefaultClickUrl();
|
|
$sent = 0;
|
|
foreach ($devices as $device) {
|
|
$token = $device->getFcmToken();
|
|
if ($token === '') {
|
|
continue;
|
|
}
|
|
if ($this->firebaseClient->sendToToken($token, $message->title, $message->body, $url, $message->priority)) {
|
|
$sent++;
|
|
}
|
|
}
|
|
|
|
$this->logger->debug('f7push: dispatched push', [
|
|
'app' => 'f7push',
|
|
'user' => $message->userId,
|
|
'source' => $message->source,
|
|
'sent' => $sent,
|
|
'devices' => count($devices),
|
|
]);
|
|
|
|
return $sent;
|
|
}
|
|
|
|
public function dispatchFromNotification(INotification $notification): int {
|
|
if (!$this->config->listenNotifications()) {
|
|
return 0;
|
|
}
|
|
|
|
$user = $notification->getUser();
|
|
if ($user === null || $user === '') {
|
|
return 0;
|
|
}
|
|
|
|
$source = $notification->getApp();
|
|
if (!$this->config->isSourceEnabled($source)) {
|
|
return 0;
|
|
}
|
|
|
|
$title = $notification->getParsedSubject();
|
|
if ($title === '') {
|
|
$title = $notification->getSubject();
|
|
}
|
|
$body = $notification->getParsedMessage();
|
|
if ($body === '') {
|
|
$body = $notification->getMessage();
|
|
}
|
|
if ($title === '' && $body === '') {
|
|
return 0;
|
|
}
|
|
if ($title === '') {
|
|
$title = $body;
|
|
}
|
|
|
|
$link = $notification->getLink();
|
|
if ($link !== '' && !str_starts_with($link, 'http://') && !str_starts_with($link, 'https://')) {
|
|
$link = $this->config->getDefaultClickUrl() . $link;
|
|
}
|
|
|
|
$priority = $source === 'spreed' ? 'high' : 'normal';
|
|
|
|
return $this->dispatch(new PushMessage(
|
|
userId: $user,
|
|
title: $title,
|
|
body: $body,
|
|
source: $source,
|
|
priority: $priority,
|
|
url: $link !== '' ? $link : null,
|
|
));
|
|
}
|
|
}
|