diff --git a/lib/Db/ShareWrapperRequest.php b/lib/Db/ShareWrapperRequest.php index ccd9ea3f8..fad80612b 100644 --- a/lib/Db/ShareWrapperRequest.php +++ b/lib/Db/ShareWrapperRequest.php @@ -42,6 +42,8 @@ public function save(IShare $share, int $parentId = 0): int { $qb = $this->getShareInsertSql(); $qb->setValue('attributes', $qb->createNamedParameter($this->formatShareAttributes($share->getAttributes()))) ->setValue('share_type', $qb->createNamedParameter($share->getShareType())) + ->setValue('mail_send', $qb->createNamedParameter($share->getMailSend())) + ->setValue('note', $qb->createNamedParameter($share->getNote())) ->setValue('item_type', $qb->createNamedParameter($share->getNodeType())) ->setValue('item_source', $qb->createNamedParameter($share->getNodeId())) ->setValue('file_source', $qb->createNamedParameter($share->getNodeId())) diff --git a/lib/Listeners/Files/ShareCreatedSendMail.php b/lib/Listeners/Files/ShareCreatedSendMail.php index 20827c493..234d84e80 100644 --- a/lib/Listeners/Files/ShareCreatedSendMail.php +++ b/lib/Listeners/Files/ShareCreatedSendMail.php @@ -32,6 +32,9 @@ use OCA\Circles\Tools\Traits\TStringTools; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; +use OCP\Files\IRootFolder; +use OCP\IURLGenerator; +use OCP\IUser; use OCP\IUserManager; /** @template-implements IEventListener */ @@ -59,6 +62,10 @@ class ShareCreatedSendMail implements IEventListener { private $contactService; /** @var IUserManager */ private $userManager; + /** @var IURLGenerator */ + private $urlGenerator; + /** @var IRootFolder */ + private $rootFolder; public function __construct( ShareWrapperService $shareWrapperService, @@ -68,6 +75,8 @@ public function __construct( ContactService $contactService, ConfigService $configService, IUserManager $userManager, + IURLGenerator $urlGenerator, + IRootFolder $rootFolder, ) { $this->shareWrapperService = $shareWrapperService; $this->shareTokenService = $shareTokenService; @@ -76,6 +85,8 @@ public function __construct( $this->contactService = $contactService; $this->configService = $configService; $this->userManager = $userManager; + $this->urlGenerator = $urlGenerator; + $this->rootFolder = $rootFolder; $this->setup('app', Application::APP_ID); } @@ -95,8 +106,39 @@ public function handle(Event $event): void { $circle = $event->getCircle(); $clearPasswords = $event->getFederatedEvent()->getInternal()->gArray('clearPasswords'); + /** @var ShareWrapper $wrappedShare */ + $wrappedShare = $event->getFederatedEvent()->getParams()->gObj('wrappedShare', ShareWrapper::class); + $iShare = $wrappedShare->getShare($this->rootFolder, $this->userManager, $this->urlGenerator); + $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', [ + 'token' => $iShare->getToken() + ]); + $initiator = $iShare->getSharedBy(); + $initiatorUser = $this->userManager->get($initiator); + $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; + $initiatorEmail = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; foreach ($circle->getInheritedMembers(false, true) as $member) { + if ($member->getUserType() == Member::TYPE_USER && $member->isLocal()) { + $user = $this->userManager->get($member->getUserId()); + if ($user === null) { + continue; + } + $email = $user->getEMailAddress(); + if ($email === null + || $email === $initiatorEmail + ) { + continue; + } + $this->sendMailService->sendUserShareMail( + $link, + $user->getEMailAddress(), + $initiatorDisplayName, + $circle->getDisplayName(), + $initiatorEmail, + $iShare, + ); + } + if ($member->getUserType() !== Member::TYPE_MAIL && $member->getUserType() !== Member::TYPE_CONTACT) { continue; diff --git a/lib/Model/ShareWrapper.php b/lib/Model/ShareWrapper.php index c469b0e83..bd0e5e7b1 100644 --- a/lib/Model/ShareWrapper.php +++ b/lib/Model/ShareWrapper.php @@ -70,6 +70,7 @@ class ShareWrapper extends ManagedModel implements IDeserializable, IQueryRow, J private ?ShareToken $shareToken = null; private ?IAttributes $attributes = null; private bool $hideDownload = false; + private bool $mailSend = true; public function __construct() { $this->shareTime = new DateTime(); @@ -374,6 +375,16 @@ public function setHideDownload(bool $hideDownload): self { return $this; } + public function setMailSend(bool $mailSend): self { + $this->mailSend = $mailSend; + + return $this; + } + + public function getMailSend(): bool { + return $this->mailSend; + } + /** * @throws IllegalIDChangeException @@ -396,6 +407,7 @@ public function getShare( $share->setHideDownload($this->getHideDownload()); $share->setAttributes($this->getAttributes()); $share->setNote($this->getShareNote()); + $share->setMailSend($this->getMailSend()); if ($this->hasShareToken()) { $password = $this->getShareToken()->getPassword(); if ($password !== '') { diff --git a/lib/Service/SendMailService.php b/lib/Service/SendMailService.php index 30e2a8f5e..18d748834 100644 --- a/lib/Service/SendMailService.php +++ b/lib/Service/SendMailService.php @@ -23,6 +23,7 @@ use OCP\Mail\IMailer; use OCP\Security\IHasher; use OCP\Share\IManager; +use OCP\Share\IShare; use OCP\Util; class SendMailService { @@ -201,6 +202,83 @@ private function sendMailExistingShares( $this->mailer->send($message); } + /** + * Send mail notifications for the user share type + * + * @param string $link link to the file/folder + * @param string $shareWith email address of share receiver + * @param string $initiatorDisplayName name of the share creator + * @param string $circleName name of the circle shared with + * @param string|null $initiatorEmail email of the share creator + * @param IShare $share + * @throws Exception + */ + public function sendUserShareMail( + string $link, + string $shareWith, + string $initiatorDisplayName, + string $circleName, + ?string $initiatorEmail, + IShare $share, + ): void { + + $filename = $share->getNode()->getName(); + $expiration = $share->getExpirationDate(); + $note = $share->getNote(); + $l = $this->l10n; + + $message = $this->mailer->createMessage(); + + $emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [ + 'filename' => $filename, + 'link' => $link, + 'initiator' => $initiatorDisplayName, + 'expiration' => $expiration, + 'shareWith' => $shareWith, + ]); + + $emailTemplate->setSubject($l->t('%1$s shared %2$s with %3$s', [$initiatorDisplayName, $filename, $circleName])); + $emailTemplate->addHeader(); + $emailTemplate->addHeading($l->t('%1$s shared %2$s with "%3$s"', [$initiatorDisplayName, $filename, $circleName]), false); + + if ($note !== '') { + $emailTemplate->addBodyText(htmlspecialchars($note), $note); + } + + $emailTemplate->addBodyButton( + $l->t('Open %s', [$filename]), + $link + ); + + $message->setTo([$shareWith]); + + // The "From" contains the sharers name + $instanceName = $this->defaults->getName(); + $senderName = $l->t( + '%1$s via %2$s', + [ + $initiatorDisplayName, + $instanceName, + ] + ); + $message->setFrom([\OCP\Util::getDefaultEmailAddress('noreply') => $senderName]); + + // The "Reply-To" is set to the sharer if an mail address is configured + // also the default footer contains a "Do not reply" which needs to be adjusted. + if ($initiatorEmail !== null) { + $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]); + $emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : '')); + } else { + $emailTemplate->addFooter(); + } + + $message->useTemplate($emailTemplate); + $failedRecipients = $this->mailer->send($message); + if (!empty($failedRecipients)) { + return; + } + } + /** * @param Circle $circle diff --git a/lib/ShareByCircleProvider.php b/lib/ShareByCircleProvider.php index 7c6774235..5d2826fc1 100644 --- a/lib/ShareByCircleProvider.php +++ b/lib/ShareByCircleProvider.php @@ -141,6 +141,7 @@ public function create(IShare $share): IShare { $circle = $this->circleService->probeCircle($share->getSharedWith(), $circleProbe, $dataProbe); $share->setToken($this->token(15)); + $share->setMailSend(true); $owner = $circle->getInitiator(); $this->shareWrapperService->save($share); @@ -161,7 +162,6 @@ public function create(IShare $share): IShare { return $wrappedShare->getShare($this->rootFolder, $this->userManager, $this->urlGenerator); } - /** * @param IShare $share *