Browse Source

feat: wIP

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
Thomas Citharel 11 months ago
parent
commit
326e5696c9

+ 1 - 1
3rdparty

@@ -1 +1 @@
-Subproject commit 7293b4ffe86c0b48c3172bd8f180a12e0907fd60
+Subproject commit 519ea16619b9a6144250bb0f65542b61bead8cfa

+ 1 - 1
apps/dav/appinfo/info.xml

@@ -5,7 +5,7 @@
 	<name>WebDAV</name>
 	<summary>WebDAV endpoint</summary>
 	<description>WebDAV endpoint</description>
-	<version>1.28.0</version>
+	<version>1.28.1</version>
 	<licence>agpl</licence>
 	<author>owncloud.org</author>
 	<namespace>DAV</namespace>

+ 8 - 0
apps/dav/composer/composer/autoload_classmap.php

@@ -71,6 +71,8 @@ return array(
     'OCA\\DAV\\CalDAV\\PublicCalendarRoot' => $baseDir . '/../lib/CalDAV/PublicCalendarRoot.php',
     'OCA\\DAV\\CalDAV\\Publishing\\PublishPlugin' => $baseDir . '/../lib/CalDAV/Publishing/PublishPlugin.php',
     'OCA\\DAV\\CalDAV\\Publishing\\Xml\\Publisher' => $baseDir . '/../lib/CalDAV/Publishing/Xml/Publisher.php',
+    'OCA\\DAV\\CalDAV\\PushSync\\Plugin' => $baseDir . '/../lib/CalDAV/PushSync/Plugin.php',
+    'OCA\\DAV\\CalDAV\\PushSync\\Xml\\PushTransports' => $baseDir . '/../lib/CalDAV/PushSync/Xml/PushTransports.php',
     'OCA\\DAV\\CalDAV\\Reminder\\Backend' => $baseDir . '/../lib/CalDAV/Reminder/Backend.php',
     'OCA\\DAV\\CalDAV\\Reminder\\INotificationProvider' => $baseDir . '/../lib/CalDAV/Reminder/INotificationProvider.php',
     'OCA\\DAV\\CalDAV\\Reminder\\NotificationProviderManager' => $baseDir . '/../lib/CalDAV/Reminder/NotificationProviderManager.php',
@@ -203,6 +205,8 @@ return array(
     'OCA\\DAV\\DAV\\ViewOnlyPlugin' => $baseDir . '/../lib/DAV/ViewOnlyPlugin.php',
     'OCA\\DAV\\Db\\Direct' => $baseDir . '/../lib/Db/Direct.php',
     'OCA\\DAV\\Db\\DirectMapper' => $baseDir . '/../lib/Db/DirectMapper.php',
+    'OCA\\DAV\\Db\\PushKey' => $baseDir . '/../lib/Db/PushKey.php',
+    'OCA\\DAV\\Db\\PushKeyMapper' => $baseDir . '/../lib/Db/PushKeyMapper.php',
     'OCA\\DAV\\Direct\\DirectFile' => $baseDir . '/../lib/Direct/DirectFile.php',
     'OCA\\DAV\\Direct\\DirectHome' => $baseDir . '/../lib/Direct/DirectHome.php',
     'OCA\\DAV\\Direct\\Server' => $baseDir . '/../lib/Direct/Server.php',
@@ -297,9 +301,13 @@ return array(
     'OCA\\DAV\\Migration\\Version1018Date20210312100735' => $baseDir . '/../lib/Migration/Version1018Date20210312100735.php',
     'OCA\\DAV\\Migration\\Version1024Date20211221144219' => $baseDir . '/../lib/Migration/Version1024Date20211221144219.php',
     'OCA\\DAV\\Migration\\Version1027Date20230504122946' => $baseDir . '/../lib/Migration/Version1027Date20230504122946.php',
+    'OCA\\DAV\\Migration\\Version1028Date20230521143154' => $baseDir . '/../lib/Migration/Version1028Date20230521143154.php',
     'OCA\\DAV\\Profiler\\ProfilerPlugin' => $baseDir . '/../lib/Profiler/ProfilerPlugin.php',
     'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
     'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
+    'OCA\\DAV\\Push\\IPushTransport' => $baseDir . '/../lib/Push/IPushTransport.php',
+    'OCA\\DAV\\Push\\IPushTransportProvider' => $baseDir . '/../lib/Push/IPushTransportProvider.php',
+    'OCA\\DAV\\Push\\PushTransportManager' => $baseDir . '/../lib/Push/PushTransportManager.php',
     'OCA\\DAV\\RootCollection' => $baseDir . '/../lib/RootCollection.php',
     'OCA\\DAV\\Search\\ACalendarSearchProvider' => $baseDir . '/../lib/Search/ACalendarSearchProvider.php',
     'OCA\\DAV\\Search\\ContactsSearchProvider' => $baseDir . '/../lib/Search/ContactsSearchProvider.php',

+ 8 - 0
apps/dav/composer/composer/autoload_static.php

@@ -86,6 +86,8 @@ class ComposerStaticInitDAV
         'OCA\\DAV\\CalDAV\\PublicCalendarRoot' => __DIR__ . '/..' . '/../lib/CalDAV/PublicCalendarRoot.php',
         'OCA\\DAV\\CalDAV\\Publishing\\PublishPlugin' => __DIR__ . '/..' . '/../lib/CalDAV/Publishing/PublishPlugin.php',
         'OCA\\DAV\\CalDAV\\Publishing\\Xml\\Publisher' => __DIR__ . '/..' . '/../lib/CalDAV/Publishing/Xml/Publisher.php',
+        'OCA\\DAV\\CalDAV\\PushSync\\Plugin' => __DIR__ . '/..' . '/../lib/CalDAV/PushSync/Plugin.php',
+        'OCA\\DAV\\CalDAV\\PushSync\\Xml\\PushTransports' => __DIR__ . '/..' . '/../lib/CalDAV/PushSync/Xml/PushTransports.php',
         'OCA\\DAV\\CalDAV\\Reminder\\Backend' => __DIR__ . '/..' . '/../lib/CalDAV/Reminder/Backend.php',
         'OCA\\DAV\\CalDAV\\Reminder\\INotificationProvider' => __DIR__ . '/..' . '/../lib/CalDAV/Reminder/INotificationProvider.php',
         'OCA\\DAV\\CalDAV\\Reminder\\NotificationProviderManager' => __DIR__ . '/..' . '/../lib/CalDAV/Reminder/NotificationProviderManager.php',
@@ -218,6 +220,8 @@ class ComposerStaticInitDAV
         'OCA\\DAV\\DAV\\ViewOnlyPlugin' => __DIR__ . '/..' . '/../lib/DAV/ViewOnlyPlugin.php',
         'OCA\\DAV\\Db\\Direct' => __DIR__ . '/..' . '/../lib/Db/Direct.php',
         'OCA\\DAV\\Db\\DirectMapper' => __DIR__ . '/..' . '/../lib/Db/DirectMapper.php',
+        'OCA\\DAV\\Db\\PushKey' => __DIR__ . '/..' . '/../lib/Db/PushKey.php',
+        'OCA\\DAV\\Db\\PushKeyMapper' => __DIR__ . '/..' . '/../lib/Db/PushKeyMapper.php',
         'OCA\\DAV\\Direct\\DirectFile' => __DIR__ . '/..' . '/../lib/Direct/DirectFile.php',
         'OCA\\DAV\\Direct\\DirectHome' => __DIR__ . '/..' . '/../lib/Direct/DirectHome.php',
         'OCA\\DAV\\Direct\\Server' => __DIR__ . '/..' . '/../lib/Direct/Server.php',
@@ -312,9 +316,13 @@ class ComposerStaticInitDAV
         'OCA\\DAV\\Migration\\Version1018Date20210312100735' => __DIR__ . '/..' . '/../lib/Migration/Version1018Date20210312100735.php',
         'OCA\\DAV\\Migration\\Version1024Date20211221144219' => __DIR__ . '/..' . '/../lib/Migration/Version1024Date20211221144219.php',
         'OCA\\DAV\\Migration\\Version1027Date20230504122946' => __DIR__ . '/..' . '/../lib/Migration/Version1027Date20230504122946.php',
+        'OCA\\DAV\\Migration\\Version1028Date20230521143154' => __DIR__ . '/..' . '/../lib/Migration/Version1028Date20230521143154.php',
         'OCA\\DAV\\Profiler\\ProfilerPlugin' => __DIR__ . '/..' . '/../lib/Profiler/ProfilerPlugin.php',
         'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
         'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
+        'OCA\\DAV\\Push\\IPushTransport' => __DIR__ . '/..' . '/../lib/Push/IPushTransport.php',
+        'OCA\\DAV\\Push\\IPushTransportProvider' => __DIR__ . '/..' . '/../lib/Push/IPushTransportProvider.php',
+        'OCA\\DAV\\Push\\PushTransportManager' => __DIR__ . '/..' . '/../lib/Push/PushTransportManager.php',
         'OCA\\DAV\\RootCollection' => __DIR__ . '/..' . '/../lib/RootCollection.php',
         'OCA\\DAV\\Search\\ACalendarSearchProvider' => __DIR__ . '/..' . '/../lib/Search/ACalendarSearchProvider.php',
         'OCA\\DAV\\Search\\ContactsSearchProvider' => __DIR__ . '/..' . '/../lib/Search/ContactsSearchProvider.php',

+ 79 - 0
apps/dav/lib/CalDAV/PushSync/Plugin.php

@@ -0,0 +1,79 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2023 Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\DAV\CalDAV\PushSync;
+
+use Closure;
+use OCA\DAV\CalDAV\Calendar;
+use OCA\DAV\CalDAV\CalendarHome;
+use OCA\DAV\CalDAV\PushSync\Xml\PushTransports;
+use OCA\DAV\Db\PushKeyMapper;
+use OCA\DAV\Push\IPushTransportProvider;
+use OCA\DAV\Push\PushTransportManager;
+use Sabre\DAV\INode;
+use Sabre\DAV\PropFind;
+use Sabre\DAV\Server;
+use Sabre\DAV\ServerPlugin;
+
+class Plugin extends ServerPlugin {
+	public const NS_CALENDARSERVER = 'http://calendarserver.org/ns/';
+	public const PROPERTY_PUSH_TRANSPORTS = '{' . self::NS_CALENDARSERVER . '}push-transports';
+	public const PROPERTY_PUSHKEY = '{' . self::NS_CALENDARSERVER . '}pushkey';
+
+	public function __construct(private PushKeyMapper $pushKeyMapper, private PushTransportManager $pushTransportManager) { }
+
+	public function initialize(Server $server): void {
+		$server->on('propFind', Closure::fromCallable([$this, 'propFind']));
+	}
+
+	private function propFind(
+		PropFind $propFind,
+		INode $node): void {
+		if ($node instanceof CalendarHome) {
+			$pushTransportProviders = $this->pushTransportManager->getPushTransportProviders();
+			$propFind->handle(self::PROPERTY_PUSH_TRANSPORTS, function () use ($node, $pushTransportProviders) {
+				return new PushTransports(array_map(function (IPushTransportProvider $pushTransportProvider) {
+					return $pushTransportProvider->getPushTransport();
+				}, $pushTransportProviders));
+			});
+			$propFind->handle(self::PROPERTY_PUSHKEY, function () use ($node) {
+				return $this->pushKeyMapper->getForPrincipal($node->getOwner());
+			});
+		}
+		if ($node instanceof Calendar) {
+			$propFind->handle(self::PROPERTY_PUSHKEY, function () use ($node) {
+				return $this->pushKeyMapper->getForUri($node->getOwner(), $node->getName());
+			});
+		}
+	}
+
+	public function getFeatures(): array {
+		return ['nc-calendar-push-sync'];
+	}
+
+	public function getPluginName(): string {
+		return 'nc-calendar-push-sync';
+	}
+}

+ 90 - 0
apps/dav/lib/CalDAV/PushSync/Xml/PushTransports.php

@@ -0,0 +1,90 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2023 Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\CalDAV\PushSync\Xml;
+
+use OCA\DAV\CalDAV\PushSync\Plugin;
+use OCA\DAV\Push\IPushTransport;
+use Sabre\Xml\Writer;
+use Sabre\Xml\XmlSerializable;
+
+
+class PushTransports implements XmlSerializable {
+
+	/** @var IPushTransport[] */
+	private array $pushTransports;
+
+	public function __construct(array $pushTransports) {
+		$this->pushTransports = $pushTransports;
+	}
+
+	public function getValue(): array {
+		return $this->pushTransports;
+	}
+
+	/**
+	 * The xmlSerialize method is called during xml writing.
+	 *
+	 * Use the $writer argument to write its own xml serialization.
+	 *
+	 * An important note: do _not_ create a parent element. Any element
+	 * implementing XmlSerializble should only ever write what's considered
+	 * its 'inner xml'.
+	 *
+	 * The parent of the current element is responsible for writing a
+	 * containing element.
+	 *
+	 * This allows serializers to be re-used for different element names.
+	 *
+	 * If you are opening new elements, you must also close them again.
+	 *
+	 * @param Writer $writer
+	 * @return void
+	 */
+	public function xmlSerialize(Writer $writer): void {
+		// $cs = '{' . Plugin::NS_CALENDARSERVER . '}';
+
+		if (count($this->pushTransports) <= 0) return;
+
+		//$writer->startElement($cs . 'push-transports');
+
+		foreach ($this->pushTransports as $pushTransport) {
+			$pushTransport->xmlSerialize($writer);
+
+//			$writer->startElement($cs . 'transport');
+//			$writer->writeAttribute('type', 'whatever');
+//
+//			$writer->startElement($cs . 'subscription-url');
+//			$writer->writeElement('{DAV:}href', $pushTransport->getSubscriptionUrl());
+//			$writer->endElement();
+//
+//			$writer->writeElement('apsbundleid', 'whatever');
+//			$writer->writeElement('env', 'whatever');
+//			$writer->writeElement('refresh-interval', $pushTransport->getRefreshInterval());
+//
+//			$writer->endElement(); // transport
+		}
+		// $writer->endElement();
+	}
+}

+ 48 - 0
apps/dav/lib/Db/PushKey.php

@@ -0,0 +1,48 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2023 Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\DAV\Db;
+
+use OCP\AppFramework\Db\Entity;
+
+/**
+ * @method string getPrincipalUri()
+ * @method void setPrincipalUri(string $principalUri)
+ * @method string getUri()
+ * @method void setUri(string $principalUri)
+ * @method string getPushKey()
+ * @method void setPushKey(string $pushKey)
+ */
+class PushKey extends Entity {
+	protected ?string $principalUri = null;
+	protected ?string $uri = null;
+	protected ?string $pushKey = null;
+
+	public function __construct() {
+		$this->addType('principalUri', 'string');
+		$this->addType('uri', 'string');
+		$this->addType('pushKey', 'string');
+	}
+}

+ 75 - 0
apps/dav/lib/Db/PushKeyMapper.php

@@ -0,0 +1,75 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2023 Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\DAV\Db;
+
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Db\QBMapper;
+use OCP\IDBConnection;
+
+/**
+ * @template-extends QBMapper<PushKey>
+ */
+class PushKeyMapper extends QBMapper {
+	public function __construct(IDBConnection $db) {
+		parent::__construct($db, 'push_transports', PushKey::class);
+	}
+
+	/**
+	 * @return PushKey[]
+	 * @throws DoesNotExistException
+	 */
+	public function getForPrincipal(string $principalUri): array {
+		$qb = $this->db->getQueryBuilder();
+
+		$qb->select('*')
+			->from($this->getTableName())
+			->where(
+				$qb->expr()->eq('principalUri', $qb->createNamedParameter($principalUri))
+			)
+			->andWhere($qb->expr()->eq('uri', $qb->createNamedParameter(null)))
+		;
+
+		return parent::findEntities($qb);
+	}
+
+	/**
+	 * @return PushKey[]
+	 * @throws DoesNotExistException
+	 */
+	public function getForUri(string $principalUri, string $uri): array {
+		$qb = $this->db->getQueryBuilder();
+
+		$qb->select('*')
+			->from($this->getTableName())
+			->where(
+				$qb->expr()->eq('principalUri', $qb->createNamedParameter($principalUri))
+			)
+			->andWhere($qb->expr()->eq('uri', $qb->createNamedParameter($uri)))
+		;
+
+		return parent::findEntities($qb);
+	}
+}

+ 72 - 0
apps/dav/lib/Listener/PushListener.php

@@ -0,0 +1,72 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\DAV\Listener;
+
+use OCA\DAV\Db\PushKeyMapper;
+use OCA\DAV\Events\CalendarObjectCreatedEvent;
+use OCA\DAV\Events\CalendarObjectUpdatedEvent;
+use OCA\DAV\Events\CardCreatedEvent;
+use OCA\DAV\Events\CardDeletedEvent;
+use OCA\DAV\Events\CardUpdatedEvent;
+use OCA\DAV\Push\PushTransportManager;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+
+class PushListener implements IEventListener {
+
+	public function __construct(private PushTransportManager $pushTransportManager, private PushKeyMapper $pushKeyMapper) {
+	}
+
+	public function handle(Event $event): void {
+		if ($event instanceof CalendarObjectCreatedEvent || $event instanceof CalendarObjectUpdatedEvent) {
+			$data = $event->getCalendarData();
+			$this->notify($data['uri'], $data['principaluri']);
+
+		} elseif ($event instanceof CardCreatedEvent || $event instanceof CardUpdatedEvent || $event instanceof CardDeletedEvent) {
+			$data = $event->getAddressBookData();
+			$this->notify($data['uri'], $data['principaluri']);
+		}
+	}
+
+	/**
+	 * @return string[]
+	 */
+	private function pushKeysForData(string $principalUri, string $uri): array {
+		$pushKeys = [];
+		$pushKeys[] = $this->pushKeyMapper->getForPrincipal($principalUri);
+		$pushKeys[] = $this->pushKeyMapper->getForUri($principalUri, $uri);
+		return $pushKeys;
+	}
+
+	private function notify(string $principalUri, string $uri): array {
+		$pushKeys = $this->pushKeysForData($principalUri, $uri);
+		foreach ($pushKeys as $pushKey) {
+			foreach ($this->pushTransportManager->getPushTransportProviders() as $pushTransportProvider) {
+				$pushTransportProvider->davNotify($pushKey);
+			}
+		}
+	}
+}

+ 90 - 0
apps/dav/lib/Migration/Version1028Date20230521143154.php

@@ -0,0 +1,90 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Your name <your@email.com>
+ *
+ * @author Your name <your@email.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\DAV\Migration;
+
+use Closure;
+use OCP\DB\ISchemaWrapper;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+/**
+ * Auto-generated migration step: Please modify to your needs!
+ */
+class Version1028Date20230521143154 extends SimpleMigrationStep {
+
+	/**
+	 * @param IOutput $output
+	 * @param Closure(): ISchemaWrapper $schemaClosure
+	 * @param array $options
+	 */
+	public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
+	}
+
+	/**
+	 * @param IOutput $output
+	 * @param Closure(): ISchemaWrapper $schemaClosure
+	 * @param array $options
+	 * @return null|ISchemaWrapper
+	 */
+	public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
+		/** @var ISchemaWrapper $schema */
+		$schema = $schemaClosure();
+
+		if (!$schema->hasTable('dav_pushkeys')) {
+			$table = $schema->createTable('dav_pushkeys');
+			$table->addColumn('id', 'integer', [
+				'autoincrement' => true,
+				'notnull' => true,
+			]);
+			$table->addColumn('principalUri', 'string', [
+				'notnull' => true,
+				'length' => 200
+			]);
+			$table->addColumn('uri', 'string', [
+				'notnull' => false,
+				'length' => 200
+			]);
+			$table->addColumn('pushKey', 'string', [
+				'notnull' => true,
+				'length' => 200
+			]);
+
+			$table->setPrimaryKey(['id']);
+			$table->addUniqueIndex(['principalUri']);
+			$table->addUniqueIndex(['principalUri', 'uri']);
+		}
+		return $schema;
+	}
+
+	/**
+	 * @param IOutput $output
+	 * @param Closure(): ISchemaWrapper $schemaClosure
+	 * @param array $options
+	 */
+	public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
+	}
+}

