From a93f2a648b2694dcebc3dffd9ca391c1303ce381 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 12 Jul 2018 14:55:50 +0200 Subject: [PATCH 01/30] 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 d30d5a05a2204..816ecde9c4044 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -698,17 +698,21 @@ public function getShares( * @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 @@ public function updateShare( 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 1a1855b9c4493..bf251c627a08c 100644 --- a/apps/sharebymail/lib/ShareByMailProvider.php +++ b/apps/sharebymail/lib/ShareByMailProvider.php @@ -506,6 +506,61 @@ protected function sendPassword(IShare $share, $password) { 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 @@ public function update(IShare $share, $plainTextPassword = null) { ->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 0000000000000..04e682a4f68df --- /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 5e52156d1d0b0..1d7dddcaf4a03 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 @@ public function create(\OCP\Share\IShare $share) { * @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 @@ public function update(\OCP\Share\IShare $share) { ->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 @@ public function update(\OCP\Share\IShare $share) { ->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 @@ public function update(\OCP\Share\IShare $share) { ->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 @@ public function update(\OCP\Share\IShare $share) { ->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 @@ protected function filterSharesOfUser(array $shares) { 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 e4d34146911c2..22a2fe7a01974 100644 --- a/lib/private/Share20/ProviderFactory.php +++ b/lib/private/Share20/ProviderFactory.php @@ -81,7 +81,10 @@ protected function defaultShareProvider() { $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 d7810165dac0d..73373c7823d06 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 @@ public function getPermissions() { 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 870794d65361e..5303cde45a6eb 100644 --- a/lib/public/Share/IShare.php +++ b/lib/public/Share/IShare.php @@ -222,6 +222,24 @@ public function setPermissions($permissions); */ 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 5c288428c1375..c18ca01286ba1 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'; From c116d116facb45683514cbb2d175b66e3d3c5c59 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 12 Jul 2018 16:05:24 +0200 Subject: [PATCH 02/30] improve mail template and escape html code Signed-off-by: Bjoern Schiessle --- apps/sharebymail/lib/ShareByMailProvider.php | 17 +++++------------ lib/private/Share20/DefaultShareProvider.php | 17 +++++------------ 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/apps/sharebymail/lib/ShareByMailProvider.php b/apps/sharebymail/lib/ShareByMailProvider.php index bf251c627a08c..0eceeca1cac2a 100644 --- a/apps/sharebymail/lib/ShareByMailProvider.php +++ b/apps/sharebymail/lib/ShareByMailProvider.php @@ -519,24 +519,17 @@ protected function sendNote(IShare $share) { $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]); + $plainHeading = $this->l->t('%1s shared »%2s« with you and want to add:', [$initiatorDisplayName, $filename]); + $htmlHeading = $this->l->t('%1s shared »%2s« 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 = $this->mailer->createEMailTemplate('shareByMail.sendNote'); $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); + $emailTemplate->addHeading(htmlspecialchars($htmlHeading), $plainHeading); + $emailTemplate->addBodyText(htmlspecialchars($note), $note); // The "From" contains the sharers name $instanceName = $this->defaults->getName(); diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index 1d7dddcaf4a03..86eac45f88e6e 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -1309,24 +1309,17 @@ private function sendNote(array $recipients, IShare $share) { $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]); + $plainHeading = $this->l->t('%1s shared »%2s« with you and want to add:', [$initiatorDisplayName, $filename]); + $htmlHeading = $this->l->t('%1s shared »%2s« 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 = $this->mailer->createEMailTemplate('defaultShareProvider.sendNote'); $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); + $emailTemplate->addHeading(htmlspecialchars($htmlHeading), $plainHeading); + $emailTemplate->addBodyText(htmlspecialchars($note), $note); // The "From" contains the sharers name $instanceName = $this->defaults->getName(); From 73b88deeb8942e188a5e1e81f4bfca02412a0c5c Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 12 Jul 2018 16:09:05 +0200 Subject: [PATCH 03/30] add note to share object when reading it from the db Signed-off-by: Bjoern Schiessle --- apps/sharebymail/lib/ShareByMailProvider.php | 1 + lib/private/Share20/DefaultShareProvider.php | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/sharebymail/lib/ShareByMailProvider.php b/apps/sharebymail/lib/ShareByMailProvider.php index 0eceeca1cac2a..cdef06f5345e9 100644 --- a/apps/sharebymail/lib/ShareByMailProvider.php +++ b/apps/sharebymail/lib/ShareByMailProvider.php @@ -957,6 +957,7 @@ protected function createShareObject($data) { ->setPermissions((int)$data['permissions']) ->setTarget($data['file_target']) ->setMailSend((bool)$data['mail_send']) + ->setNote($data['note']) ->setToken($data['token']); $shareTime = new \DateTime(); diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index 86eac45f88e6e..8ecd1e811bac3 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -910,6 +910,7 @@ private function createShare($data) { ->setShareType((int)$data['share_type']) ->setPermissions((int)$data['permissions']) ->setTarget($data['file_target']) + ->setNote($data['note']) ->setMailSend((bool)$data['mail_send']); $shareTime = new \DateTime(); From 4f59c8e8ae349fbebf646907d8bf610cf14189d6 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 12 Jul 2018 16:58:36 +0200 Subject: [PATCH 04/30] show note on public link page Signed-off-by: Bjoern Schiessle --- apps/files_sharing/css/public.scss | 5 +++++ apps/files_sharing/lib/Controller/ShareController.php | 1 + apps/files_sharing/templates/public.php | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/apps/files_sharing/css/public.scss b/apps/files_sharing/css/public.scss index 2e788a06c40f1..583912ad23614 100644 --- a/apps/files_sharing/css/public.scss +++ b/apps/files_sharing/css/public.scss @@ -169,3 +169,8 @@ thead { opacity: .57; margin-top: 10px; } + +#note { + text-align: center; + padding: 10px; +} diff --git a/apps/files_sharing/lib/Controller/ShareController.php b/apps/files_sharing/lib/Controller/ShareController.php index 0b30a599c7ffa..bd1331a090884 100644 --- a/apps/files_sharing/lib/Controller/ShareController.php +++ b/apps/files_sharing/lib/Controller/ShareController.php @@ -262,6 +262,7 @@ public function showShare($path = ''): TemplateResponse { $shareTmpl['owner'] = $share->getShareOwner(); $shareTmpl['filename'] = $share->getNode()->getName(); $shareTmpl['directory_path'] = $share->getTarget(); + $shareTmpl['note'] = $share->getNote(); $shareTmpl['mimetype'] = $share->getNode()->getMimetype(); $shareTmpl['previewSupported'] = $this->previewManager->isMimeSupported($share->getNode()->getMimetype()); $shareTmpl['dirToken'] = $this->getToken(); diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index 476f0851547f6..e337eb9b7f353 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -31,6 +31,11 @@
+ +
+ t('Note: ')); p($_['note']); ?> +
+
From a29261175d1b8062e81239a54d456018d792d3e9 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 12 Jul 2018 17:07:11 +0200 Subject: [PATCH 05/30] fix mail templates Signed-off-by: Bjoern Schiessle --- apps/sharebymail/lib/ShareByMailProvider.php | 6 +++--- lib/private/Share20/DefaultShareProvider.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/sharebymail/lib/ShareByMailProvider.php b/apps/sharebymail/lib/ShareByMailProvider.php index cdef06f5345e9..50fbd6fa0ed79 100644 --- a/apps/sharebymail/lib/ShareByMailProvider.php +++ b/apps/sharebymail/lib/ShareByMailProvider.php @@ -519,8 +519,8 @@ protected function sendNote(IShare $share) { $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; - $plainHeading = $this->l->t('%1s shared »%2s« with you and want to add:', [$initiatorDisplayName, $filename]); - $htmlHeading = $this->l->t('%1s shared »%2s« with you and want to add:', [$initiatorDisplayName, $filename]); + $plainHeading = $this->l->t('%1$s shared »%2$s« with you and want to add:', [$initiatorDisplayName, $filename]); + $htmlHeading = $this->l->t('%1$s shared »%2$s« with you and want to add:', [$initiatorDisplayName, $filename]); $message = $this->mailer->createMessage(); @@ -534,7 +534,7 @@ protected function sendNote(IShare $share) { // The "From" contains the sharers name $instanceName = $this->defaults->getName(); $senderName = $this->l->t( - '%s via %s', + '%1$s via %2$s', [ $initiatorDisplayName, $instanceName diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index 8ecd1e811bac3..2594b9e297394 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -1310,8 +1310,8 @@ private function sendNote(array $recipients, IShare $share) { $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; - $plainHeading = $this->l->t('%1s shared »%2s« with you and want to add:', [$initiatorDisplayName, $filename]); - $htmlHeading = $this->l->t('%1s shared »%2s« with you and want to add:', [$initiatorDisplayName, $filename]); + $plainHeading = $this->l->t('%1$s shared »%2$s« with you and want to add:', [$initiatorDisplayName, $filename]); + $htmlHeading = $this->l->t('%1$s shared »%2$s« with you and want to add:', [$initiatorDisplayName, $filename]); $message = $this->mailer->createMessage(); @@ -1325,7 +1325,7 @@ private function sendNote(array $recipients, IShare $share) { // The "From" contains the sharers name $instanceName = $this->defaults->getName(); $senderName = $this->l->t( - '%s via %s', + '%1$s via %2$s', [ $initiatorDisplayName, $instanceName From b56ccef564f19e78d5e3c9f255cfebcf2df8e31b Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 12 Jul 2018 18:17:22 +0200 Subject: [PATCH 06/30] add direct link to the file for user/group shares Signed-off-by: Bjoern Schiessle --- lib/private/Share20/DefaultShareProvider.php | 22 ++++++++++++++++---- lib/private/Share20/ProviderFactory.php | 3 ++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index 2594b9e297394..90fa5044aeb3a 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -33,6 +33,7 @@ use OCP\Defaults; use OCP\Files\Folder; use OCP\IL10N; +use OCP\IURLGenerator; use OCP\IUser; use OCP\Mail\IMailer; use OCP\Share\IShare; @@ -81,6 +82,9 @@ class DefaultShareProvider implements IShareProvider { /** @var IL10N */ private $l; + /** @var IURLGenerator */ + private $urlGenerator; + /** * DefaultShareProvider constructor. * @@ -91,6 +95,7 @@ class DefaultShareProvider implements IShareProvider { * @param IMailer $mailer ; * @param Defaults $defaults * @param IL10N $l + * @param IURLGenerator $urlGenerator */ public function __construct( IDBConnection $connection, @@ -99,7 +104,8 @@ public function __construct( IRootFolder $rootFolder, IMailer $mailer, Defaults $defaults, - IL10N $l) { + IL10N $l, + IURLGenerator $urlGenerator) { $this->dbConn = $connection; $this->userManager = $userManager; $this->groupManager = $groupManager; @@ -107,6 +113,7 @@ public function __construct( $this->mailer = $mailer; $this->defaults = $defaults; $this->l = $l; + $this->urlGenerator = $urlGenerator; } /** @@ -1309,18 +1316,25 @@ private function sendNote(array $recipients, IShare $share) { $initiatorUser = $this->userManager->get($initiator); $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; - $plainHeading = $this->l->t('%1$s shared »%2$s« with you and want to add:', [$initiatorDisplayName, $filename]); $htmlHeading = $this->l->t('%1$s shared »%2$s« with you and want to add:', [$initiatorDisplayName, $filename]); - + $link = $this->urlGenerator->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $share->getNode()->getId()]); + if($share->getNode()->getType() === \OCP\Files\FileInfo::TYPE_FILE) { + $plainLink = $this->l->t('Direct link to the file: %s', [$link]); + $htmlLink = $this->l->t('Direct link to the file.', [$link]); + } else { + $plainLink = $this->l->t('Direct link to the folder: %s', [$link]); + $htmlLink = $this->l->t('Direct link to the folder.', [$link]); + } $message = $this->mailer->createMessage(); $emailTemplate = $this->mailer->createEMailTemplate('defaultShareProvider.sendNote'); $emailTemplate->setSubject($this->l->t('»%s« added a note to a file shared with you', [$initiatorDisplayName])); $emailTemplate->addHeader(); - $emailTemplate->addHeading(htmlspecialchars($htmlHeading), $plainHeading); + $emailTemplate->addHeading($htmlHeading, $plainHeading); $emailTemplate->addBodyText(htmlspecialchars($note), $note); + $emailTemplate->addBodyText($htmlLink, $plainLink); // The "From" contains the sharers name $instanceName = $this->defaults->getName(); diff --git a/lib/private/Share20/ProviderFactory.php b/lib/private/Share20/ProviderFactory.php index 22a2fe7a01974..0aacca409d148 100644 --- a/lib/private/Share20/ProviderFactory.php +++ b/lib/private/Share20/ProviderFactory.php @@ -84,7 +84,8 @@ protected function defaultShareProvider() { $this->serverContainer->getLazyRootFolder(), $this->serverContainer->getMailer(), $this->serverContainer->query(Defaults::class), - $this->serverContainer->getL10N('sharing') + $this->serverContainer->getL10N('sharing'), + $this->serverContainer->getURLGenerator() ); } From 1ce519ad38e5c7f56a2c8007517570cac3c94bec Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 12 Jul 2018 19:32:03 +0200 Subject: [PATCH 07/30] add direct link to the share Signed-off-by: Bjoern Schiessle --- apps/sharebymail/lib/ShareByMailProvider.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/sharebymail/lib/ShareByMailProvider.php b/apps/sharebymail/lib/ShareByMailProvider.php index 50fbd6fa0ed79..0e4ecded3f9f7 100644 --- a/apps/sharebymail/lib/ShareByMailProvider.php +++ b/apps/sharebymail/lib/ShareByMailProvider.php @@ -531,6 +531,13 @@ protected function sendNote(IShare $share) { $emailTemplate->addHeading(htmlspecialchars($htmlHeading), $plainHeading); $emailTemplate->addBodyText(htmlspecialchars($note), $note); + $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', + ['token' => $share->getToken()]); + $emailTemplate->addBodyButton( + $this->l->t('Open »%s«', [$filename]), + $link + ); + // The "From" contains the sharers name $instanceName = $this->defaults->getName(); $senderName = $this->l->t( From 2250dbec215ba6336160ae1b71102ae072863f1a Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 12 Jul 2018 19:32:35 +0200 Subject: [PATCH 08/30] add a nice looking button as direct link to the sharre Signed-off-by: Bjoern Schiessle --- lib/private/Share20/DefaultShareProvider.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index 90fa5044aeb3a..f5e32de424e78 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -1318,14 +1318,6 @@ private function sendNote(array $recipients, IShare $share) { $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; $plainHeading = $this->l->t('%1$s shared »%2$s« with you and want to add:', [$initiatorDisplayName, $filename]); $htmlHeading = $this->l->t('%1$s shared »%2$s« with you and want to add:', [$initiatorDisplayName, $filename]); - $link = $this->urlGenerator->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $share->getNode()->getId()]); - if($share->getNode()->getType() === \OCP\Files\FileInfo::TYPE_FILE) { - $plainLink = $this->l->t('Direct link to the file: %s', [$link]); - $htmlLink = $this->l->t('Direct link to the file.', [$link]); - } else { - $plainLink = $this->l->t('Direct link to the folder: %s', [$link]); - $htmlLink = $this->l->t('Direct link to the folder.', [$link]); - } $message = $this->mailer->createMessage(); $emailTemplate = $this->mailer->createEMailTemplate('defaultShareProvider.sendNote'); @@ -1334,7 +1326,13 @@ private function sendNote(array $recipients, IShare $share) { $emailTemplate->addHeader(); $emailTemplate->addHeading($htmlHeading, $plainHeading); $emailTemplate->addBodyText(htmlspecialchars($note), $note); - $emailTemplate->addBodyText($htmlLink, $plainLink); + + $link = $this->urlGenerator->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $share->getNode()->getId()]); + $emailTemplate->addBodyButton( + $this->l->t('Open »%s«', [$filename]), + $link + ); + // The "From" contains the sharers name $instanceName = $this->defaults->getName(); From b81962e3e865e9187d099bcb958cec9acfc7d593 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 13 Jul 2018 10:51:22 +0200 Subject: [PATCH 09/30] fix unit tests Signed-off-by: Bjoern Schiessle --- .../tests/ShareByMailProviderTest.php | 18 ++++--- .../lib/Share20/DefaultShareProviderTest.php | 52 +++++++++++++++++-- 2 files changed, 59 insertions(+), 11 deletions(-) diff --git a/apps/sharebymail/tests/ShareByMailProviderTest.php b/apps/sharebymail/tests/ShareByMailProviderTest.php index 95d746cfb46a2..f0d99e6026cda 100644 --- a/apps/sharebymail/tests/ShareByMailProviderTest.php +++ b/apps/sharebymail/tests/ShareByMailProviderTest.php @@ -342,15 +342,17 @@ public function testUpdate() { $uidOwner = 'user2'; $permissions = 1; $token = 'token'; + $note = 'personal note'; $instance = $this->getInstance(); - $id = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token); + $id = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $note); $this->share->expects($this->once())->method('getPermissions')->willReturn($permissions + 1); $this->share->expects($this->once())->method('getShareOwner')->willReturn($uidOwner); $this->share->expects($this->once())->method('getSharedBy')->willReturn($sharedBy); + $this->share->expects($this->any())->method('getNote')->willReturn($note); $this->share->expects($this->atLeastOnce())->method('getId')->willReturn($id); $this->assertSame($this->share, @@ -372,6 +374,7 @@ public function testUpdate() { $this->assertSame($uidOwner, $result[0]['uid_owner']); $this->assertSame($permissions + 1, (int)$result[0]['permissions']); $this->assertSame($token, $result[0]['token']); + $this->assertSame($note, $result[0]['note']); } public function testDelete() { @@ -478,7 +481,7 @@ public function testGetShareByToken() { $instance = $this->getInstance(['createShareObject']); $idMail = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token); - $idPublic = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token, \OCP\Share::SHARE_TYPE_LINK); + $idPublic = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token, '', \OCP\Share::SHARE_TYPE_LINK); $this->assertTrue($idMail !== $idPublic); @@ -490,9 +493,9 @@ function ($data) use ($idMail) { } ); - $this->assertInstanceOf('OCP\Share\IShare', - $instance->getShareByToken('token') - ); + $result = $instance->getShareByToken('token'); + + $this->assertInstanceOf('OCP\Share\IShare', $result); } /** @@ -511,7 +514,7 @@ public function testGetShareByTokenFailed() { $instance = $this->getInstance(['createShareObject']); $idMail = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token); - $idPublic = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, "token2", \OCP\Share::SHARE_TYPE_LINK); + $idPublic = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, "token2", '', \OCP\Share::SHARE_TYPE_LINK); $this->assertTrue($idMail !== $idPublic); @@ -631,7 +634,7 @@ public function testGetRawShareFailed() { $this->invokePrivate($instance, 'getRawShare', [$id+1]); } - private function createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $shareType = \OCP\Share::SHARE_TYPE_EMAIL) { + private function createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $note='', $shareType = \OCP\Share::SHARE_TYPE_EMAIL) { $qb = $this->connection->getQueryBuilder(); $qb->insert('share') ->setValue('share_type', $qb->createNamedParameter($shareType)) @@ -643,6 +646,7 @@ private function createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy)) ->setValue('permissions', $qb->createNamedParameter($permissions)) ->setValue('token', $qb->createNamedParameter($token)) + ->setValue('note', $qb->createNamedParameter($note)) ->setValue('stime', $qb->createNamedParameter(time())); /* diff --git a/tests/lib/Share20/DefaultShareProviderTest.php b/tests/lib/Share20/DefaultShareProviderTest.php index 230c8db40ce65..19f3716062717 100644 --- a/tests/lib/Share20/DefaultShareProviderTest.php +++ b/tests/lib/Share20/DefaultShareProviderTest.php @@ -22,15 +22,19 @@ namespace Test\Share20; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Defaults; use OCP\Files\File; use OCP\Files\Folder; use OCP\IDBConnection; use OCP\IGroup; +use OCP\IL10N; +use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserManager; use OCP\IGroupManager; use OCP\Files\IRootFolder; use OC\Share20\DefaultShareProvider; +use OCP\Mail\IMailer; use OCP\Share\IShare; /** @@ -56,11 +60,27 @@ class DefaultShareProviderTest extends \Test\TestCase { /** @var DefaultShareProvider */ protected $provider; + /** @var \PHPUnit_Framework_MockObject_MockObject|IMailer */ + protected $mailer; + + /** @var \PHPUnit_Framework_MockObject_MockObject|IL10N */ + protected $l10n; + + /** @var \PHPUnit_Framework_MockObject_MockObject|Defaults */ + protected $defaults; + + /** @var \PHPUnit_Framework_MockObject_MockObject|IURLGenerator */ + protected $urlGenerator; + public function setUp() { $this->dbConn = \OC::$server->getDatabaseConnection(); $this->userManager = $this->createMock(IUserManager::class); $this->groupManager = $this->createMock(IGroupManager::class); $this->rootFolder = $this->createMock(IRootFolder::class); + $this->mailer = $this->createMock(IMailer::class); + $this->l10n = $this->createMock(IL10N::class); + $this->defaults = $this->getMockBuilder(Defaults::class)->disableOriginalConstructor()->getMock(); + $this->urlGenerator = $this->createMock(IURLGenerator::class); $this->userManager->expects($this->any())->method('userExists')->willReturn(true); @@ -71,7 +91,11 @@ public function setUp() { $this->dbConn, $this->userManager, $this->groupManager, - $this->rootFolder + $this->rootFolder, + $this->mailer, + $this->defaults, + $this->l10n, + $this->urlGenerator ); } @@ -403,6 +427,10 @@ public function testDeleteSingleShare() { $this->userManager, $this->groupManager, $this->rootFolder, + $this->mailer, + $this->defaults, + $this->l10n, + $this->urlGenerator ]) ->setMethods(['getShareById']) ->getMock(); @@ -493,6 +521,10 @@ public function testDeleteGroupShareWithUserGroupShares() { $this->userManager, $this->groupManager, $this->rootFolder, + $this->mailer, + $this->defaults, + $this->l10n, + $this->urlGenerator ]) ->setMethods(['getShareById']) ->getMock(); @@ -2368,7 +2400,11 @@ public function testGetSharesInFolder() { $this->dbConn, $userManager, $groupManager, - $rootFolder + $rootFolder, + $this->mailer, + $this->defaults, + $this->l10n, + $this->urlGenerator ); $password = md5(time()); @@ -2461,7 +2497,11 @@ public function testGetAccessListNoCurrentAccessRequired() { $this->dbConn, $userManager, $groupManager, - $rootFolder + $rootFolder, + $this->mailer, + $this->defaults, + $this->l10n, + $this->urlGenerator ); $u1 = $userManager->createUser('testShare1', 'test'); @@ -2552,7 +2592,11 @@ public function testGetAccessListCurrentAccessRequired() { $this->dbConn, $userManager, $groupManager, - $rootFolder + $rootFolder, + $this->mailer, + $this->defaults, + $this->l10n, + $this->urlGenerator ); $u1 = $userManager->createUser('testShare1', 'test'); From 94c70524820a51bc34a1539a93cd6bbb4bc31193 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 13 Jul 2018 11:41:53 +0200 Subject: [PATCH 10/30] allow 'note' to be null Signed-off-by: Bjoern Schiessle --- core/Migrations/Version14000Date20180712153140.php | 6 ++---- lib/private/Share20/Share.php | 5 ++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/core/Migrations/Version14000Date20180712153140.php b/core/Migrations/Version14000Date20180712153140.php index 04e682a4f68df..7f667fa384798 100644 --- a/core/Migrations/Version14000Date20180712153140.php +++ b/core/Migrations/Version14000Date20180712153140.php @@ -21,6 +21,7 @@ namespace OC\Core\Migrations; +use OCP\DB\ISchemaWrapper; use OCP\Migration\SimpleMigrationStep; /** @@ -35,10 +36,7 @@ public function changeSchema(\OCP\Migration\IOutput $output, \Closure $schemaClo $schema = $schemaClosure(); $table = $schema->getTable('share'); - $table->addColumn('note', 'text', [ - 'notnull' => true, - 'default' => '' - ]); + $table->addColumn('note', 'text'); return $schema; } diff --git a/lib/private/Share20/Share.php b/lib/private/Share20/Share.php index 73373c7823d06..e54497c9b5517 100644 --- a/lib/private/Share20/Share.php +++ b/lib/private/Share20/Share.php @@ -322,7 +322,10 @@ public function setNote($note) { * @inheritdoc */ public function getNote() { - return $this->note; + if (is_string($this->note)) { + return $this->note; + } + return ''; } /** From eab4d96c4cf200c095de64258d96b791700a7cf4 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 13 Jul 2018 12:09:15 +0200 Subject: [PATCH 11/30] some small template fixes Signed-off-by: Bjoern Schiessle --- apps/files_sharing/templates/public.php | 2 +- apps/sharebymail/lib/ShareByMailProvider.php | 4 ++-- lib/private/Share20/DefaultShareProvider.php | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index e337eb9b7f353..4aedf986962e4 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -33,7 +33,7 @@
- t('Note: ')); p($_['note']); ?> + t('Note:')); p(' ' . $_['note']); ?>
diff --git a/apps/sharebymail/lib/ShareByMailProvider.php b/apps/sharebymail/lib/ShareByMailProvider.php index 0e4ecded3f9f7..73e962e3292be 100644 --- a/apps/sharebymail/lib/ShareByMailProvider.php +++ b/apps/sharebymail/lib/ShareByMailProvider.php @@ -519,8 +519,8 @@ protected function sendNote(IShare $share) { $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; - $plainHeading = $this->l->t('%1$s shared »%2$s« with you and want to add:', [$initiatorDisplayName, $filename]); - $htmlHeading = $this->l->t('%1$s shared »%2$s« with you and want to add:', [$initiatorDisplayName, $filename]); + $plainHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add:', [$initiatorDisplayName, $filename]); + $htmlHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add', [$initiatorDisplayName, $filename]); $message = $this->mailer->createMessage(); diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index f5e32de424e78..9c5d78a59589f 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -1316,8 +1316,8 @@ private function sendNote(array $recipients, IShare $share) { $initiatorUser = $this->userManager->get($initiator); $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; - $plainHeading = $this->l->t('%1$s shared »%2$s« with you and want to add:', [$initiatorDisplayName, $filename]); - $htmlHeading = $this->l->t('%1$s shared »%2$s« with you and want to add:', [$initiatorDisplayName, $filename]); + $plainHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add:', [$initiatorDisplayName, $filename]); + $htmlHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add', [$initiatorDisplayName, $filename]); $message = $this->mailer->createMessage(); $emailTemplate = $this->mailer->createEMailTemplate('defaultShareProvider.sendNote'); From 7bdedfba48d4b7750fd9e37fffd54bde38e8dc60 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 13 Jul 2018 15:35:46 +0200 Subject: [PATCH 12/30] explicitely mention that the note column can be null Signed-off-by: Bjoern Schiessle --- core/Migrations/Version14000Date20180712153140.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/Migrations/Version14000Date20180712153140.php b/core/Migrations/Version14000Date20180712153140.php index 7f667fa384798..268a479eaad78 100644 --- a/core/Migrations/Version14000Date20180712153140.php +++ b/core/Migrations/Version14000Date20180712153140.php @@ -36,7 +36,7 @@ public function changeSchema(\OCP\Migration\IOutput $output, \Closure $schemaClo $schema = $schemaClosure(); $table = $schema->getTable('share'); - $table->addColumn('note', 'text'); + $table->addColumn('note', 'text', ['notnull' => false]); return $schema; } From 660b5d1af6e712b4f42a71ba861b22dcb7e95ee6 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 13 Jul 2018 17:34:32 +0200 Subject: [PATCH 13/30] fix unit tests Signed-off-by: Bjoern Schiessle --- apps/files_sharing/tests/Controller/ShareControllerTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/files_sharing/tests/Controller/ShareControllerTest.php b/apps/files_sharing/tests/Controller/ShareControllerTest.php index fb417878647b0..a01560d0288a8 100644 --- a/apps/files_sharing/tests/Controller/ShareControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareControllerTest.php @@ -192,6 +192,9 @@ public function testShowShareNotAuthenticated() { public function testShowShare() { + + $note = 'personal note'; + $this->shareController->setToken('token'); $owner = $this->getMockBuilder(IUser::class)->getMock(); @@ -210,6 +213,7 @@ public function testShowShare() { $share->setPassword('password') ->setShareOwner('ownerUID') ->setNode($file) + ->setNote($note) ->setTarget('/file1.txt'); $this->session->method('exists')->with('public_link_authenticated')->willReturn(true); @@ -283,6 +287,7 @@ public function testShowShare() { 'shareUrl' => null, 'previewImage' => null, 'previewURL' => 'downloadURL', + 'note' => $note ); $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); From 72d24555773aeffd2481b59e54e866632a1c763c Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 13 Jul 2018 17:53:14 +0200 Subject: [PATCH 14/30] return the as well note if we fetch a share Signed-off-by: Bjoern Schiessle --- apps/files_sharing/lib/Controller/ShareAPIController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php index 816ecde9c4044..33782d21b5f0d 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -144,6 +144,7 @@ protected function formatShare(\OCP\Share\IShare $share, Node $recipientNode = n 'expiration' => null, 'token' => null, 'uid_file_owner' => $share->getShareOwner(), + 'note' => $share->getNote(), 'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(), ]; From 4e08d8342e8582e8001df31ff6e56f40d20ccc40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Molakvo=C3=A6=20=28skjnldsv=29?= Date: Sat, 14 Jul 2018 11:45:04 +0200 Subject: [PATCH 15/30] UI set share note! MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: John Molakvoæ (skjnldsv) --- apps/files_sharing/css/sharetabview.scss | 21 ++++ core/js/core.json | 1 + core/js/merged-share-backend.json | 1 + core/js/sharedialognoteview.js | 149 +++++++++++++++++++++++ core/js/sharedialogshareelistview.js | 21 ++++ core/js/sharedialogview.js | 9 ++ 6 files changed, 202 insertions(+) create mode 100644 core/js/sharedialognoteview.js diff --git a/apps/files_sharing/css/sharetabview.scss b/apps/files_sharing/css/sharetabview.scss index b4b64daff2b0b..28cae27d405f7 100644 --- a/apps/files_sharing/css/sharetabview.scss +++ b/apps/files_sharing/css/sharetabview.scss @@ -131,6 +131,7 @@ display: none !important; } +form#newNoteForm, .linkShareView { margin-top: 16px; } @@ -142,3 +143,23 @@ .shareTabView .icon { background-size: 16px 16px; } + + +/* NOTE */ +form#newNoteForm { + display: flex; + flex-wrap: wrap; + .message { + flex: 1 1; + min-height: 76px; + margin-right: 0; + border-bottom-right-radius: 0; + border-top-right-radius: 0; + } + input { + width: 44px; + border-bottom-left-radius: 0; + border-top-left-radius: 0; + margin-left: -1px; + } +} \ No newline at end of file diff --git a/core/js/core.json b/core/js/core.json index 502e3a5797615..6a6249c294b34 100644 --- a/core/js/core.json +++ b/core/js/core.json @@ -38,6 +38,7 @@ "shareitemmodel.js", "sharedialogview.js", "sharedialogexpirationview.js", + "sharedialognoteview.js", "sharedialoglinkshareview.js", "sharedialogresharerinfoview.js", "sharedialogshareelistview.js", diff --git a/core/js/merged-share-backend.json b/core/js/merged-share-backend.json index d39945b8f7933..48ad5d5340c1f 100644 --- a/core/js/merged-share-backend.json +++ b/core/js/merged-share-backend.json @@ -5,6 +5,7 @@ "sharedialogresharerinfoview.js", "sharedialoglinkshareview.js", "sharedialogexpirationview.js", + "sharedialognoteview.js", "sharedialogshareelistview.js", "sharedialogview.js", "share.js" diff --git a/core/js/sharedialognoteview.js b/core/js/sharedialognoteview.js new file mode 100644 index 0000000000000..429d9cd942b50 --- /dev/null +++ b/core/js/sharedialognoteview.js @@ -0,0 +1,149 @@ +/* + * @copyright Copyright (c) 2018 John Molakvoæ + * + * @author John Molakvoæ + * + * @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 . + * + */ + +/* global moment, Handlebars */ + +(function() { + if (!OC.Share) { + OC.Share = {}; + } + + var TEMPLATE = + '
' + + ' ' + + ' ' + + '
' + + ' ' + ; + + /** + * @class OCA.Share.ShareDialogNoteView + * @member {OC.Share.ShareItemModel} model + * @member {jQuery} $el + * @memberof OCA.Sharing + * @classdesc + * + * Represents the expiration part in the GUI of the share dialogue + * + */ + var ShareDialogNoteView = OC.Backbone.View.extend({ + + id: 'shareNote', + + className: 'hidden', + + shareId: undefined, + + events: { + 'submit #newNoteForm': '_onSubmitComment' + }, + + _onSubmitComment: function(e) { + var self = this; + var $form = $(e.target); + var $submit = $form.find('.submit'); + var $commentField = $form.find('.message'); + var $error = $form.siblings('.error'); + var message = $commentField.val().trim(); + e.preventDefault(); + + if (message.length < 1) { + return; + } + + $submit.prop('disabled', true); + $form.addClass('icon-loading').prop('disabled', true); + + // send data + $.ajax({ + method: 'PUT', + url: OC.generateUrl('/ocs/v2.php/apps/files_sharing/api/v1/shares/' + self.shareId), + data: { note: message }, + complete : function() { + $submit.prop('disabled', false); + $form.removeClass('icon-loading').prop('disabled', false); + }, + error: function() { + $error.show(); + setTimeout(function() { + $error.hide(); + }, 3000); + } + }); + + // update local js object + var shares = this.model.get('shares'); + var share = shares.filter(function (share) { + return share.id === self.shareId; + }); + share[0].note = message; + + return message; + }, + + render: function(shareId) { + this.shareId = shareId; + var shares = this.model.get('shares'); + if (!shares) { + return; + } + var share = shares.filter(function (share) { + return share.id === shareId; + }); + if (share.length !== 1) { + // should not happend + return; + } + this.$el.show(); + this.$el.html(this.template({ + note: share[0].note, + submitText: t('core', 'Submit the note'), + placeholder: t('core', 'Add a note…'), + error: t('core', 'An error has occured. Unable to save the note.'), + shareId: shareId + })); + + this.delegateEvents(); + + return this; + }, + + hide() { + this.$el.hide(); + }, + + /** + * @returns {Function} from Handlebars + * @private + */ + template: function (data) { + if (!this._template) { + this._template = Handlebars.compile(TEMPLATE); + } + return this._template(data); + } + + }); + + OC.Share.ShareDialogNoteView = ShareDialogNoteView; + +})(); diff --git a/core/js/sharedialogshareelistview.js b/core/js/sharedialogshareelistview.js index 53a65fcdf7a47..af4abce17b60a 100644 --- a/core/js/sharedialogshareelistview.js +++ b/core/js/sharedialogshareelistview.js @@ -120,6 +120,9 @@ '
' + '' + '' + + '
  • ' + + '{{addNoteLabel}}' + + '
  • ' + '
  • ' + '{{unshareLabel}}' + '
  • ' + @@ -154,8 +157,11 @@ /** @type {boolean|number} **/ _renderPermissionChange: false, + _noteView: undefined, + events: { 'click .unshare': 'onUnshare', + 'click .addnote': 'showNoteForm', 'click .icon-more': 'onToggleMenu', 'click .permissions': 'onPermissionChange', 'click .expireDate' : 'onExpireDateChange', @@ -178,6 +184,8 @@ this.model.on('change:shares', function() { view.render(); }); + + this._noteView = options.parent.noteView; }, /** @@ -269,6 +277,7 @@ getShareProperties: function() { return { unshareLabel: t('core', 'Unshare'), + addNoteLabel: t('core', 'Set share note'), canShareLabel: t('core', 'Can reshare'), canEditLabel: t('core', 'Can edit'), createPermissionLabel: t('core', 'Can create'), @@ -470,6 +479,16 @@ return this._popoverMenuTemplate(data); }, + showNoteForm(event) { + event.preventDefault(); + event.stopPropagation(); + var self = this; + var $element = $(event.target); + var $li = $element.closest('li[data-share-id]'); + var shareId = $li.data('share-id'); + this._noteView.render(shareId); + }, + onUnshare: function(event) { event.preventDefault(); event.stopPropagation(); @@ -493,6 +512,8 @@ self.model.removeShare(shareId) .done(function() { $li.remove(); + // remove note field on sucess + self._noteView.hide(); }) .fail(function() { $loading.addClass('hidden'); diff --git a/core/js/sharedialogview.js b/core/js/sharedialogview.js index d886e45856fe6..4b5dc80e945f9 100644 --- a/core/js/sharedialogview.js +++ b/core/js/sharedialogview.js @@ -28,6 +28,7 @@ '
    ' + '
    ' + '
    ' + + '
    ' + ''; /** @@ -62,6 +63,9 @@ /** @type {object} **/ expirationView: undefined, + /** @type {object} **/ + noteView: undefined, + /** @type {object} **/ shareeListView: undefined, @@ -105,6 +109,7 @@ var subViewOptions = { model: this.model, + parent: this, configModel: this.configModel }; @@ -112,6 +117,7 @@ resharerInfoView: 'ShareDialogResharerInfoView', linkShareView: 'ShareDialogLinkShareView', expirationView: 'ShareDialogExpirationView', + noteView: 'ShareDialogNoteView', shareeListView: 'ShareDialogShareeListView' }; @@ -674,6 +680,9 @@ this.expirationView.$el = this.$el.find('.expirationView'); this.expirationView.render(); + this.noteView.$el = this.$el.find('.noteView'); + this.noteView.render(); + this.shareeListView.$el = this.$el.find('.shareeListView'); this.shareeListView.render(); From fa44300016424d5f2994bd37d13184fe13b700e2 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Fri, 13 Jul 2018 18:39:44 +0200 Subject: [PATCH 16/30] unit tests updated Signed-off-by: Bjoern Schiessle --- .../Controller/ShareAPIControllerTest.php | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php index 5d376f2d4f795..79029092947fe 100644 --- a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php @@ -238,7 +238,7 @@ public function testGetGetShareNotExists() { */ public function createShare($id, $shareType, $sharedWith, $sharedBy, $shareOwner, $path, $permissions, - $shareTime, $expiration, $parent, $target, $mail_send, $token=null, + $shareTime, $expiration, $parent, $target, $mail_send, $note = '', $token=null, $password=null) { $share = $this->getMockBuilder(IShare::class)->getMock(); $share->method('getId')->willReturn($id); @@ -248,6 +248,7 @@ public function createShare($id, $shareType, $sharedWith, $sharedBy, $shareOwner $share->method('getShareOwner')->willReturn($shareOwner); $share->method('getNode')->willReturn($path); $share->method('getPermissions')->willReturn($permissions); + $share->method('getNote')->willReturn($note); $time = new \DateTime(); $time->setTimestamp($shareTime); $share->method('getShareTime')->willReturn($time); @@ -310,7 +311,8 @@ public function dataGetShare() { null, 6, 'target', - 0 + 0, + 'personal note' ); $expected = [ 'id' => 100, @@ -334,6 +336,7 @@ public function dataGetShare() { 'storage' => 101, 'mail_send' => 0, 'uid_file_owner' => 'ownerId', + 'note' => 'personal note', 'displayname_file_owner' => 'ownerDisplay', 'mimetype' => 'myMimeType', ]; @@ -352,7 +355,8 @@ public function dataGetShare() { null, 6, 'target', - 0 + 0, + 'personal note' ); $expected = [ 'id' => 101, @@ -376,6 +380,7 @@ public function dataGetShare() { 'storage' => 101, 'mail_send' => 0, 'uid_file_owner' => 'ownerId', + 'note' => 'personal note', 'displayname_file_owner' => 'ownerDisplay', 'mimetype' => 'myFolderMimeType', ]; @@ -396,6 +401,7 @@ public function dataGetShare() { 6, 'target', 0, + 'personal note', 'token', 'password' ); @@ -422,6 +428,7 @@ public function dataGetShare() { 'mail_send' => 0, 'url' => 'url', 'uid_file_owner' => 'ownerId', + 'note' => 'personal note', 'displayname_file_owner' => 'ownerDisplay', 'mimetype' => 'myFolderMimeType', ]; @@ -455,7 +462,7 @@ public function testGetShare(\OCP\Share\IShare $share, array $result) { ->willReturn(true); $this->shareManager - ->expects($this->once()) + ->expects($this->any()) ->method('getShareById') ->with($share->getFullId(), 'currentUser') ->willReturn($share); @@ -501,6 +508,8 @@ public function testGetShare(\OCP\Share\IShare $share, array $result) { ['group', $group], ])); + $d = $ocs->getShare($share->getId())->getData()[0]; + $this->assertEquals($result, $ocs->getShare($share->getId())->getData()[0]); } @@ -1810,6 +1819,7 @@ public function dataFormatShare() { ->setNode($file) ->setShareTime(new \DateTime('2000-01-01T00:01:02')) ->setTarget('myTarget') + ->setNote('personal note') ->setId(42); /* User backend down */ @@ -1836,6 +1846,7 @@ public function dataFormatShare() { 'file_target' => 'myTarget', 'share_with' => 'recipient', 'share_with_displayname' => 'recipient', + 'note' => 'personal note', 'mail_send' => 0, 'mimetype' => 'myMimeType', ], $share, [], false @@ -1855,6 +1866,7 @@ public function dataFormatShare() { 'token' => null, 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'ownerDN', + 'note' => 'personal note', 'path' => 'file', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -1883,6 +1895,7 @@ public function dataFormatShare() { ->setNode($file) ->setShareTime(new \DateTime('2000-01-01T00:01:02')) ->setTarget('myTarget') + ->setNote('personal note') ->setId(42); /* User backend down */ @@ -1899,6 +1912,7 @@ public function dataFormatShare() { 'token' => null, 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', + 'note' => 'personal note', 'path' => 'file', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -1924,6 +1938,7 @@ public function dataFormatShare() { ->setNode($file) ->setShareTime(new \DateTime('2000-01-01T00:01:02')) ->setTarget('myTarget') + ->setNote('personal note') ->setId(42); $result[] = [ @@ -1939,6 +1954,7 @@ public function dataFormatShare() { 'token' => null, 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', + 'note' => 'personal note', 'path' => 'file', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -1964,6 +1980,7 @@ public function dataFormatShare() { ->setNode($file) ->setShareTime(new \DateTime('2000-01-01T00:01:02')) ->setTarget('myTarget') + ->setNote('personal note') ->setId(42); $result[] = [ [ @@ -1978,6 +1995,7 @@ public function dataFormatShare() { 'token' => null, 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', + 'note' => 'personal note', 'path' => 'file', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -2004,6 +2022,7 @@ public function dataFormatShare() { ->setPassword('mypassword') ->setExpirationDate(new \DateTime('2001-01-02T00:00:00')) ->setToken('myToken') + ->setNote('personal note') ->setId(42); $result[] = [ @@ -2019,6 +2038,7 @@ public function dataFormatShare() { 'token' => 'myToken', 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', + 'note' => 'personal note', 'path' => 'file', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -2044,6 +2064,7 @@ public function dataFormatShare() { ->setNode($folder) ->setShareTime(new \DateTime('2000-01-01T00:01:02')) ->setTarget('myTarget') + ->setNote('personal note') ->setId(42); $result[] = [ @@ -2059,6 +2080,7 @@ public function dataFormatShare() { 'token' => null, 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', + 'note' => 'personal note', 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -2207,6 +2229,7 @@ public function dataFormatShare() { ->setPermissions(\OCP\Constants::PERMISSION_READ) ->setShareTime(new \DateTime('2000-01-01T00:01:02')) ->setTarget('myTarget') + ->setNote('personal note') ->setId(42); $result[] = [ From 0a7e34f6c8c6e74bddfae7b6b3fd918a96c90695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Molakvo=C3=A6=20=28skjnldsv=29?= Date: Wed, 18 Jul 2018 17:42:30 +0200 Subject: [PATCH 17/30] Popovermenu migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: John Molakvoæ (skjnldsv) --- apps/files_sharing/css/sharetabview.scss | 311 ++++++++++++----------- core/css/apps.scss | 5 + core/js/core.json | 1 - core/js/merged-share-backend.json | 1 - core/js/sharedialognoteview.js | 149 ----------- core/js/sharedialogshareelistview.js | 90 ++++++- core/js/sharedialogview.js | 10 +- core/js/shareitemmodel.js | 13 + 8 files changed, 271 insertions(+), 309 deletions(-) delete mode 100644 core/js/sharedialognoteview.js diff --git a/apps/files_sharing/css/sharetabview.scss b/apps/files_sharing/css/sharetabview.scss index 28cae27d405f7..18897802f48e9 100644 --- a/apps/files_sharing/css/sharetabview.scss +++ b/apps/files_sharing/css/sharetabview.scss @@ -2,164 +2,183 @@ min-height: 100px; } -.shareTabView .oneline { - white-space: nowrap; - position: relative; -} - -.shareTabView .shareWithLoading { - padding-left: 10px; - right: 35px; - top: 0px; -} - -.shareTabView .shareWithConfirm, -.shareTabView .clipboardButton, -.shareTabView .linkPass .icon-loading-small { - position: absolute; - right: -7px; - top: -2px; - padding: 14px; -} - -.shareTabView .shareWithConfirm { - opacity: .5; -} - -.shareTabView .shareWithField:focus ~ .shareWithConfirm { - opacity: 1; -} - -.shareTabView .linkMore { - position: absolute; - right: -7px; - top: -4px; - padding: 14px; +.shareTabView { + .oneline { + white-space: nowrap; + position: relative; + } + .shareWithLoading { + padding-left: 10px; + right: 35px; + top: 0px; + } + .shareWithConfirm, + .clipboardButton, + .linkPass .icon-loading-small { + position: absolute; + right: -7px; + top: -2px; + padding: 14px; + } + .shareWithConfirm { + opacity: 0.5; + } + .shareWithField:focus ~ .shareWithConfirm { + opacity: 1; + } + .linkMore { + position: absolute; + right: -7px; + top: -4px; + padding: 14px; + } + .popovermenu { + &.socialSharingMenu { + right: -7px; + } + .clipboardButton { + position: relative; + top: initial; + right: initial; + padding: 0; + } + .share-add { + input.share-note-delete { + display: none; + border: none; + background-color: transparent; + width: 44px !important; + padding: 0; + flex: 0 0 44px; + margin-left: auto; + } + } + // note + .share-note-form { + span.icon-note { + position: relative; + } + textarea.share-note { + margin: 0; + width: 200px; + min-height: 70px; + resize: none; + + input.share-note-submit { + position: absolute; + width: 44px !important; + height: 44px; + bottom: 0px; + right: 10px; + margin: 0; + background-color: transparent; + border: none; + opacity: .7; + &:hover, + &:focus, + &:active { + opacity: 1; + } + } + } + } + } + label { + white-space: nowrap; + } + input { + &[type='checkbox'] { + margin: 0 3px 0 8px; + vertical-align: middle; + } + &[type='text'] { + &.shareWithField, + &.emailField, + &.linkText { + width: 100%; + box-sizing: border-box; + padding-right: 32px; + text-overflow: ellipsis; + } + } + &[type='password'] { + width: 100%; + box-sizing: border-box; + padding-right: 32px; + text-overflow: ellipsis; + } + } + form { + font-size: 100%; + margin-left: 0; + margin-right: 0; + } } /* fix the popup menu because the button is shifted and then the menu is not aligned */ -.shareTabView .popovermenu.socialSharingMenu { - right: -7px; -} - -.shareTabView .popovermenu .clipboardButton { - position: relative; - top: initial; - right: initial; - padding: 0; -} - -.shareTabView label { - white-space: nowrap; -} - -.shareTabView input[type="checkbox"] { - margin: 0 3px 0 8px; - vertical-align: middle; -} - -.shareTabView input[type="text"].shareWithField, -.shareTabView input[type="text"].emailField, -.shareTabView input[type="text"].linkText, -.shareTabView input[type="password"] { - width: 100%; - box-sizing: border-box; - padding-right: 32px; - text-overflow: ellipsis; -} - -.shareTabView form { - font-size: 100%; - margin-left: 0; - margin-right: 0; -} #shareWithList { list-style-type: none; padding: 0 0 16px; + > li { + padding-top: 5px; + padding-bottom: 5px; + white-space: normal; + display: inline-flex; + align-items: center; + } + .unshare img { + vertical-align: text-bottom; + /* properly align icons */ + } + .sharingOptionsGroup { + > a .icon { + padding: 7px; + vertical-align: middle; + opacity: 0.5; + } + .popovermenu:after { + right: 3px; + } + } + label input[type='checkbox'] { + margin-left: 0; + position: relative; + } + .username { + padding-right: 8px; + white-space: nowrap; + text-overflow: ellipsis; + display: inline-block; + overflow: hidden; + vertical-align: middle; + } + li .sharingOptionsGroup > .shareOption > label { + padding: 6px; + margin-right: 8px; + vertical-align: text-top; + } } -#shareWithList > li { - padding-top: 5px; - padding-bottom: 5px; - white-space: normal; - display: inline-flex; - align-items: center; -} - -#shareWithList .unshare img { - vertical-align: text-bottom; /* properly align icons */ -} - -#shareWithList .sharingOptionsGroup > a .icon { - padding: 7px; - vertical-align: middle; - opacity: .5; -} - -#shareWithList .sharingOptionsGroup .popovermenu:after { - right: 3px; -} - -#shareWithList label input[type=checkbox] { - margin-left: 0; - position: relative; -} -#shareWithList .username { - padding-right: 8px; - white-space: nowrap; - text-overflow: ellipsis; - display: inline-block; - overflow: hidden; - vertical-align: middle; -} -#shareWithList li .sharingOptionsGroup > .shareOption > label { - padding: 6px; - margin-right: 8px; - vertical-align: text-top; -} - -.shareTabView .icon-loading-small { - display: inline-block; - z-index: 1; - vertical-align: text-top; -} - -.shareTabView .shareWithList .icon-loading-small:not(.hidden) + span, -.shareTabView .linkShareView .icon-loading-small:not(.hidden) + input + label:before { - /* Hide if loader is visible */ - display: none !important; -} - -form#newNoteForm, .linkShareView { margin-top: 16px; } -.shareTabView .linkPass .icon-loading-small { - margin-right: 0px; -} - -.shareTabView .icon { - background-size: 16px 16px; -} - - -/* NOTE */ -form#newNoteForm { - display: flex; - flex-wrap: wrap; - .message { - flex: 1 1; - min-height: 76px; - margin-right: 0; - border-bottom-right-radius: 0; - border-top-right-radius: 0; +.shareTabView { + .linkPass .icon-loading-small { + margin-right: 0px; } - input { - width: 44px; - border-bottom-left-radius: 0; - border-top-left-radius: 0; - margin-left: -1px; + .icon { + background-size: 16px 16px; } -} \ No newline at end of file + .icon-loading-small { + display: inline-block; + z-index: 1; + vertical-align: text-top; + } + .shareWithList .icon-loading-small:not(.hidden) + span, + .linkShareView .icon-loading-small:not(.hidden) + input + label:before { + /* Hide if loader is visible */ + display: none !important; + } +} + diff --git a/core/css/apps.scss b/core/css/apps.scss index d524dd94bb77e..b294d8c3feed6 100644 --- a/core/css/apps.scss +++ b/core/css/apps.scss @@ -998,6 +998,11 @@ $popovericon-size: 16px; } } } + + &.hidden { + display: none; + } + /* css hack, only first not hidden*/ &:not(.hidden):not([style*='display:none']) { &:first-of-type { diff --git a/core/js/core.json b/core/js/core.json index 6a6249c294b34..502e3a5797615 100644 --- a/core/js/core.json +++ b/core/js/core.json @@ -38,7 +38,6 @@ "shareitemmodel.js", "sharedialogview.js", "sharedialogexpirationview.js", - "sharedialognoteview.js", "sharedialoglinkshareview.js", "sharedialogresharerinfoview.js", "sharedialogshareelistview.js", diff --git a/core/js/merged-share-backend.json b/core/js/merged-share-backend.json index 48ad5d5340c1f..d39945b8f7933 100644 --- a/core/js/merged-share-backend.json +++ b/core/js/merged-share-backend.json @@ -5,7 +5,6 @@ "sharedialogresharerinfoview.js", "sharedialoglinkshareview.js", "sharedialogexpirationview.js", - "sharedialognoteview.js", "sharedialogshareelistview.js", "sharedialogview.js", "share.js" diff --git a/core/js/sharedialognoteview.js b/core/js/sharedialognoteview.js deleted file mode 100644 index 429d9cd942b50..0000000000000 --- a/core/js/sharedialognoteview.js +++ /dev/null @@ -1,149 +0,0 @@ -/* - * @copyright Copyright (c) 2018 John Molakvoæ - * - * @author John Molakvoæ - * - * @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 . - * - */ - -/* global moment, Handlebars */ - -(function() { - if (!OC.Share) { - OC.Share = {}; - } - - var TEMPLATE = - '
    ' + - ' ' + - ' ' + - '
    ' + - ' ' - ; - - /** - * @class OCA.Share.ShareDialogNoteView - * @member {OC.Share.ShareItemModel} model - * @member {jQuery} $el - * @memberof OCA.Sharing - * @classdesc - * - * Represents the expiration part in the GUI of the share dialogue - * - */ - var ShareDialogNoteView = OC.Backbone.View.extend({ - - id: 'shareNote', - - className: 'hidden', - - shareId: undefined, - - events: { - 'submit #newNoteForm': '_onSubmitComment' - }, - - _onSubmitComment: function(e) { - var self = this; - var $form = $(e.target); - var $submit = $form.find('.submit'); - var $commentField = $form.find('.message'); - var $error = $form.siblings('.error'); - var message = $commentField.val().trim(); - e.preventDefault(); - - if (message.length < 1) { - return; - } - - $submit.prop('disabled', true); - $form.addClass('icon-loading').prop('disabled', true); - - // send data - $.ajax({ - method: 'PUT', - url: OC.generateUrl('/ocs/v2.php/apps/files_sharing/api/v1/shares/' + self.shareId), - data: { note: message }, - complete : function() { - $submit.prop('disabled', false); - $form.removeClass('icon-loading').prop('disabled', false); - }, - error: function() { - $error.show(); - setTimeout(function() { - $error.hide(); - }, 3000); - } - }); - - // update local js object - var shares = this.model.get('shares'); - var share = shares.filter(function (share) { - return share.id === self.shareId; - }); - share[0].note = message; - - return message; - }, - - render: function(shareId) { - this.shareId = shareId; - var shares = this.model.get('shares'); - if (!shares) { - return; - } - var share = shares.filter(function (share) { - return share.id === shareId; - }); - if (share.length !== 1) { - // should not happend - return; - } - this.$el.show(); - this.$el.html(this.template({ - note: share[0].note, - submitText: t('core', 'Submit the note'), - placeholder: t('core', 'Add a note…'), - error: t('core', 'An error has occured. Unable to save the note.'), - shareId: shareId - })); - - this.delegateEvents(); - - return this; - }, - - hide() { - this.$el.hide(); - }, - - /** - * @returns {Function} from Handlebars - * @private - */ - template: function (data) { - if (!this._template) { - this._template = Handlebars.compile(TEMPLATE); - } - return this._template(data); - } - - }); - - OC.Share.ShareDialogNoteView = ShareDialogNoteView; - -})(); diff --git a/core/js/sharedialogshareelistview.js b/core/js/sharedialogshareelistview.js index af4abce17b60a..2f561aa66eec1 100644 --- a/core/js/sharedialogshareelistview.js +++ b/core/js/sharedialogshareelistview.js @@ -121,7 +121,17 @@ '' + '' + '
  • ' + - '{{addNoteLabel}}' + + '' + + '
  • ' + + '' + '
  • ' + '{{unshareLabel}}' + @@ -161,7 +171,9 @@ events: { 'click .unshare': 'onUnshare', - 'click .addnote': 'showNoteForm', + 'click .share-add': 'showNoteForm', + 'click .share-note-delete': 'deleteNote', + 'click .share-note-submit': 'updateNote', 'click .icon-more': 'onToggleMenu', 'click .permissions': 'onPermissionChange', 'click .expireDate' : 'onExpireDateChange', @@ -269,6 +281,7 @@ isPasswordSet: hasPassword, secureDropMode: !this.model.hasReadPermission(shareIndex), hasExpireDate: this.model.getExpireDate(shareIndex) !== null, + shareNote: this.model.getNote(shareIndex), expireDate: moment(this.model.getExpireDate(shareIndex), 'YYYY-MM-DD').format('DD-MM-YYYY'), passwordPlaceholder: hasPassword ? PASSWORD_PLACEHOLDER : PASSWORD_PLACEHOLDER_MESSAGE, }); @@ -486,7 +499,78 @@ var $element = $(event.target); var $li = $element.closest('li[data-share-id]'); var shareId = $li.data('share-id'); - this._noteView.render(shareId); + var $menu = $element.closest('li'); + var $form = $menu.next('li.share-note-form'); + + // show elements + $menu.find('.share-note-delete').toggle(); + $form.toggleClass('hidden'); + }, + + deleteNote(event) { + event.preventDefault(); + event.stopPropagation(); + var self = this; + var $element = $(event.target); + var $li = $element.closest('li[data-share-id]'); + var shareId = $li.data('share-id'); + var $menu = $element.closest('li'); + var $form = $menu.next('li.share-note-form'); + + console.log($form.find('.share-note')); + $form.find('.share-note').val(''); + + self.sendNote('', shareId, $menu); + }, + + updateNote(event) { + event.preventDefault(); + event.stopPropagation(); + var self = this; + var $element = $(event.target); + var $li = $element.closest('li[data-share-id]'); + var shareId = $li.data('share-id'); + var $form = $element.closest('li.share-note-form'); + var $menu = $form.prev('li'); + var message = $form.find('.share-note').val().trim(); + + if (message.length < 1) { + return; + } + + self.sendNote(message, shareId, $menu); + + }, + + sendNote(note, shareId, $menu) { + var $form = $menu.next('li.share-note-form'); + var $submit = $form.find('input.share-note-submit'); + var $error = $form.find('input.share-note-error'); + + $submit.prop('disabled', true); + $menu.find('.icon-loading-small').removeClass('hidden'); + $menu.find('.icon-edit').hide(); + + var complete = function() { + $submit.prop('disabled', false); + $menu.find('.icon-loading-small').addClass('hidden'); + $menu.find('.icon-edit').show(); + }; + var error = function() { + $error.show(); + setTimeout(function() { + $error.hide(); + }, 3000); + }; + + // send data + $.ajax({ + method: 'PUT', + url: OC.generateUrl('/ocs/v2.php/apps/files_sharing/api/v1/shares/' + shareId), + data: { note: note }, + complete : complete, + error: error + }); }, onUnshare: function(event) { diff --git a/core/js/sharedialogview.js b/core/js/sharedialogview.js index 4b5dc80e945f9..b69bc5026c3f1 100644 --- a/core/js/sharedialogview.js +++ b/core/js/sharedialogview.js @@ -28,7 +28,6 @@ '
    ' + '
    ' + '
    ' + - '
    ' + ''; /** @@ -62,10 +61,7 @@ /** @type {object} **/ expirationView: undefined, - - /** @type {object} **/ - noteView: undefined, - + /** @type {object} **/ shareeListView: undefined, @@ -117,7 +113,6 @@ resharerInfoView: 'ShareDialogResharerInfoView', linkShareView: 'ShareDialogLinkShareView', expirationView: 'ShareDialogExpirationView', - noteView: 'ShareDialogNoteView', shareeListView: 'ShareDialogShareeListView' }; @@ -680,9 +675,6 @@ this.expirationView.$el = this.$el.find('.expirationView'); this.expirationView.render(); - this.noteView.$el = this.$el.find('.noteView'); - this.noteView.render(); - this.shareeListView.$el = this.$el.find('.shareeListView'); this.shareeListView.render(); diff --git a/core/js/shareitemmodel.js b/core/js/shareitemmodel.js index 93feba9c8897c..68e55443dd247 100644 --- a/core/js/shareitemmodel.js +++ b/core/js/shareitemmodel.js @@ -366,6 +366,10 @@ return this._shareExpireDate(shareIndex); }, + getNote: function(shareIndex) { + return this._shareNote(shareIndex); + }, + /** * Returns all share entries that only apply to the current item * (file/folder) @@ -502,6 +506,15 @@ return date2; }, + + _shareNote: function(shareIndex) { + var share = this.get('shares')[shareIndex]; + if(!_.isObject(share)) { + throw "Unknown Share"; + } + return share.note; + }, + /** * @return {int} */ From fc2767bbbb730254f19c259425783315ead35841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Molakvo=C3=A6=20=28skjnldsv=29?= Date: Wed, 18 Jul 2018 18:04:15 +0200 Subject: [PATCH 18/30] Autoresize + autoloader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: John Molakvoæ (skjnldsv) --- core/js/sharedialogshareelistview.js | 3 +++ lib/composer/composer/autoload_classmap.php | 1 + lib/composer/composer/autoload_static.php | 1 + 3 files changed, 5 insertions(+) diff --git a/core/js/sharedialogshareelistview.js b/core/js/sharedialogshareelistview.js index 2f561aa66eec1..01a96d3c3d160 100644 --- a/core/js/sharedialogshareelistview.js +++ b/core/js/sharedialogshareelistview.js @@ -457,6 +457,9 @@ this._renderPermissionChange = false; + // new note autosize + autosize(this.$el.find('.share-note-form .share-note')); + this.delegateEvents(); return this; diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 234aa418f5679..a060131979d01 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -611,6 +611,7 @@ 'OC\\Core\\Migrations\\Version14000Date20180518120534' => $baseDir . '/core/Migrations/Version14000Date20180518120534.php', 'OC\\Core\\Migrations\\Version14000Date20180522074438' => $baseDir . '/core/Migrations/Version14000Date20180522074438.php', 'OC\\Core\\Migrations\\Version14000Date20180626223656' => $baseDir . '/core/Migrations/Version14000Date20180626223656.php', + 'OC\\Core\\Migrations\\Version14000Date20180712153140' => $baseDir . '/core/Migrations/Version14000Date20180712153140.php', 'OC\\DB\\Adapter' => $baseDir . '/lib/private/DB/Adapter.php', 'OC\\DB\\AdapterMySQL' => $baseDir . '/lib/private/DB/AdapterMySQL.php', 'OC\\DB\\AdapterOCI8' => $baseDir . '/lib/private/DB/AdapterOCI8.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index c54120586f969..4c6c55a59ad64 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -641,6 +641,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Core\\Migrations\\Version14000Date20180518120534' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180518120534.php', 'OC\\Core\\Migrations\\Version14000Date20180522074438' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180522074438.php', 'OC\\Core\\Migrations\\Version14000Date20180626223656' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180626223656.php', + 'OC\\Core\\Migrations\\Version14000Date20180712153140' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180712153140.php', 'OC\\DB\\Adapter' => __DIR__ . '/../../..' . '/lib/private/DB/Adapter.php', 'OC\\DB\\AdapterMySQL' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterMySQL.php', 'OC\\DB\\AdapterOCI8' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterOCI8.php', From 967a97904fb05f3778d9b7efcef7a8f1d76f829c Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 19 Jul 2018 08:57:20 +0200 Subject: [PATCH 19/30] fix post url Signed-off-by: Bjoern Schiessle --- core/js/sharedialogshareelistview.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/js/sharedialogshareelistview.js b/core/js/sharedialogshareelistview.js index 01a96d3c3d160..88f116e83012d 100644 --- a/core/js/sharedialogshareelistview.js +++ b/core/js/sharedialogshareelistview.js @@ -504,7 +504,7 @@ var shareId = $li.data('share-id'); var $menu = $element.closest('li'); var $form = $menu.next('li.share-note-form'); - + // show elements $menu.find('.share-note-delete').toggle(); $form.toggleClass('hidden'); @@ -522,7 +522,7 @@ console.log($form.find('.share-note')); $form.find('.share-note').val(''); - + self.sendNote('', shareId, $menu); }, @@ -569,7 +569,7 @@ // send data $.ajax({ method: 'PUT', - url: OC.generateUrl('/ocs/v2.php/apps/files_sharing/api/v1/shares/' + shareId), + url: OC.linkToOCS('apps/files_sharing/api/v1/shares',2) + shareId + '?' + OC.buildQueryString({format: 'json'}), data: { note: note }, complete : complete, error: error From e951ad50340c19ecd669fba867b82f7c332a56df Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Thu, 19 Jul 2018 09:26:08 +0200 Subject: [PATCH 20/30] fix unit tests Signed-off-by: Bjoern Schiessle --- .../tests/Controller/ShareAPIControllerTest.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php index 79029092947fe..30041c3a27b99 100644 --- a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php @@ -1822,7 +1822,7 @@ public function dataFormatShare() { ->setNote('personal note') ->setId(42); - /* User backend down */ + // User backend down $result[] = [ [ 'id' => 42, @@ -1851,8 +1851,7 @@ public function dataFormatShare() { 'mimetype' => 'myMimeType', ], $share, [], false ]; - - /* User backend up */ + // User backend up $result[] = [ [ 'id' => 42, @@ -1897,8 +1896,7 @@ public function dataFormatShare() { ->setTarget('myTarget') ->setNote('personal note') ->setId(42); - - /* User backend down */ + // User backend down $result[] = [ [ 'id' => 42, @@ -1929,6 +1927,7 @@ public function dataFormatShare() { ]; // with existing group + $share = \OC::$server->getShareManager()->newShare(); $share->setShareType(\OCP\Share::SHARE_TYPE_GROUP) ->setSharedWith('recipientGroup') @@ -2123,6 +2122,7 @@ public function dataFormatShare() { 'token' => null, 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', + 'note' => '', 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -2164,6 +2164,7 @@ public function dataFormatShare() { 'token' => null, 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', + 'note' => '', 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -2205,6 +2206,7 @@ public function dataFormatShare() { 'token' => null, 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', + 'note' => '', 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -2261,6 +2263,7 @@ public function dataFormatShare() { 'token' => null, 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', + 'note' => '', 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', From c71d3dc9bf22a19745d5da40b261605fc337f44c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Molakvo=C3=A6=20=28skjnldsv=29?= Date: Thu, 19 Jul 2018 10:04:37 +0200 Subject: [PATCH 21/30] Public share MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: John Molakvoæ (skjnldsv) --- apps/files_sharing/css/sharetabview.scss | 115 ++++--- core/css/apps.scss | 1 + core/css/share.scss | 204 ------------- core/img/actions/public-white.svg | 1 + core/js/sharedialoglinkshareview.js | 371 ++++++++++++++++------- core/js/sharedialogshareelistview.js | 18 +- core/js/sharedialogview.js | 1 - 7 files changed, 325 insertions(+), 386 deletions(-) delete mode 100644 core/css/share.scss create mode 100644 core/img/actions/public-white.svg diff --git a/apps/files_sharing/css/sharetabview.scss b/apps/files_sharing/css/sharetabview.scss index 18897802f48e9..22cc58cbdc08c 100644 --- a/apps/files_sharing/css/sharetabview.scss +++ b/apps/files_sharing/css/sharetabview.scss @@ -33,9 +33,6 @@ padding: 14px; } .popovermenu { - &.socialSharingMenu { - right: -7px; - } .clipboardButton { position: relative; top: initial; @@ -80,10 +77,22 @@ } } } + // fix for popover link share + &.share-note-link { + margin-bottom: 10px; + } } } - label { - white-space: nowrap; + .linkPass .icon-loading-small { + margin-right: 0px; + } + .icon { + background-size: 16px 16px; + } + .shareWithList .icon-loading-small:not(.hidden) + span, + .linkShareView .icon-loading-small:not(.hidden) + input + label:before { + /* Hide if loader is visible */ + display: none !important; } input { &[type='checkbox'] { @@ -92,19 +101,16 @@ } &[type='text'] { &.shareWithField, - &.emailField, - &.linkText { + &.emailField { width: 100%; box-sizing: border-box; padding-right: 32px; text-overflow: ellipsis; } } - &[type='password'] { - width: 100%; - box-sizing: border-box; - padding-right: 32px; - text-overflow: ellipsis; + &[type='text'].linkText + &[type='password'].linkPassText { + width: 180px !important; } } form { @@ -114,71 +120,58 @@ } } -/* fix the popup menu because the button is shifted and then the menu is not aligned */ - +// Sharing tab users list #shareWithList { list-style-type: none; - padding: 0 0 16px; + display: flex; + flex-direction: column; > li { - padding-top: 5px; - padding-bottom: 5px; + height: 44px; white-space: normal; display: inline-flex; align-items: center; + .avatar { + width: 32px; + height: 32px; + background-color: var(--color-background-darker); + } } .unshare img { vertical-align: text-bottom; /* properly align icons */ } .sharingOptionsGroup { - > a .icon { - padding: 7px; - vertical-align: middle; - opacity: 0.5; + margin-left: auto; + display: flex; + align-items: center; + // can edit label + > .shareOption > label { + padding: 13px; + padding-right: 0; } - .popovermenu:after { - right: 3px; + // more menu + > .share-menu { + position: relative; + display: block; + .icon-more { + padding: 14px; + height: 16px; + width: 16px; + opacity: .5; + display: block; + cursor: pointer; + } + &:hover, + &:focus, + &:active { + .icon-more { + opacity: .7;; + } + } } } - label input[type='checkbox'] { - margin-left: 0; - position: relative; - } .username { - padding-right: 8px; - white-space: nowrap; - text-overflow: ellipsis; - display: inline-block; - overflow: hidden; - vertical-align: middle; - } - li .sharingOptionsGroup > .shareOption > label { - padding: 6px; - margin-right: 8px; - vertical-align: text-top; - } -} - -.linkShareView { - margin-top: 16px; -} - -.shareTabView { - .linkPass .icon-loading-small { - margin-right: 0px; - } - .icon { - background-size: 16px 16px; - } - .icon-loading-small { - display: inline-block; - z-index: 1; - vertical-align: text-top; - } - .shareWithList .icon-loading-small:not(.hidden) + span, - .linkShareView .icon-loading-small:not(.hidden) + input + label:before { - /* Hide if loader is visible */ - display: none !important; + padding: 0 8px; } } diff --git a/core/css/apps.scss b/core/css/apps.scss index b294d8c3feed6..3fd1c90e61d0c 100644 --- a/core/css/apps.scss +++ b/core/css/apps.scss @@ -963,6 +963,7 @@ $popovericon-size: 16px; > input.checkbox + label { padding: 0 !important; width: 100%; + white-space: nowrap; } > input.checkbox + label::before { margin: -2px 13px 0; diff --git a/core/css/share.scss b/core/css/share.scss deleted file mode 100644 index 07489cd55a364..0000000000000 --- a/core/css/share.scss +++ /dev/null @@ -1,204 +0,0 @@ -/** - * @copyright Copyright (c) 2016, John Molakvoæ - * @copyright Copyright (c) 2016, Morris Jobke - * @copyright Copyright (c) 2016, Julia Bode - * @copyright Copyright (c) 2016, Christoph Wurst - * @copyright Copyright (c) 2015, Hendrik Leppelsack - * @copyright Copyright (c) 2015, Jan-Christoph Borchardt - * @copyright Copyright (c) 2015, Vincent Petry - * @copyright Copyright (c) 2015, Arthur Schiwon - * @copyright Copyright (c) 2015, Roeland Jago Douma - * @copyright Copyright (c) 2015, Morris Jobke - * - * @license GNU AGPL version 3 or any later version - * - */ - -/* SHARE TAB STYLING -------------------------------------------------------- */ -.shareTabView { - .unshare.icon-loading-small { - margin-top: 1px; - } - .shareWithLoading, .linkShare .icon-loading-small { - display: inline-block !important; - padding-left: 10px; - } - .shareWithLoading { - position: relative; - right: 70px; - top: 2px; - } - .icon-loading-small.hidden { - display: none !important; - } - .avatar { - margin-right: 8px; - display: inline-block; - overflow: hidden; - vertical-align: middle; - width: 32px; - height: 32px; - } - label { - font-weight: 400; - white-space: nowrap; - } - input[type='radio'].radio + label { - margin-left: -1px; - } - input[type='checkbox'] { - margin: 0 3px 0 8px; - vertical-align: middle; - } - input[type='submit'] { - margin-left: 7px; - } - form { - font-size: 100%; - margin-left: 0; - margin-right: 0; - } - .error { - color: var(--color-error); - border-color: var(--color-error); - } - .mailView .icon-mail { - opacity: 0.5; - } -} - -.share-autocomplete-item { - display: flex; - .autocomplete-item-text { - margin-left: 10px; - margin-right: 10px; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - line-height: 32px; - vertical-align: middle; - } -} - -.ui-autocomplete .autocomplete-note { - padding: 5px 10px; - color: rgba(0, 0, 0, .3); -} - -#shareWithList { - list-style-type: none; - padding: 8px; - > li { - position: relative; - padding-top: 10px; - padding-bottom: 10px; - font-weight: bold; - line-height: 21px; - white-space: normal; - width: 100%; - } - .sharingOptionsGroup { - flex-shrink: 0; - position: relative; - .popovermenu { - right: -11px; - top: 35px; - } - } - - .shareOption { - white-space: nowrap; - display: inline-block; - } - .unshare img { - vertical-align: text-bottom; - /* properly align icons */ - } - label input[type=checkbox] { - margin-left: 0; - position: relative; - } - .username { - padding-right: 8px; - white-space: nowrap; - text-overflow: ellipsis; - display: inline-block; - overflow: hidden; - vertical-align: middle; - flex-grow: 5; - } -} - -#link { - border-top: 1px solid var(--color-border); - padding-top: 8px; - #showPassword img { - padding-left: 5px; - width: 12px; - } -} - -.reshare, -#link label, -#expiration label { - display: inline-block; - padding: 6px 4px; -} - -.resharerInfoView.subView { - position: relative; -} - -#defaultExpireMessage, .reshare { - /* fix shared by text going out of box */ - white-space: normal; -} - -#defaultExpireMessage { - /* show message on new line */ - display: block; - padding-left: 4px; - /* TODO: style the dropdown in a proper way - border-box, etc. */ - width: 90%; -} - -.ui-autocomplete { - /* limit dropdown height to 4 1/2 entries */ - max-height: 200px; - overflow-y: auto; - overflow-x: hidden; -} - -.notCreatable { - padding-left: 12px; - padding-top: 12px; - color: var(--color-text-lighter); -} - -.contactsmenu-popover { - left: -6px; - right: auto; - padding: 3px 6px; - top: 100%; - margin-top: 0; - li.hidden { - display: none !important; - } - &:after { - left: 8px; - right: auto; - } -} - -.popovermenu .datepicker { - margin-left: 35px; -} - -.popovermenu .passwordField { - margin-left: 35px; - width: inherit !important; -} - -.ui-datepicker { - z-index: 1111 !important; -} diff --git a/core/img/actions/public-white.svg b/core/img/actions/public-white.svg new file mode 100644 index 0000000000000..d85defb6a0999 --- /dev/null +++ b/core/img/actions/public-white.svg @@ -0,0 +1 @@ + diff --git a/core/js/sharedialoglinkshareview.js b/core/js/sharedialoglinkshareview.js index 5a78276a49191..be2a89cd1b925 100644 --- a/core/js/sharedialoglinkshareview.js +++ b/core/js/sharedialoglinkshareview.js @@ -21,76 +21,106 @@ var TEMPLATE = '{{#if shareAllowed}}' + - '' + - '' + - '' + - '
    ' + - '
    ' + - '' + - '' + - '{{#if singleAction}}' + - '' + - '{{else}}' + - '' + - '{{{popoverMenu}}}' + - '{{/if}}' + - '
    ' + - '{{#if publicUpload}}' + - '
    ' + - '' + - '' + - '' + - '
    ' + - '
    ' + - '' + - '' + - '' + - '
    ' + - '
    ' + - '' + - '' + - '' + - '
    ' + - '{{/if}}' + - ' {{#if publicEditing}}' + - '
    ' + - ' ' + - ' ' + - '' + - '
    ' + - ' {{/if}}' + - ' {{#if showPasswordCheckBox}}' + - '' + - '' + - ' {{/if}}' + - '
    ' + - ' ' + - ' {{#if showPasswordCheckBox}}' + - ' ' + - ' {{else}}' + - ' ' + - ' {{/if}}' + - ' ' + - '
    ' + + '
      ' + + '
    • ' + + '
      {{linkShareLabel}}' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' {{#if isLinkShare}}' + + ' ' + + ' {{/if}}' + + ' ' + + '
    • ' + + '
    ' + '{{else}}' + // FIXME: this doesn't belong in this view '{{#if noSharingPlaceholder}}{{/if}}' + '{{/if}}' ; var TEMPLATE_POPOVER_MENU = - '