From c43abe43b07370467cc80e8af2936df2b533aa06 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Wed, 26 Jul 2017 23:53:07 +0200 Subject: [PATCH] Send an email once a file/folder is shared with a user * only if user has set an email address * only for user shares (no group shares for now) Signed-off-by: Morris Jobke --- lib/private/Server.php | 5 +- lib/private/Share20/Manager.php | 101 +++++++++++++++++++++++++++++- tests/lib/Share20/ManagerTest.php | 47 +++++++++++--- 3 files changed, 144 insertions(+), 9 deletions(-) diff --git a/lib/private/Server.php b/lib/private/Server.php index 5efbcfecf3..b43d0d7d0a 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -964,7 +964,10 @@ class Server extends ServerContainer implements IServerContainer { $factory, $c->getUserManager(), $c->getLazyRootFolder(), - $c->getEventDispatcher() + $c->getEventDispatcher(), + $c->getMailer(), + $c->getURLGenerator(), + $c->getThemingDefaults() ); return $manager; diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index ca9d8e2843..f7f090f261 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -31,6 +31,7 @@ use OC\Cache\CappedMemoryCache; use OC\Files\Mount\MoveableMount; use OC\HintException; use OC\Share20\Exception\ProviderException; +use OCP\Defaults; use OCP\Files\File; use OCP\Files\Folder; use OCP\Files\IRootFolder; @@ -40,7 +41,9 @@ use OCP\IConfig; use OCP\IGroupManager; use OCP\IL10N; use OCP\ILogger; +use OCP\IURLGenerator; use OCP\IUserManager; +use OCP\Mail\IMailer; use OCP\Security\IHasher; use OCP\Security\ISecureRandom; use OCP\Share\Exceptions\GenericShareException; @@ -82,6 +85,12 @@ class Manager implements IManager { private $eventDispatcher; /** @var LegacyHooks */ private $legacyHooks; + /** @var IMailer */ + private $mailer; + /** @var IURLGenerator */ + private $urlGenerator; + /** @var \OC_Defaults */ + private $defaults; /** @@ -98,6 +107,9 @@ class Manager implements IManager { * @param IUserManager $userManager * @param IRootFolder $rootFolder * @param EventDispatcher $eventDispatcher + * @param IMailer $mailer + * @param IURLGenerator $urlGenerator + * @param \OC_Defaults $defaults */ public function __construct( ILogger $logger, @@ -110,7 +122,10 @@ class Manager implements IManager { IProviderFactory $factory, IUserManager $userManager, IRootFolder $rootFolder, - EventDispatcher $eventDispatcher + EventDispatcher $eventDispatcher, + IMailer $mailer, + IURLGenerator $urlGenerator, + \OC_Defaults $defaults ) { $this->logger = $logger; $this->config = $config; @@ -125,6 +140,9 @@ class Manager implements IManager { $this->eventDispatcher = $eventDispatcher; $this->sharingDisabledForUsersCache = new CappedMemoryCache(); $this->legacyHooks = new LegacyHooks($this->eventDispatcher); + $this->mailer = $mailer; + $this->urlGenerator = $urlGenerator; + $this->defaults = $defaults; } /** @@ -664,9 +682,90 @@ class Manager implements IManager { \OC_Hook::emit('OCP\Share', 'post_shared', $postHookData); + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { + $user = $this->userManager->get($share->getSharedWith()); + if ($user !== null) { + $emailAddress = $user->getEMailAddress(); + if ($emailAddress !== null && $emailAddress !== '') { + $this->sendMailNotification( + $share->getNode()->getName(), + $this->urlGenerator->linkToRouteAbsolute('files.viewcontroller.showFile', [ 'fileid' => $share->getNode()->getId() ]), + $share->getSharedBy(), + $emailAddress + ); + $this->logger->debug('Send share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']); + } else { + $this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']); + } + } else { + $this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']); + } + } + return $share; } + /** + * @param string $filename file/folder name + * @param string $link link to the file/folder + * @param string $initiator user ID of share sender + * @param string $shareWith email address of share receiver + * @throws \Exception If mail couldn't be sent + */ + protected function sendMailNotification($filename, + $link, + $initiator, + $shareWith) { + $initiatorUser = $this->userManager->get($initiator); + $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; + $subject = (string)$this->l->t('%s shared »%s« with you', array($initiatorDisplayName, $filename)); + + $message = $this->mailer->createMessage(); + + $emailTemplate = $this->mailer->createEMailTemplate(); + + $emailTemplate->addHeader(); + $emailTemplate->addHeading($this->l->t('%s shared »%s« with you', [$initiatorDisplayName, $filename]), false); + $text = $this->l->t('%s shared »%s« with you.', [$initiatorDisplayName, $filename]); + + $emailTemplate->addBodyText( + $text . ' ' . $this->l->t('Click the button below to open it.'), + $text + ); + $emailTemplate->addBodyButton( + $this->l->t('Open »%s«', [$filename]), + $link + ); + + $message->setTo([$shareWith]); + + // The "From" contains the sharers name + $instanceName = $this->defaults->getName(); + $senderName = $this->l->t( + '%s via %s', + [ + $initiatorDisplayName, + $instanceName + ] + ); + $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); + + // The "Reply-To" is set to the sharer if an mail address is configured + // also the default footer contains a "Do not reply" which needs to be adjusted. + $initiatorEmail = $initiatorUser->getEMailAddress(); + if($initiatorEmail !== null) { + $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]); + $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); + } else { + $emailTemplate->addFooter(); + } + + $message->setSubject($subject); + $message->setPlainBody($emailTemplate->renderText()); + $message->setHtmlBody($emailTemplate->renderHtml()); + $this->mailer->send($message); + } + /** * Update a share * diff --git a/tests/lib/Share20/ManagerTest.php b/tests/lib/Share20/ManagerTest.php index a764350c40..01d594de7a 100644 --- a/tests/lib/Share20/ManagerTest.php +++ b/tests/lib/Share20/ManagerTest.php @@ -23,6 +23,7 @@ namespace Test\Share20; use OC\Files\Mount\MoveableMount; use OC\HintException; use OC\Share20\DefaultShareProvider; +use OCP\Defaults; use OCP\Files\File; use OCP\Files\Folder; use OCP\Files\IRootFolder; @@ -31,8 +32,10 @@ use OCP\Files\Node; use OCP\Files\Storage; use OCP\IGroup; use OCP\IServerContainer; +use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserManager; +use OCP\Mail\IMailer; use OCP\Share\Exceptions\ShareNotFound; use OCP\Share\IProviderFactory; use OCP\Share\IShare; @@ -85,6 +88,12 @@ class ManagerTest extends \Test\TestCase { protected $rootFolder; /** @var EventDispatcher | \PHPUnit_Framework_MockObject_MockObject */ protected $eventDispatcher; + /** @var IMailer|\PHPUnit_Framework_MockObject_MockObject */ + protected $mailer; + /** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */ + protected $urlGenerator; + /** @var \OC_Defaults|\PHPUnit_Framework_MockObject_MockObject */ + protected $defaults; public function setUp() { @@ -97,6 +106,9 @@ class ManagerTest extends \Test\TestCase { $this->userManager = $this->createMock(IUserManager::class); $this->rootFolder = $this->createMock(IRootFolder::class); $this->eventDispatcher = $this->createMock(EventDispatcher::class); + $this->mailer = $this->createMock(IMailer::class); + $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->defaults = $this->createMock(\OC_Defaults::class); $this->l = $this->createMock(IL10N::class); $this->l->method('t') @@ -117,7 +129,10 @@ class ManagerTest extends \Test\TestCase { $this->factory, $this->userManager, $this->rootFolder, - $this->eventDispatcher + $this->eventDispatcher, + $this->mailer, + $this->urlGenerator, + $this->defaults ); $this->defaultProvider = $this->createMock(DefaultShareProvider::class); @@ -141,7 +156,10 @@ class ManagerTest extends \Test\TestCase { $this->factory, $this->userManager, $this->rootFolder, - $this->eventDispatcher + $this->eventDispatcher, + $this->mailer, + $this->urlGenerator, + $this->defaults ]); } @@ -2108,7 +2126,10 @@ class ManagerTest extends \Test\TestCase { $factory, $this->userManager, $this->rootFolder, - $this->eventDispatcher + $this->eventDispatcher, + $this->mailer, + $this->urlGenerator, + $this->defaults ); $share = $this->createMock(IShare::class); @@ -2147,7 +2168,10 @@ class ManagerTest extends \Test\TestCase { $factory, $this->userManager, $this->rootFolder, - $this->eventDispatcher + $this->eventDispatcher, + $this->mailer, + $this->urlGenerator, + $this->defaults ); $share = $this->createMock(IShare::class); @@ -2795,7 +2819,10 @@ class ManagerTest extends \Test\TestCase { $factory, $this->userManager, $this->rootFolder, - $this->eventDispatcher + $this->eventDispatcher, + $this->mailer, + $this->urlGenerator, + $this->defaults ); $this->assertSame($expected, $manager->shareProviderExists($shareType) @@ -2823,7 +2850,10 @@ class ManagerTest extends \Test\TestCase { $factory, $this->userManager, $this->rootFolder, - $this->eventDispatcher + $this->eventDispatcher, + $this->mailer, + $this->urlGenerator, + $this->defaults ); $factory->setProvider($this->defaultProvider); @@ -2882,7 +2912,10 @@ class ManagerTest extends \Test\TestCase { $factory, $this->userManager, $this->rootFolder, - $this->eventDispatcher + $this->eventDispatcher, + $this->mailer, + $this->urlGenerator, + $this->defaults ); $factory->setProvider($this->defaultProvider);