+ 34 - 0
apps/dav/lib/Push/IPushTransport.php

@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023, Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Push;
+
+use Sabre\Xml\XmlSerializable;
+
+/**
+ * @since 28.0.0
+ */
+interface IPushTransport extends XmlSerializable {
+
+}

+ 37 - 0
apps/dav/lib/Push/IPushTransportProvider.php

@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023, Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Push;
+
+
+use OCP\Push\IProvider;
+
+/**
+ * @since 28.0.0
+ */
+interface IPushTransportProvider extends IProvider {
+
+	public function davNotify(string $pushKey): void;
+	public function getPushTransport(): IPushTransport;
+}

+ 50 - 0
apps/dav/lib/Push/PushTransportManager.php

@@ -0,0 +1,50 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023, Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Push;
+
+
+use OCP\Push\IManager;
+
+/**
+ * @since 28.0.0
+ */
+class PushTransportManager {
+	private array $pushTransportProviders = [];
+
+	public function __construct(IManager $pushManager) {
+		$this->pushTransportProviders = array_filter($pushManager->getPushNotifierServices(), function ($pushNotifierService) {
+			return $pushNotifierService instanceof IPushTransportProvider;
+		});
+	}
+
+	/**
+	 * @return IPushTransportProvider[]
+	 */
+	public function getPushTransportProviders(): array
+	{
+		return $this->pushTransportProviders;
+	}
+
+}

