summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoas Schilling <coding@schilljs.com>2019-08-22 03:17:17 +0200
committerJoas Schilling <coding@schilljs.com>2019-11-12 17:33:50 +0100
commite96c9e0e4a402277a9f18470c77503dd914c6de4 (patch)
tree5d1442e925f976578354224abdfe4ef2b56d16b5
parentdcdbea54e60d13d2508b71ebdcb7992f2ae5ef34 (diff)
downloadnextcloud-server-e96c9e0e4a402277a9f18470c77503dd914c6de4.tar.gz
nextcloud-server-e96c9e0e4a402277a9f18470c77503dd914c6de4.zip
Add the notifier and the API endpoint for user shares
Signed-off-by: Joas Schilling <coding@schilljs.com>
-rw-r--r--apps/federatedfilesharing/lib/Notifier.php2
-rw-r--r--apps/files_sharing/appinfo/app.php1
-rw-r--r--apps/files_sharing/appinfo/routes.php5
-rw-r--r--apps/files_sharing/composer/composer/autoload_classmap.php1
-rw-r--r--apps/files_sharing/composer/composer/autoload_static.php1
-rw-r--r--apps/files_sharing/lib/AppInfo/Application.php11
-rw-r--r--apps/files_sharing/lib/Controller/ShareAPIController.php39
-rw-r--r--apps/files_sharing/lib/Notification/Listener.php72
-rw-r--r--apps/files_sharing/lib/Notification/Notifier.php105
-rw-r--r--lib/private/Share20/DefaultShareProvider.php1
10 files changed, 232 insertions, 6 deletions
diff --git a/apps/federatedfilesharing/lib/Notifier.php b/apps/federatedfilesharing/lib/Notifier.php
index 02a46d65bba..1916390a1ad 100644
--- a/apps/federatedfilesharing/lib/Notifier.php
+++ b/apps/federatedfilesharing/lib/Notifier.php
@@ -86,7 +86,7 @@ class Notifier implements INotifier {
* @throws \InvalidArgumentException
*/
public function prepare(INotification $notification, string $languageCode): INotification {
- if ($notification->getApp() !== 'files_sharing') {
+ if ($notification->getApp() !== 'files_sharing' || $notification->getObjectType() !== 'remote_share') {
// Not my app => throw
throw new \InvalidArgumentException();
}
diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php
index c4f44095dcd..8d4b511c265 100644
--- a/apps/files_sharing/appinfo/app.php
+++ b/apps/files_sharing/appinfo/app.php
@@ -38,6 +38,7 @@ use OCA\Files_Sharing\AppInfo\Application;
$application = \OC::$server->query(Application::class);
$application->registerMountProviders();
+$application->register();
$eventDispatcher = \OC::$server->getEventDispatcher();
$eventDispatcher->addListener(
diff --git a/apps/files_sharing/appinfo/routes.php b/apps/files_sharing/appinfo/routes.php
index ce7ba409199..ab5e829f86b 100644
--- a/apps/files_sharing/appinfo/routes.php
+++ b/apps/files_sharing/appinfo/routes.php
@@ -73,6 +73,11 @@ return [
'url' => '/api/v1/shares/{id}',
'verb' => 'DELETE',
],
+ [
+ 'name' => 'ShareAPI#acceptShare',
+ 'url' => '/api/v1/shares/pending/{id}',
+ 'verb' => 'POST',
+ ],
/*
* Deleted Shares
*/
diff --git a/apps/files_sharing/composer/composer/autoload_classmap.php b/apps/files_sharing/composer/composer/autoload_classmap.php
index 63c31f0a3c6..d5609a9a607 100644
--- a/apps/files_sharing/composer/composer/autoload_classmap.php
+++ b/apps/files_sharing/composer/composer/autoload_classmap.php
@@ -51,6 +51,7 @@ return array(
'OCA\\Files_Sharing\\Migration\\OwncloudGuestShareType' => $baseDir . '/../lib/Migration/OwncloudGuestShareType.php',
'OCA\\Files_Sharing\\Migration\\SetPasswordColumn' => $baseDir . '/../lib/Migration/SetPasswordColumn.php',
'OCA\\Files_Sharing\\MountProvider' => $baseDir . '/../lib/MountProvider.php',
+ 'OCA\\Files_Sharing\\Notification\\Listener' => $baseDir . '/../lib/Notification/Listener.php',
'OCA\\Files_Sharing\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php',
'OCA\\Files_Sharing\\Scanner' => $baseDir . '/../lib/Scanner.php',
'OCA\\Files_Sharing\\ShareBackend\\File' => $baseDir . '/../lib/ShareBackend/File.php',
diff --git a/apps/files_sharing/composer/composer/autoload_static.php b/apps/files_sharing/composer/composer/autoload_static.php
index 659903300c6..0975feafec2 100644
--- a/apps/files_sharing/composer/composer/autoload_static.php
+++ b/apps/files_sharing/composer/composer/autoload_static.php
@@ -66,6 +66,7 @@ class ComposerStaticInitFiles_Sharing
'OCA\\Files_Sharing\\Migration\\OwncloudGuestShareType' => __DIR__ . '/..' . '/../lib/Migration/OwncloudGuestShareType.php',
'OCA\\Files_Sharing\\Migration\\SetPasswordColumn' => __DIR__ . '/..' . '/../lib/Migration/SetPasswordColumn.php',
'OCA\\Files_Sharing\\MountProvider' => __DIR__ . '/..' . '/../lib/MountProvider.php',
+ 'OCA\\Files_Sharing\\Notification\\Listener' => __DIR__ . '/..' . '/../lib/Notification/Listener.php',
'OCA\\Files_Sharing\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php',
'OCA\\Files_Sharing\\Scanner' => __DIR__ . '/..' . '/../lib/Scanner.php',
'OCA\\Files_Sharing\\ShareBackend\\File' => __DIR__ . '/..' . '/../lib/ShareBackend/File.php',
diff --git a/apps/files_sharing/lib/AppInfo/Application.php b/apps/files_sharing/lib/AppInfo/Application.php
index bba87ba991f..92b3a92d438 100644
--- a/apps/files_sharing/lib/AppInfo/Application.php
+++ b/apps/files_sharing/lib/AppInfo/Application.php
@@ -32,6 +32,7 @@ namespace OCA\Files_Sharing\AppInfo;
use OCA\Files_Sharing\Middleware\OCSShareAPIMiddleware;
use OCA\Files_Sharing\Middleware\ShareInfoMiddleware;
use OCA\Files_Sharing\MountProvider;
+use OCA\Files_Sharing\Notification\Listener;
use OCA\Files_Sharing\Notification\Notifier;
use OCP\AppFramework\App;
use OC\AppFramework\Utility\SimpleContainer;
@@ -45,6 +46,7 @@ use \OCP\IContainer;
use OCP\IServerContainer;
use OCA\Files_Sharing\Capabilities;
use OCA\Files_Sharing\External\Manager;
+use Symfony\Component\EventDispatcher\GenericEvent;
class Application extends App {
public function __construct(array $urlParams = array()) {
@@ -178,4 +180,13 @@ class Application extends App {
$mountProviderCollection->registerProvider($this->getContainer()->query('MountProvider'));
$mountProviderCollection->registerProvider($this->getContainer()->query('ExternalMountProvider'));
}
+
+ public function register(): void {
+ $dispatcher = $this->getContainer()->getServer()->getEventDispatcher();
+ $dispatcher->addListener('OCP\Share::postShare', function(GenericEvent $event) {
+ /** @var Listener $listener */
+ $listener = $this->getContainer()->query(Listener::class);
+ $listener->shareNotification($event);
+ });
+ }
}
diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php
index 66b2383ea7d..acb95a0a3d3 100644
--- a/apps/files_sharing/lib/Controller/ShareAPIController.php
+++ b/apps/files_sharing/lib/Controller/ShareAPIController.php
@@ -947,6 +947,45 @@ class ShareAPIController extends OCSController {
}
/**
+ * @NoAdminRequired
+ *
+ * @param string $id
+ * @return DataResponse
+ * @throws OCSNotFoundException
+ * @throws OCSException
+ * @throws OCSBadRequestException
+ */
+ public function acceptShare(string $id): DataResponse {
+ try {
+ $share = $this->getShareById($id);
+ } catch (ShareNotFound $e) {
+ throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
+ }
+
+ if (!$this->canAccessShare($share, false)) {
+ throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
+ }
+
+ if ($share->getShareType() !== Share::SHARE_TYPE_USER ||
+ $share->getSharedWith() !== $this->currentUser) {
+ throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
+ }
+
+ $share->setStatus(IShare::STATUS_ACCEPTED);
+
+ try {
+ $this->shareManager->updateShare($share);
+ } catch (GenericShareException $e) {
+ $code = $e->getCode() === 0 ? 403 : $e->getCode();
+ throw new OCSException($e->getHint(), $code);
+ } catch (\Exception $e) {
+ throw new OCSBadRequestException($e->getMessage(), $e);
+ }
+
+ return new DataResponse();
+ }
+
+ /**
* Does the user have read permission on the share
*
* @param \OCP\Share\IShare $share the share to check
diff --git a/apps/files_sharing/lib/Notification/Listener.php b/apps/files_sharing/lib/Notification/Listener.php
new file mode 100644
index 00000000000..98c40f31677
--- /dev/null
+++ b/apps/files_sharing/lib/Notification/Listener.php
@@ -0,0 +1,72 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2019, Joas Schilling <coding@schilljs.com>
+ *
+ * @author Joas Schilling <coding@schilljs.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\Files_Sharing\Notification;
+
+use OC\Share\Share;
+use OCP\Notification\IManager;
+use OCP\Notification\INotification;
+use OCP\Share\IShare;
+use Symfony\Component\EventDispatcher\GenericEvent;
+
+class Listener {
+
+ /** @var IManager */
+ protected $notificationManager;
+
+ public function __construct(
+ IManager $notificationManager
+ ) {
+ $this->notificationManager = $notificationManager;
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function shareNotification(GenericEvent $event): void {
+ /** @var IShare $share */
+ $share = $event->getSubject();
+ $notification = $this->instantiateNotification($share);
+
+ if ($share->getShareType() === Share::SHARE_TYPE_USER) {
+ $notification->setSubject('incoming_user_share')
+ ->setUser($share->getSharedWith());
+ $this->notificationManager->notify($notification);
+ }
+ }
+
+ /**
+ * @param IShare $share
+ * @return INotification
+ */
+ protected function instantiateNotification(IShare $share): INotification {
+ $notification = $this->notificationManager->createNotification();
+ $notification
+ ->setApp('files_sharing')
+ ->setObject('share', $share->getFullId())
+ ->setDateTime($share->getShareTime());
+
+ return $notification;
+ }
+}
diff --git a/apps/files_sharing/lib/Notification/Notifier.php b/apps/files_sharing/lib/Notification/Notifier.php
index a9028ec9cf5..6ae009895d3 100644
--- a/apps/files_sharing/lib/Notification/Notifier.php
+++ b/apps/files_sharing/lib/Notification/Notifier.php
@@ -2,8 +2,10 @@
declare(strict_types=1);
/**
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
+ * @copyright Copyright (c) 2019, Joas Schilling <coding@schilljs.com>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -25,43 +27,70 @@ declare(strict_types=1);
namespace OCA\Files_Sharing\Notification;
use OCP\Files\IRootFolder;
+use OCP\IL10N;
+use OCP\IURLGenerator;
use OCP\L10N\IFactory;
use OCP\Notification\AlreadyProcessedException;
use OCP\Notification\INotification;
use OCP\Notification\INotifier;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager;
+use OCP\Share\IShare;
class Notifier implements INotifier {
/** @var IFactory */
protected $l10nFactory;
-
/** @var IManager */
private $shareManager;
-
/** @var IRootFolder */
private $rootFolder;
+ /** @var IURLGenerator */
+ protected $url;
+
public function __construct(IFactory $l10nFactory,
IManager $shareManager,
- IRootFolder $rootFolder) {
+ IRootFolder $rootFolder,
+ IURLGenerator $url) {
$this->l10nFactory = $l10nFactory;
$this->shareManager = $shareManager;
$this->rootFolder = $rootFolder;
+ $this->url = $url;
}
+ /**
+ * Identifier of the notifier, only use [a-z0-9_]
+ *
+ * @return string
+ * @since 17.0.0
+ */
public function getID(): string {
return 'files_sharing';
}
+ /**
+ * Human readable name describing the notifier
+ *
+ * @return string
+ * @since 17.0.0
+ */
public function getName(): string {
- return $this->l10nFactory->get('files_sharing')->t('Files sharing');
+ return $this->l10nFactory->get('files_sharing')->t('File sharing');
}
+ /**
+ * @param INotification $notification
+ * @param string $languageCode The code of the language that should be used to prepare the notification
+ * @return INotification
+ * @throws \InvalidArgumentException When the notification was not prepared by a notifier
+ * @throws AlreadyProcessedException When the notification is not needed anymore and should be deleted
+ * @since 9.0.0
+ */
public function prepare(INotification $notification, string $languageCode): INotification {
if ($notification->getApp() !== 'files_sharing' ||
- $notification->getSubject() !== 'expiresTomorrow') {
+ ($notification->getSubject() !== 'expiresTomorrow' &&
+ $notification->getObjectType() !== 'share')) {
throw new \InvalidArgumentException('Unhandled app or subject');
}
@@ -74,6 +103,15 @@ class Notifier implements INotifier {
throw new AlreadyProcessedException();
}
+ if ($notification->getSubject() === 'expiresTomorrow') {
+ $notification = $this->parseShareExpiration($share, $notification, $l);
+ } else {
+ $notification = $this->parseShareInvitation($share, $notification, $l);
+ }
+ return $notification;
+ }
+
+ protected function parseShareExpiration(IShare $share, INotification $notification, IL10N $l): INotification {
$node = $share->getNode();
$userFolder = $this->rootFolder->getUserFolder($notification->getUser());
$path = $userFolder->getRelativePath($node->getPath());
@@ -95,4 +133,61 @@ class Notifier implements INotifier {
return $notification;
}
+
+ protected function parseShareInvitation(IShare $share, INotification $notification, IL10N $l): INotification {
+ if ($share->getShareType() === IShare::TYPE_USER) {
+ if ($share->getSharedWith() !== $notification->getUser()) {
+ throw new AlreadyProcessedException();
+ }
+
+ if ($share->getStatus() !== IShare::STATUS_PENDING) {
+ throw new AlreadyProcessedException();
+ }
+ }
+
+ switch ($notification->getSubject()) {
+ case 'incoming_user_share':
+ $subject = $l->t('You received {share} as a share from {user}');
+ $subjectParameters = [
+ 'share' => [
+ 'type' => 'highlight',
+ 'id' => $notification->getObjectId(),
+ 'name' => $share->getNode()->getName(),
+ ],
+ 'user' => [
+ 'type' => 'user',
+ 'id' => $share->getShareOwner(),
+ 'name' => $share->getShareOwner(),
+ ],
+ ];
+
+ $placeholders = $replacements = [];
+ foreach ($subjectParameters as $placeholder => $parameter) {
+ $placeholders[] = '{' . $placeholder . '}';
+ $replacements[] = $parameter['name'];
+ }
+
+ $notification->setParsedSubject(str_replace($placeholders, $replacements, $subject))
+ ->setRichSubject($subject, $subjectParameters)
+ ->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/share.svg')));
+
+ $acceptAction = $notification->createAction();
+ $acceptAction->setParsedLabel($l->t('Accept'))
+ ->setLink($this->url->linkToOCSRouteAbsolute('files_sharing.ShareAPI.acceptShare', ['id' => $share->getId()]), 'POST')
+ ->setPrimary(true);
+ $notification->addParsedAction($acceptAction);
+
+ $rejectAction = $notification->createAction();
+ $rejectAction->setParsedLabel($l->t('Reject'))
+ ->setLink($this->url->linkToOCSRouteAbsolute('files_sharing.ShareAPI.deleteShare', ['id' => $share->getId()]), 'DELETE')
+ ->setPrimary(false);
+ $notification->addParsedAction($rejectAction);
+
+ return $notification;
+ break;
+
+ default:
+ throw new \InvalidArgumentException('Invalid subject');
+ }
+ }
}
diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php
index 61c62364153..66d28869dbd 100644
--- a/lib/private/Share20/DefaultShareProvider.php
+++ b/lib/private/Share20/DefaultShareProvider.php
@@ -253,6 +253,7 @@ class DefaultShareProvider implements IShareProvider {
->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
->set('note', $qb->createNamedParameter($share->getNote()))
+ ->set('accepted', $qb->createNamedParameter($share->getStatus()))
->execute();
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
$qb = $this->dbConn->getQueryBuilder();