owncloud/core

View on GitHub
apps/files_sharing/lib/Service/NotificationPublisher.php

Summary

Maintainability
A
2 hrs
Test Coverage
<?php
/**
 * @author Vincent Petry <pvince81@owncloud.com>
 *
 * @copyright Copyright (c) 2018, ownCloud GmbH
 * @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\Files_Sharing\Service;

use OCP\IURLGenerator;
use OCP\IUserManager;
use OCP\IGroupManager;
use OCP\Share\IShare;

class NotificationPublisher {
    /** @var \OCP\Notification\IManager */
    private $notificationManager;
    /** @var IGroupManager */
    private $groupManager;
    /** @var IUserManager */
    private $userManager;
    /** @var IURLGenerator */
    private $urlGenerator;

    public function __construct(
        \OCP\Notification\IManager $notificationManager,
        IUserManager $userManager,
        IGroupManager $groupManager,
        IURLGenerator $urlGenerator
    ) {
        $this->notificationManager = $notificationManager;
        $this->userManager = $userManager;
        $this->groupManager = $groupManager;
        $this->urlGenerator = $urlGenerator;
    }

    private function getAffectedUsers(IShare $share) {
        $users = [];
        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
            // notify all group members
            $group = $this->groupManager->get($share->getSharedWith());
            // TODO: scale / chunk / ...
            foreach ($group->getUsers() as $user) {
                if ($user->getUID() !== $share->getShareOwner() && $user->getUID() !== $share->getSharedBy()) {
                    yield $user->getUID();
                }
            }
        } elseif ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
            yield $share->getSharedWith();
        }
    }

    /**
     * Send notification for accepting share
     * The notification will be sent if the share type is either user or group (not link, for example)
     * and only for pending shares (if the share has a different status the notification won't be sent)
     *
     * @param IShare $share share
     */
    public function sendNotification(IShare $share) {
        if ($share->getShareType() !== \OCP\Share::SHARE_TYPE_USER &&
            $share->getShareType() !== \OCP\Share::SHARE_TYPE_GROUP) {
            return;
        }

        if ($share->getState() !== \OCP\Share::STATE_PENDING) {
            return;
        }

        $fileLink = $this->urlGenerator->linkToRoute('files.viewcontroller.showFile', ['fileId' => $share->getNode()->getId()]);
        $endpointUrl = $this->urlGenerator->linkTo('', 'ocs/v1.php/apps/files_sharing/api/v1/shares/pending/' . $share->getId());

        foreach ($this->getAffectedUsers($share) as $userId) {
            $notification = $this->notificationManager->createNotification();
            $notification->setApp('files_sharing')
                ->setUser($userId)
                ->setDateTime(new \DateTime())
                ->setObject('local_share', $share->getFullId());
            // the fullId is used here to be able to retrieve the share using the core's share manager
            // in case we need to retrieve the share object from the notification.
            // it can be used later to discard the notification if the share isn't valid any longer.

            $notification->setIcon(
                $this->urlGenerator->imagePath('core', 'actions/shared.svg')
            );
            $notification->setLink($fileLink);

            $notification->setSubject('local_share', [$share->getShareOwner(), $share->getSharedBy(), $share->getNode()->getName()]);
            $notification->setMessage('local_share', [$share->getShareOwner(), $share->getSharedBy(), $share->getNode()->getName()]);

            $declineAction = $notification->createAction();
            $declineAction->setLabel('decline');
            $declineAction->setLink($endpointUrl, 'DELETE');
            $notification->addAction($declineAction);

            $acceptAction = $notification->createAction();
            $acceptAction->setLabel('accept');
            $acceptAction->setLink($endpointUrl, 'POST');
            $acceptAction->setPrimary(true);
            $notification->addAction($acceptAction);

            $this->notificationManager->notify($notification);
        }
    }

    /**
     * Discards all notification related to the given share.
     * This is useful to cancel notifications in case said share
     * is being deleted
     *
     * @param IShare $share share
     */
    public function discardNotification(IShare $share) {
        foreach ($this->getAffectedUsers($share) as $userId) {
            $notification = $this->notificationManager->createNotification();
            $notification->setApp('files_sharing')
                ->setUser($userId)
                ->setObject('local_share', $share->getFullId());

            $this->notificationManager->markProcessed($notification);
        }
    }

    /**
     * Discards the notification related to the given share for the specific user.
     * This is useful to remove the notification when the user has seen or processed it
     *
     * @param IShare $share share
     * @param string $userId the user id (who should have been received the notification) that will
     * have his notification discarded.
     */
    public function discardNotificationForUser(IShare $share, $userId) {
        $notification = $this->notificationManager->createNotification();
        $notification->setApp('files_sharing')
            ->setUser($userId)
            ->setObject('local_share', $share->getFullId());

        $this->notificationManager->markProcessed($notification);
    }
}