From a93f2a648b2694dcebc3dffd9ca391c1303ce381 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 12 Jul 2018 14:55:50 +0200 Subject: [PATCH] allow to add a personal note to a share Signed-off-by: Bjoern Schiessle --- .../lib/Controller/ShareAPIController.php | 14 +- apps/sharebymail/lib/ShareByMailProvider.php | 60 ++++++++ .../Version14000Date20180712153140.php | 45 ++++++ lib/private/Share20/DefaultShareProvider.php | 131 +++++++++++++++++- lib/private/Share20/ProviderFactory.php | 5 +- lib/private/Share20/Share.php | 17 +++ lib/public/Share/IShare.php | 18 +++ version.php | 2 +- 8 files changed, 286 insertions(+), 6 deletions(-) create mode 100644 core/Migrations/Version14000Date20180712153140.php diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php index d30d5a05a2..816ecde9c4 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -698,17 +698,21 @@ class ShareAPIController extends OCSController { * @param string $password * @param string $publicUpload * @param string $expireDate + * @param string $note * @return DataResponse - * @throws OCSNotFoundException + * @throws LockedException + * @throws NotFoundException * @throws OCSBadRequestException * @throws OCSForbiddenException + * @throws OCSNotFoundException */ public function updateShare( string $id, int $permissions = null, string $password = null, string $publicUpload = null, - string $expireDate = null + string $expireDate = null, + string $note = null ): DataResponse { try { $share = $this->getShareById($id); @@ -722,10 +726,14 @@ class ShareAPIController extends OCSController { throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist')); } - if ($permissions === null && $password === null && $publicUpload === null && $expireDate === null) { + if ($permissions === null && $password === null && $publicUpload === null && $expireDate === null && $note === null) { throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given')); } + if($note !== null) { + $share->setNote($note); + } + /* * expirationdate, password and publicUpload only make sense for link shares */ diff --git a/apps/sharebymail/lib/ShareByMailProvider.php b/apps/sharebymail/lib/ShareByMailProvider.php index 1a1855b9c4..bf251c627a 100644 --- a/apps/sharebymail/lib/ShareByMailProvider.php +++ b/apps/sharebymail/lib/ShareByMailProvider.php @@ -506,6 +506,61 @@ class ShareByMailProvider implements IShareProvider { return true; } + protected function sendNote(IShare $share) { + + $recipient = $share->getSharedWith(); + + + $filename = $share->getNode()->getName(); + $initiator = $share->getSharedBy(); + $note = $share->getNote(); + + $initiatorUser = $this->userManager->get($initiator); + $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; + $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; + + $plainBodyPart = $this->l->t("%s shared »%s« with you and want to add:\n", [$initiatorDisplayName, $filename]); + $htmlBodyPart = $this->l->t('%s shared »%s« with you and want to add:', [$initiatorDisplayName, $filename]); + + $message = $this->mailer->createMessage(); + + $emailTemplate = $this->mailer->createEMailTemplate('shareByMail.sendNote', [ + 'filename' => $filename, + 'note' => $note, + 'initiator' => $initiatorDisplayName, + 'initiatorEmail' => $initiatorEmailAddress, + 'shareWith' => $recipient, + ]); + + $emailTemplate->setSubject($this->l->t('»%s« added a note to a file shared with you', [$initiatorDisplayName])); + $emailTemplate->addHeader(); + $emailTemplate->addHeading($this->l->t('Note regarding »%s«', [$filename]), false); + $emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart); + $emailTemplate->addBodyText($note); + + // 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]); + if ($initiatorEmailAddress !== null) { + $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]); + $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); + } else { + $emailTemplate->addFooter(); + } + + $message->setTo([$recipient]); + $message->useTemplate($emailTemplate); + $this->mailer->send($message); + + } + /** * send auto generated password to the owner. This happens if the admin enforces * a password for mail shares and forbid to send the password by mail to the recipient @@ -662,8 +717,13 @@ class ShareByMailProvider implements IShareProvider { ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy())) ->set('password', $qb->createNamedParameter($share->getPassword())) ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE)) + ->set('note', $qb->createNamedParameter($share->getNote())) ->execute(); + if ($originalShare->getNote() !== $share->getNote() && $share->getNote() !== '') { + $this->sendNote($share); + } + return $share; } diff --git a/core/Migrations/Version14000Date20180712153140.php b/core/Migrations/Version14000Date20180712153140.php new file mode 100644 index 0000000000..04e682a4f6 --- /dev/null +++ b/core/Migrations/Version14000Date20180712153140.php @@ -0,0 +1,45 @@ + + * + * @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 . + * + */ + +namespace OC\Core\Migrations; + +use OCP\Migration\SimpleMigrationStep; + +/** + * add column for share notes + * + * Class Version14000Date20180712153140 + */ +class Version14000Date20180712153140 extends SimpleMigrationStep { + public function changeSchema(\OCP\Migration\IOutput $output, \Closure $schemaClosure, array $options) { + + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $table = $schema->getTable('share'); + $table->addColumn('note', 'text', [ + 'notnull' => true, + 'default' => '' + ]); + + return $schema; + } +} diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index 5e52156d1d..1d7dddcaf4 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -30,8 +30,13 @@ namespace OC\Share20; use OC\Files\Cache\Cache; +use OCP\Defaults; use OCP\Files\Folder; +use OCP\IL10N; +use OCP\IUser; +use OCP\Mail\IMailer; use OCP\Share\IShare; +use OCP\Share\IShareHelper; use OCP\Share\IShareProvider; use OC\Share20\Exception\InvalidShare; use OC\Share20\Exception\ProviderException; @@ -67,6 +72,15 @@ class DefaultShareProvider implements IShareProvider { /** @var IRootFolder */ private $rootFolder; + /** @var IMailer */ + private $mailer; + + /** @var Defaults */ + private $defaults; + + /** @var IL10N */ + private $l; + /** * DefaultShareProvider constructor. * @@ -74,16 +88,25 @@ class DefaultShareProvider implements IShareProvider { * @param IUserManager $userManager * @param IGroupManager $groupManager * @param IRootFolder $rootFolder + * @param IMailer $mailer ; + * @param Defaults $defaults + * @param IL10N $l */ public function __construct( IDBConnection $connection, IUserManager $userManager, IGroupManager $groupManager, - IRootFolder $rootFolder) { + IRootFolder $rootFolder, + IMailer $mailer, + Defaults $defaults, + IL10N $l) { $this->dbConn = $connection; $this->userManager = $userManager; $this->groupManager = $groupManager; $this->rootFolder = $rootFolder; + $this->mailer = $mailer; + $this->defaults = $defaults; + $this->l = $l; } /** @@ -197,6 +220,9 @@ class DefaultShareProvider implements IShareProvider { * @return \OCP\Share\IShare The share object */ public function update(\OCP\Share\IShare $share) { + + $originalShare = $this->getShareById($share->getId()); + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { /* * We allow updating the recipient on user shares. @@ -211,6 +237,7 @@ class DefaultShareProvider implements IShareProvider { ->set('item_source', $qb->createNamedParameter($share->getNode()->getId())) ->set('file_source', $qb->createNamedParameter($share->getNode()->getId())) ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE)) + ->set('note', $qb->createNamedParameter($share->getNote())) ->execute(); } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { $qb = $this->dbConn->getQueryBuilder(); @@ -222,6 +249,7 @@ class DefaultShareProvider implements IShareProvider { ->set('item_source', $qb->createNamedParameter($share->getNode()->getId())) ->set('file_source', $qb->createNamedParameter($share->getNode()->getId())) ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE)) + ->set('note', $qb->createNamedParameter($share->getNote())) ->execute(); /* @@ -235,6 +263,7 @@ class DefaultShareProvider implements IShareProvider { ->set('item_source', $qb->createNamedParameter($share->getNode()->getId())) ->set('file_source', $qb->createNamedParameter($share->getNode()->getId())) ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE)) + ->set('note', $qb->createNamedParameter($share->getNote())) ->execute(); /* @@ -259,9 +288,15 @@ class DefaultShareProvider implements IShareProvider { ->set('file_source', $qb->createNamedParameter($share->getNode()->getId())) ->set('token', $qb->createNamedParameter($share->getToken())) ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE)) + ->set('note', $qb->createNamedParameter($share->getNote())) ->execute(); } + if ($originalShare->getNote() !== $share->getNote() && $share->getNote() !== '') { + $this->propagateNote($share); + } + + return $share; } @@ -1227,4 +1262,98 @@ class DefaultShareProvider implements IShareProvider { return $best; } + + /** + * propagate notes to the recipients + * + * @param IShare $share + * @throws \OCP\Files\NotFoundException + */ + private function propagateNote(IShare $share) { + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) { + $user = $this->userManager->get($share->getSharedWith()); + $this->sendNote([$user], $share); + } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { + $group = $this->groupManager->get($share->getSharedWith()); + $groupMembers = $group->getUsers(); + $this->sendNote($groupMembers, $share); + } + } + + /** + * send note by mail + * + * @param array $recipients + * @param IShare $share + * @throws \OCP\Files\NotFoundException + */ + private function sendNote(array $recipients, IShare $share) { + + $toList = []; + + foreach ($recipients as $recipient) { + /** @var IUser $recipient */ + $email = $recipient->getEMailAddress(); + if ($email) { + $toList[$email] = $recipient->getDisplayName(); + } + } + + if (!empty($toList)) { + + $filename = $share->getNode()->getName(); + $initiator = $share->getSharedBy(); + $note = $share->getNote(); + + $initiatorUser = $this->userManager->get($initiator); + $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; + $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; + + $plainBodyPart = $this->l->t("%s shared »%s« with you and want to add:\n", [$initiatorDisplayName, $filename]); + $htmlBodyPart = $this->l->t('%s shared »%s« with you and want to add:', [$initiatorDisplayName, $filename]); + + $message = $this->mailer->createMessage(); + + $emailTemplate = $this->mailer->createEMailTemplate('defaultShareProvider.sendNote', [ + 'filename' => $filename, + 'note' => $note, + 'initiator' => $initiatorDisplayName, + 'initiatorEmail' => $initiatorEmailAddress, + 'shareWith' => $recipient, + ]); + + $emailTemplate->setSubject($this->l->t('»%s« added a note to a file shared with you', [$initiatorDisplayName])); + $emailTemplate->addHeader(); + $emailTemplate->addHeading($this->l->t('Note regarding »%s«', [$filename]), false); + $emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart); + $emailTemplate->addBodyText($note); + + // 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]); + if ($initiatorEmailAddress !== null) { + $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]); + $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); + } else { + $emailTemplate->addFooter(); + } + + if (count($toList) === 1) { + $message->setTo($toList); + } else { + $message->setTo([]); + $message->setBcc($toList); + } + $message->useTemplate($emailTemplate); + $this->mailer->send($message); + } + + } } diff --git a/lib/private/Share20/ProviderFactory.php b/lib/private/Share20/ProviderFactory.php index e4d3414691..22a2fe7a01 100644 --- a/lib/private/Share20/ProviderFactory.php +++ b/lib/private/Share20/ProviderFactory.php @@ -81,7 +81,10 @@ class ProviderFactory implements IProviderFactory { $this->serverContainer->getDatabaseConnection(), $this->serverContainer->getUserManager(), $this->serverContainer->getGroupManager(), - $this->serverContainer->getLazyRootFolder() + $this->serverContainer->getLazyRootFolder(), + $this->serverContainer->getMailer(), + $this->serverContainer->query(Defaults::class), + $this->serverContainer->getL10N('sharing') ); } diff --git a/lib/private/Share20/Share.php b/lib/private/Share20/Share.php index d7810165da..73373c7823 100644 --- a/lib/private/Share20/Share.php +++ b/lib/private/Share20/Share.php @@ -57,6 +57,8 @@ class Share implements \OCP\Share\IShare { private $shareOwner; /** @var int */ private $permissions; + /** @var string */ + private $note = ''; /** @var \DateTime */ private $expireDate; /** @var string */ @@ -308,6 +310,21 @@ class Share implements \OCP\Share\IShare { return $this->permissions; } + /** + * @inheritdoc + */ + public function setNote($note) { + $this->note = $note; + return $this; + } + + /** + * @inheritdoc + */ + public function getNote() { + return $this->note; + } + /** * @inheritdoc */ diff --git a/lib/public/Share/IShare.php b/lib/public/Share/IShare.php index 870794d653..5303cde45a 100644 --- a/lib/public/Share/IShare.php +++ b/lib/public/Share/IShare.php @@ -222,6 +222,24 @@ interface IShare { */ public function getPermissions(); + /** + * Attach a note to a share + * + * @param string $note + * @return \OCP\Share\IShare The modified object + * @since 14.0.0 + */ + public function setNote($note); + + /** + * Get note attached to a share + * + * @return string + * @since 14.0.0 + */ + public function getNote(); + + /** * Set the expiration date * diff --git a/version.php b/version.php index 5c288428c1..c18ca01286 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ // between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel // when updating major/minor version number. -$OC_Version = array(14, 0, 0, 10); +$OC_Version = array(14, 0, 0, 11); // The human readable string $OC_VersionString = '14.0.0 alpha';