+ 1 - 0
apps/dav/lib/Server.php

@@ -181,6 +181,7 @@ class Server {
 			}
 
 			$this->server->addPlugin(\OC::$server->get(\OCA\DAV\CalDAV\Trashbin\Plugin::class));
+			$this->server->addPlugin(\OC::$server->get(\OCA\DAV\CalDAV\PushSync\Plugin::class));
 			$this->server->addPlugin(new \OCA\DAV\CalDAV\WebcalCaching\Plugin($request));
 			if (\OC::$server->getConfig()->getAppValue('dav', 'allow_calendar_link_subscriptions', 'yes') === 'yes') {
 				$this->server->addPlugin(new \Sabre\CalDAV\Subscriptions\Plugin());

+ 10 - 0
lib/composer/composer/autoload_classmap.php

@@ -548,6 +548,12 @@ return array(
     'OCP\\Profile\\ParameterDoesNotExistException' => $baseDir . '/lib/public/Profile/ParameterDoesNotExistException.php',
     'OCP\\Profiler\\IProfile' => $baseDir . '/lib/public/Profiler/IProfile.php',
     'OCP\\Profiler\\IProfiler' => $baseDir . '/lib/public/Profiler/IProfiler.php',
+    'OCP\\Push\\IDeferrableProvider' => $baseDir . '/lib/public/Push/IDeferrableProvider.php',
+    'OCP\\Push\\IManager' => $baseDir . '/lib/public/Push/IManager.php',
+    'OCP\\Push\\IProvider' => $baseDir . '/lib/public/Push/IProvider.php',
+    'OCP\\Push\\IPush' => $baseDir . '/lib/public/Push/IPush.php',
+    'OCP\\Push\\IPushNotification' => $baseDir . '/lib/public/Push/IPushNotification.php',
+    'OCP\\Push\\IPushNotificationSentReport' => $baseDir . '/lib/public/Push/IPushNotificationSentReport.php',
     'OCP\\Remote\\Api\\IApiCollection' => $baseDir . '/lib/public/Remote/Api/IApiCollection.php',
     'OCP\\Remote\\Api\\IApiFactory' => $baseDir . '/lib/public/Remote/Api/IApiFactory.php',
     'OCP\\Remote\\Api\\ICapabilitiesApi' => $baseDir . '/lib/public/Remote/Api/ICapabilitiesApi.php',
@@ -1523,6 +1529,10 @@ return array(
     'OC\\Profiler\\Profile' => $baseDir . '/lib/private/Profiler/Profile.php',
     'OC\\Profiler\\Profiler' => $baseDir . '/lib/private/Profiler/Profiler.php',
     'OC\\Profiler\\RoutingDataCollector' => $baseDir . '/lib/private/Profiler/RoutingDataCollector.php',
+    'OC\\Push\\Manager' => $baseDir . '/lib/private/Push/Manager.php',
+    'OC\\Push\\Push' => $baseDir . '/lib/private/Push/Push.php',
+    'OC\\Push\\PushNotification' => $baseDir . '/lib/private/Push/PushNotification.php',
+    'OC\\Push\\PushNotificationSentReport' => $baseDir . '/lib/private/Push/PushNotificationSentReport.php',
     'OC\\RedisFactory' => $baseDir . '/lib/private/RedisFactory.php',
     'OC\\Remote\\Api\\ApiBase' => $baseDir . '/lib/private/Remote/Api/ApiBase.php',
     'OC\\Remote\\Api\\ApiCollection' => $baseDir . '/lib/private/Remote/Api/ApiCollection.php',

+ 10 - 0
lib/composer/composer/autoload_static.php

@@ -581,6 +581,12 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
         'OCP\\Profile\\ParameterDoesNotExistException' => __DIR__ . '/../../..' . '/lib/public/Profile/ParameterDoesNotExistException.php',
         'OCP\\Profiler\\IProfile' => __DIR__ . '/../../..' . '/lib/public/Profiler/IProfile.php',
         'OCP\\Profiler\\IProfiler' => __DIR__ . '/../../..' . '/lib/public/Profiler/IProfiler.php',
+        'OCP\\Push\\IDeferrableProvider' => __DIR__ . '/../../..' . '/lib/public/Push/IDeferrableProvider.php',
+        'OCP\\Push\\IManager' => __DIR__ . '/../../..' . '/lib/public/Push/IManager.php',
+        'OCP\\Push\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Push/IProvider.php',
+        'OCP\\Push\\IPush' => __DIR__ . '/../../..' . '/lib/public/Push/IPush.php',
+        'OCP\\Push\\IPushNotification' => __DIR__ . '/../../..' . '/lib/public/Push/IPushNotification.php',
+        'OCP\\Push\\IPushNotificationSentReport' => __DIR__ . '/../../..' . '/lib/public/Push/IPushNotificationSentReport.php',
         'OCP\\Remote\\Api\\IApiCollection' => __DIR__ . '/../../..' . '/lib/public/Remote/Api/IApiCollection.php',
         'OCP\\Remote\\Api\\IApiFactory' => __DIR__ . '/../../..' . '/lib/public/Remote/Api/IApiFactory.php',
         'OCP\\Remote\\Api\\ICapabilitiesApi' => __DIR__ . '/../../..' . '/lib/public/Remote/Api/ICapabilitiesApi.php',
@@ -1556,6 +1562,10 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
         'OC\\Profiler\\Profile' => __DIR__ . '/../../..' . '/lib/private/Profiler/Profile.php',
         'OC\\Profiler\\Profiler' => __DIR__ . '/../../..' . '/lib/private/Profiler/Profiler.php',
         'OC\\Profiler\\RoutingDataCollector' => __DIR__ . '/../../..' . '/lib/private/Profiler/RoutingDataCollector.php',
+        'OC\\Push\\Manager' => __DIR__ . '/../../..' . '/lib/private/Push/Manager.php',
+        'OC\\Push\\Push' => __DIR__ . '/../../..' . '/lib/private/Push/Push.php',
+        'OC\\Push\\PushNotification' => __DIR__ . '/../../..' . '/lib/private/Push/PushNotification.php',
+        'OC\\Push\\PushNotificationSentReport' => __DIR__ . '/../../..' . '/lib/private/Push/PushNotificationSentReport.php',
         'OC\\RedisFactory' => __DIR__ . '/../../..' . '/lib/private/RedisFactory.php',
         'OC\\Remote\\Api\\ApiBase' => __DIR__ . '/../../..' . '/lib/private/Remote/Api/ApiBase.php',
         'OC\\Remote\\Api\\ApiCollection' => __DIR__ . '/../../..' . '/lib/private/Remote/Api/ApiCollection.php',

+ 17 - 0
lib/private/AppFramework/Bootstrap/RegistrationContext.php

@@ -137,6 +137,8 @@ class RegistrationContext {
 	/** @var ServiceRegistration<IReferenceProvider>[] */
 	private array $referenceProviders = [];
 
+	private array $pushNotifierServices = [];
+
 
 
 
@@ -372,6 +374,10 @@ class RegistrationContext {
 					$class
 				);
 			}
+
+			public function registerPushNotifierProvider(string $class): void {
+				$this->context->registerPushNotifierProvider($this->appId, $class);
+			}
 		};
 	}
 
@@ -523,6 +529,10 @@ class RegistrationContext {
 		$this->publicShareTemplateProviders[] = new ServiceRegistration($appId, $class);
 	}
 
+	public function registerPushNotifierProvider(string $appId, string $class): void {
+		$this->pushNotifierServices[] = new ServiceRegistration($appId, $class);
+	}
+
 	/**
 	 * @param App[] $apps
 	 */
@@ -828,4 +838,11 @@ class RegistrationContext {
 	public function getPublicShareTemplateProviders(): array {
 		return $this->publicShareTemplateProviders;
 	}
+
+	/**
+	 * @return ServiceRegistration<\OCP\Push\IProvider>[]
+	 */
+	public function getPushNotifierServices(): array {
+		return $this->pushNotifierServices;
+	}
 }

+ 76 - 0
lib/private/Push/Manager.php

@@ -0,0 +1,76 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023, Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Push;
+
+use OC\AppFramework\Bootstrap\Coordinator;
+use OCP\Push\IManager;
+use OCP\Push\IProvider;
+use Psr\Container\ContainerExceptionInterface;
+use Psr\Log\LoggerInterface;
+
+/**
+ * @since 28.0.0
+ */
+class Manager implements IManager {
+
+	public function __construct(private LoggerInterface $logger, private Coordinator $coordinator) { }
+
+	/**
+	 * @return IProvider[]
+	 */
+	public function getPushNotifierServices(): array {
+		$notifierServices = [];
+
+		$notifierServiceRegistrations = $this->coordinator->getRegistrationContext()->getPushNotifierServices();
+
+		if (empty($notifierServiceRegistrations)) {
+			return $notifierServices;
+		}
+
+		foreach ($notifierServiceRegistrations as $notifierServiceRegistration) {
+			$serviceClass = $notifierServiceRegistration->getService();
+			try {
+				$notifierService = \OC::$server->get($serviceClass);
+			} catch (ContainerExceptionInterface $e) {
+				$this->logger->error('Failed to load push notification service class: ' . $serviceClass, [
+					'exception' => $e,
+					'app' => 'notifications',
+				]);
+				continue;
+			}
+
+			if (!($notifierService instanceof IProvider)) {
+				$this->logger->error('Push notification notifier class ' . $serviceClass . ' is not implementing ' . IProvider::class, [
+					'app' => 'notifications',
+				]);
+				continue;
+			}
+
+			$notifierServices[] = $notifierService;
+		}
+
+		return $notifierServices;
+	}
+}

+ 60 - 0
lib/private/Push/Push.php

@@ -0,0 +1,60 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023, Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Push;
+
+use OCP\IUser;
+use OCP\Push\IProvider;
+use OCP\Push\IPush;
+use OCP\Push\IPushNotification;
+
+/**
+ * @since 28.0.0
+ */
+class Push implements IPush {
+
+	/** @var IProvider[] */
+	private array $pushNotificationServices;
+
+	public function __construct(private Manager $manager) {
+		$this->pushNotificationServices = $this->manager->getPushNotifierServices();
+	}
+
+	public function createNotification(IUser $user, string $payload): IPushNotification {
+
+	}
+
+
+	public function queueNotification(IPushNotification $pushNotification): array {
+		return array_map(function ($service) use ($pushNotification) {
+			return $service->queueNotification($pushNotification);
+		}, $this->pushNotificationServices);
+	}
+
+	public function queueNotifications(array $pushNotifications, \Closure $report): void {
+		foreach ($this->pushNotificationServices as $service) {
+			$service->queueNotifications($pushNotifications, $report);
+		}
+	}
+}

+ 74 - 0
lib/private/Push/PushNotification.php

@@ -0,0 +1,74 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023, Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Push;
+
+use OCP\Push\IPushNotification;
+
+/**
+ * @since 28.0.0
+ */
+class PushNotification implements IPushNotification {
+
+	private string $endpoint;
+	private string $publicKey;
+	private string $authToken;
+	private string $payload;
+
+	public function getEndpoint(): string {
+		return $this->endpoint;
+	}
+
+	public function setEndpoint(string $endpoint): PushNotification {
+		$this->endpoint = $endpoint;
+		return $this;
+	}
+
+	public function getPublicKey(): string {
+		return $this->publicKey;
+	}
+
+	public function setPublicKey(string $publicKey): PushNotification {
+		$this->publicKey = $publicKey;
+		return $this;
+	}
+
+	public function getAuthToken(): string {
+		return $this->authToken;
+	}
+
+	public function setAuthToken(string $authToken): PushNotification {
+		$this->authToken = $authToken;
+		return $this;
+	}
+
+	public function getPayload(): string {
+		return $this->payload;
+	}
+
+	public function setPayload(string $payload): PushNotification {
+		$this->payload = $payload;
+		return $this;
+	}
+}

+ 33 - 0
lib/private/Push/PushNotificationSentReport.php

@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023, Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Push;
+
+use Minishlink\WebPush\MessageSentReport;
+use OCP\Push\IPushNotificationSentReport;
+
+/**
+ * @since 28.0.0
+ */
+class PushNotificationSentReport extends MessageSentReport implements IPushNotificationSentReport {}

+ 2 - 0
lib/private/Server.php

@@ -1414,6 +1414,8 @@ class Server extends ServerContainer implements IServerContainer {
 
 		$this->registerAlias(\OCP\TextProcessing\IManager::class, \OC\TextProcessing\Manager::class);
 
+		$this->registerAlias(\OCP\Push\IManager::class, \OC\Push\Manager::class);
+
 		$this->connectDispatcher();
 	}
 

+ 10 - 0
lib/public/AppFramework/Bootstrap/IRegistrationContext.php

@@ -371,4 +371,14 @@ interface IRegistrationContext {
 	 * @since 26.0.0
 	 */
 	public function registerPublicShareTemplateProvider(string $class): void;
+
+	/**
+	 * Register an implementation of Push\IProvider.
+	 *
+	 * @param string $class
+	 * @psalm-param class-string<\OCP\Push\IProvider> $class
+	 * @return void
+	 * @since 28.0.0
+	 */
+	public function registerPushNotifierProvider(string $class): void;
 }

+ 33 - 0
lib/public/Push/IDeferrableProvider.php

@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023, Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Push;
+
+/**
+ * @since 28.0.0
+ */
+interface IDeferrableProvider extends IProvider {
+	public function defer(): void;
+	public function flush(): void;
+}

+ 32 - 0
lib/public/Push/IManager.php

@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023, Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Push;
+
+/**
+ * @since 28.0.0
+ */
+interface IManager {
+	public function getPushNotifierServices(): array;
+}

+ 36 - 0
lib/public/Push/IProvider.php

@@ -0,0 +1,36 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023, Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Push;
+
+/**
+ * @since 28.0.0
+ */
+interface IProvider {
+	public function notify(IPushNotification $notification): void;
+
+	public function queueNotification(IPushNotification $pushNotification): IPushNotificationSentReport;
+
+	public function queueNotifications(array $pushNotifications, \Closure $report): void;
+}

+ 38 - 0
lib/public/Push/IPush.php

@@ -0,0 +1,38 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023, Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Push;
+
+/**
+ * @since 28.0.0
+ */
+interface IPush {
+
+	/**
+	 * @return IPushNotificationSentReport[]
+	 */
+	public function queueNotification(IPushNotification $pushNotification): array;
+
+	public function queueNotifications(array $pushNotifications, \Closure $report): void;
+}

+ 35 - 0
lib/public/Push/IPushNotification.php

@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023, Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Push;
+
+/**
+ * @since 28.0.0
+ */
+interface IPushNotification {
+	public function getEndpoint(): string;
+	public function getPublicKey(): string;
+	public function getAuthToken(): string;
+	public function getPayload(): string;
+}

+ 34 - 0
lib/public/Push/IPushNotificationSentReport.php

@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023, Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP\Push;
+
+/**
+ * @since 28.0.0
+ */
+interface IPushNotificationSentReport {
+	public function isSuccess(): bool;
+	public function getReason(): string;
+	public function getResponseContent(): ?string;
+}