Skip to content

Commit 0ce3818

Browse files
authored
Merge pull request #2050 from nextcloud/feature/notify-internal-users-on-circle-share
feature: send email to internal users of circles when shared with circle
2 parents 014aaf4 + c5828fc commit 0ce3818

5 files changed

Lines changed: 135 additions & 1 deletion

File tree

lib/Db/ShareWrapperRequest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public function save(IShare $share, int $parentId = 0): int {
4242
$qb = $this->getShareInsertSql();
4343
$qb->setValue('attributes', $qb->createNamedParameter($this->formatShareAttributes($share->getAttributes())))
4444
->setValue('share_type', $qb->createNamedParameter($share->getShareType()))
45+
->setValue('mail_send', $qb->createNamedParameter($share->getMailSend()))
46+
->setValue('note', $qb->createNamedParameter($share->getNote()))
4547
->setValue('item_type', $qb->createNamedParameter($share->getNodeType()))
4648
->setValue('item_source', $qb->createNamedParameter($share->getNodeId()))
4749
->setValue('file_source', $qb->createNamedParameter($share->getNodeId()))

lib/Listeners/Files/ShareCreatedSendMail.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
use OCA\Circles\Tools\Traits\TStringTools;
3333
use OCP\EventDispatcher\Event;
3434
use OCP\EventDispatcher\IEventListener;
35+
use OCP\Files\IRootFolder;
36+
use OCP\IURLGenerator;
37+
use OCP\IUser;
3538
use OCP\IUserManager;
3639

3740
/** @template-implements IEventListener<FileShareCreatedEvent|Event> */
@@ -59,6 +62,10 @@ class ShareCreatedSendMail implements IEventListener {
5962
private $contactService;
6063
/** @var IUserManager */
6164
private $userManager;
65+
/** @var IURLGenerator */
66+
private $urlGenerator;
67+
/** @var IRootFolder */
68+
private $rootFolder;
6269

6370
public function __construct(
6471
ShareWrapperService $shareWrapperService,
@@ -68,6 +75,8 @@ public function __construct(
6875
ContactService $contactService,
6976
ConfigService $configService,
7077
IUserManager $userManager,
78+
IURLGenerator $urlGenerator,
79+
IRootFolder $rootFolder,
7180
) {
7281
$this->shareWrapperService = $shareWrapperService;
7382
$this->shareTokenService = $shareTokenService;
@@ -76,6 +85,8 @@ public function __construct(
7685
$this->contactService = $contactService;
7786
$this->configService = $configService;
7887
$this->userManager = $userManager;
88+
$this->urlGenerator = $urlGenerator;
89+
$this->rootFolder = $rootFolder;
7990

8091
$this->setup('app', Application::APP_ID);
8192
}
@@ -95,8 +106,39 @@ public function handle(Event $event): void {
95106

96107
$circle = $event->getCircle();
97108
$clearPasswords = $event->getFederatedEvent()->getInternal()->gArray('clearPasswords');
109+
/** @var ShareWrapper $wrappedShare */
110+
$wrappedShare = $event->getFederatedEvent()->getParams()->gObj('wrappedShare', ShareWrapper::class);
111+
$iShare = $wrappedShare->getShare($this->rootFolder, $this->userManager, $this->urlGenerator);
112+
$link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', [
113+
'token' => $iShare->getToken()
114+
]);
115+
$initiator = $iShare->getSharedBy();
116+
$initiatorUser = $this->userManager->get($initiator);
117+
$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
118+
$initiatorEmail = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
98119

99120
foreach ($circle->getInheritedMembers(false, true) as $member) {
121+
if ($member->getUserType() == Member::TYPE_USER && $member->isLocal()) {
122+
$user = $this->userManager->get($member->getUserId());
123+
if ($user === null) {
124+
continue;
125+
}
126+
$email = $user->getEMailAddress();
127+
if ($email === null
128+
|| $email === $initiatorEmail
129+
) {
130+
continue;
131+
}
132+
$this->sendMailService->sendUserShareMail(
133+
$link,
134+
$user->getEMailAddress(),
135+
$initiatorDisplayName,
136+
$circle->getDisplayName(),
137+
$initiatorEmail,
138+
$iShare,
139+
);
140+
}
141+
100142
if ($member->getUserType() !== Member::TYPE_MAIL
101143
&& $member->getUserType() !== Member::TYPE_CONTACT) {
102144
continue;

lib/Model/ShareWrapper.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class ShareWrapper extends ManagedModel implements IDeserializable, IQueryRow, J
7070
private ?ShareToken $shareToken = null;
7171
private ?IAttributes $attributes = null;
7272
private bool $hideDownload = false;
73+
private bool $mailSend = true;
7374

7475
public function __construct() {
7576
$this->shareTime = new DateTime();
@@ -374,6 +375,16 @@ public function setHideDownload(bool $hideDownload): self {
374375
return $this;
375376
}
376377

378+
public function setMailSend(bool $mailSend): self {
379+
$this->mailSend = $mailSend;
380+
381+
return $this;
382+
}
383+
384+
public function getMailSend(): bool {
385+
return $this->mailSend;
386+
}
387+
377388

378389
/**
379390
* @throws IllegalIDChangeException
@@ -396,6 +407,7 @@ public function getShare(
396407
$share->setHideDownload($this->getHideDownload());
397408
$share->setAttributes($this->getAttributes());
398409
$share->setNote($this->getShareNote());
410+
$share->setMailSend($this->getMailSend());
399411
if ($this->hasShareToken()) {
400412
$password = $this->getShareToken()->getPassword();
401413
if ($password !== '') {

lib/Service/SendMailService.php

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use OCP\Mail\IMailer;
2424
use OCP\Security\IHasher;
2525
use OCP\Share\IManager;
26+
use OCP\Share\IShare;
2627
use OCP\Util;
2728

2829
class SendMailService {
@@ -201,6 +202,83 @@ private function sendMailExistingShares(
201202
$this->mailer->send($message);
202203
}
203204

205+
/**
206+
* Send mail notifications for the user share type
207+
*
208+
* @param string $link link to the file/folder
209+
* @param string $shareWith email address of share receiver
210+
* @param string $initiatorDisplayName name of the share creator
211+
* @param string $circleName name of the circle shared with
212+
* @param string|null $initiatorEmail email of the share creator
213+
* @param IShare $share
214+
* @throws Exception
215+
*/
216+
public function sendUserShareMail(
217+
string $link,
218+
string $shareWith,
219+
string $initiatorDisplayName,
220+
string $circleName,
221+
?string $initiatorEmail,
222+
IShare $share,
223+
): void {
224+
225+
$filename = $share->getNode()->getName();
226+
$expiration = $share->getExpirationDate();
227+
$note = $share->getNote();
228+
$l = $this->l10n;
229+
230+
$message = $this->mailer->createMessage();
231+
232+
$emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [
233+
'filename' => $filename,
234+
'link' => $link,
235+
'initiator' => $initiatorDisplayName,
236+
'expiration' => $expiration,
237+
'shareWith' => $shareWith,
238+
]);
239+
240+
$emailTemplate->setSubject($l->t('%1$s shared %2$s with %3$s', [$initiatorDisplayName, $filename, $circleName]));
241+
$emailTemplate->addHeader();
242+
$emailTemplate->addHeading($l->t('%1$s shared %2$s with "%3$s"', [$initiatorDisplayName, $filename, $circleName]), false);
243+
244+
if ($note !== '') {
245+
$emailTemplate->addBodyText(htmlspecialchars($note), $note);
246+
}
247+
248+
$emailTemplate->addBodyButton(
249+
$l->t('Open %s', [$filename]),
250+
$link
251+
);
252+
253+
$message->setTo([$shareWith]);
254+
255+
// The "From" contains the sharers name
256+
$instanceName = $this->defaults->getName();
257+
$senderName = $l->t(
258+
'%1$s via %2$s',
259+
[
260+
$initiatorDisplayName,
261+
$instanceName,
262+
]
263+
);
264+
$message->setFrom([\OCP\Util::getDefaultEmailAddress('noreply') => $senderName]);
265+
266+
// The "Reply-To" is set to the sharer if an mail address is configured
267+
// also the default footer contains a "Do not reply" which needs to be adjusted.
268+
if ($initiatorEmail !== null) {
269+
$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
270+
$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : ''));
271+
} else {
272+
$emailTemplate->addFooter();
273+
}
274+
275+
$message->useTemplate($emailTemplate);
276+
$failedRecipients = $this->mailer->send($message);
277+
if (!empty($failedRecipients)) {
278+
return;
279+
}
280+
}
281+
204282

205283
/**
206284
* @param Circle $circle

lib/ShareByCircleProvider.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ public function create(IShare $share): IShare {
141141

142142
$circle = $this->circleService->probeCircle($share->getSharedWith(), $circleProbe, $dataProbe);
143143
$share->setToken($this->token(15));
144+
$share->setMailSend(true);
144145
$owner = $circle->getInitiator();
145146
$this->shareWrapperService->save($share);
146147

@@ -161,7 +162,6 @@ public function create(IShare $share): IShare {
161162
return $wrappedShare->getShare($this->rootFolder, $this->userManager, $this->urlGenerator);
162163
}
163164

164-
165165
/**
166166
* @param IShare $share
167167
*

0 commit comments

Comments
 (0)