1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
|
6
|
|
|
/** |
7
|
|
|
* Circles - Bring cloud-users closer together. |
8
|
|
|
* |
9
|
|
|
* This file is licensed under the Affero General Public License version 3 or |
10
|
|
|
* later. See the COPYING file. |
11
|
|
|
* |
12
|
|
|
* @author Maxence Lange <[email protected]> |
13
|
|
|
* @copyright 2021 |
14
|
|
|
* @license GNU AGPL version 3 or any later version |
15
|
|
|
* |
16
|
|
|
* This program is free software: you can redistribute it and/or modify |
17
|
|
|
* it under the terms of the GNU Affero General Public License as |
18
|
|
|
* published by the Free Software Foundation, either version 3 of the |
19
|
|
|
* License, or (at your option) any later version. |
20
|
|
|
* |
21
|
|
|
* This program is distributed in the hope that it will be useful, |
22
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
23
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
24
|
|
|
* GNU Affero General Public License for more details. |
25
|
|
|
* |
26
|
|
|
* You should have received a copy of the GNU Affero General Public License |
27
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
28
|
|
|
* |
29
|
|
|
*/ |
30
|
|
|
|
31
|
|
|
|
32
|
|
|
namespace OCA\Circles\FederatedItems; |
33
|
|
|
|
34
|
|
|
|
35
|
|
|
use daita\MySmallPhpTools\Exceptions\InvalidItemException; |
36
|
|
|
use daita\MySmallPhpTools\Exceptions\RequestNetworkException; |
37
|
|
|
use daita\MySmallPhpTools\Exceptions\SignatoryException; |
38
|
|
|
use daita\MySmallPhpTools\Traits\Nextcloud\nc21\TNC21Logger; |
39
|
|
|
use daita\MySmallPhpTools\Traits\TStringTools; |
40
|
|
|
use Exception; |
41
|
|
|
use OC\User\NoUserException; |
42
|
|
|
use OCA\Circles\Db\MemberRequest; |
43
|
|
|
use OCA\Circles\Exceptions\CircleNotFoundException; |
44
|
|
|
use OCA\Circles\Exceptions\FederatedUserException; |
45
|
|
|
use OCA\Circles\Exceptions\FederatedUserNotFoundException; |
46
|
|
|
use OCA\Circles\Exceptions\InvalidIdException; |
47
|
|
|
use OCA\Circles\Exceptions\MemberAlreadyExistsException; |
48
|
|
|
use OCA\Circles\Exceptions\MemberNotFoundException; |
49
|
|
|
use OCA\Circles\Exceptions\MembersLimitException; |
50
|
|
|
use OCA\Circles\Exceptions\OwnerNotFoundException; |
51
|
|
|
use OCA\Circles\Exceptions\RemoteInstanceException; |
52
|
|
|
use OCA\Circles\Exceptions\RemoteNotFoundException; |
53
|
|
|
use OCA\Circles\Exceptions\RemoteResourceNotFoundException; |
54
|
|
|
use OCA\Circles\Exceptions\TokenDoesNotExistException; |
55
|
|
|
use OCA\Circles\Exceptions\UnknownRemoteException; |
56
|
|
|
use OCA\Circles\Exceptions\UserTypeNotFoundException; |
57
|
|
|
use OCA\Circles\IFederatedItem; |
58
|
|
|
use OCA\Circles\IFederatedItemAsyncProcess; |
59
|
|
|
use OCA\Circles\IFederatedItemMemberCheckNotRequired; |
60
|
|
|
use OCA\Circles\IFederatedItemMemberRequired; |
61
|
|
|
use OCA\Circles\IFederatedUser; |
62
|
|
|
use OCA\Circles\Model\DeprecatedCircle; |
63
|
|
|
use OCA\Circles\Model\DeprecatedMember; |
64
|
|
|
use OCA\Circles\Model\Federated\FederatedEvent; |
65
|
|
|
use OCA\Circles\Model\FederatedUser; |
66
|
|
|
use OCA\Circles\Model\Helpers\MemberHelper; |
67
|
|
|
use OCA\Circles\Model\ManagedModel; |
68
|
|
|
use OCA\Circles\Model\Member; |
69
|
|
|
use OCA\Circles\Model\SharesToken; |
70
|
|
|
use OCA\Circles\Service\CircleEventService; |
71
|
|
|
use OCA\Circles\Service\CircleService; |
72
|
|
|
use OCA\Circles\Service\ConfigService; |
73
|
|
|
use OCA\Circles\Service\FederatedUserService; |
74
|
|
|
use OCP\IUser; |
75
|
|
|
use OCP\IUserManager; |
76
|
|
|
use OCP\Mail\IEMailTemplate; |
77
|
|
|
use OCP\Util; |
78
|
|
|
|
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* Class MemberAdd |
82
|
|
|
* |
83
|
|
|
* @package OCA\Circles\GlobalScale |
84
|
|
|
*/ |
85
|
|
|
class MemberAdd implements |
86
|
|
|
IFederatedItem, |
87
|
|
|
IFederatedItemAsyncProcess, |
88
|
|
|
IFederatedItemMemberRequired, |
89
|
|
|
IFederatedItemMemberCheckNotRequired { |
90
|
|
|
|
91
|
|
|
|
92
|
|
|
use TStringTools; |
93
|
|
|
use TNC21Logger; |
94
|
|
|
|
95
|
|
|
|
96
|
|
|
/** @var IUserManager */ |
97
|
|
|
private $userManager; |
98
|
|
|
|
99
|
|
|
/** @var FederatedUserService */ |
100
|
|
|
private $federatedUserService; |
101
|
|
|
|
102
|
|
|
/** @var MemberRequest */ |
103
|
|
|
private $memberRequest; |
104
|
|
|
|
105
|
|
|
/** @var CircleService */ |
106
|
|
|
private $circleService; |
107
|
|
|
|
108
|
|
|
/** @var CircleEventService */ |
109
|
|
|
private $circleEventService; |
110
|
|
|
|
111
|
|
|
/** @var ConfigService */ |
112
|
|
|
private $configService; |
113
|
|
|
|
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* MemberAdd constructor. |
117
|
|
|
* |
118
|
|
|
* @param IUserManager $userManager |
119
|
|
|
* @param FederatedUserService $federatedUserService |
120
|
|
|
* @param MemberRequest $memberRequest |
121
|
|
|
* @param CircleService $circleService |
122
|
|
|
* @param CircleEventService $circleEventService |
123
|
|
|
* @param ConfigService $configService |
124
|
|
|
*/ |
125
|
|
|
public function __construct( |
126
|
|
|
IUserManager $userManager, FederatedUserService $federatedUserService, MemberRequest $memberRequest, |
127
|
|
|
CircleService $circleService, CircleEventService $circleEventService, ConfigService $configService |
128
|
|
|
) { |
129
|
|
|
$this->userManager = $userManager; |
130
|
|
|
$this->federatedUserService = $federatedUserService; |
131
|
|
|
$this->memberRequest = $memberRequest; |
132
|
|
|
$this->circleService = $circleService; |
133
|
|
|
$this->circleEventService = $circleEventService; |
134
|
|
|
$this->configService = $configService; |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* @param FederatedEvent $event |
140
|
|
|
* |
141
|
|
|
* @throws CircleNotFoundException |
142
|
|
|
* @throws FederatedUserException |
143
|
|
|
* @throws FederatedUserNotFoundException |
144
|
|
|
* @throws InvalidItemException |
145
|
|
|
* @throws MemberAlreadyExistsException |
146
|
|
|
* @throws MemberNotFoundException |
147
|
|
|
* @throws MembersLimitException |
148
|
|
|
* @throws OwnerNotFoundException |
149
|
|
|
* @throws RemoteInstanceException |
150
|
|
|
* @throws RemoteNotFoundException |
151
|
|
|
* @throws RemoteResourceNotFoundException |
152
|
|
|
* @throws RequestNetworkException |
153
|
|
|
* @throws SignatoryException |
154
|
|
|
* @throws UnknownRemoteException |
155
|
|
|
* @throws UserTypeNotFoundException |
156
|
|
|
*/ |
157
|
|
|
public function verify(FederatedEvent $event): void { |
158
|
|
|
$member = $event->getMember(); |
159
|
|
|
$circle = $event->getCircle(); |
160
|
|
|
$initiator = $circle->getInitiator(); |
161
|
|
|
|
162
|
|
|
$member->setCircleId($circle->getId()); |
163
|
|
|
|
164
|
|
|
$initiatorHelper = new MemberHelper($initiator); |
165
|
|
|
$initiatorHelper->mustBeModerator(); |
166
|
|
|
|
167
|
|
|
$federatedId = $member->getUserId() . '@' . $member->getInstance(); |
168
|
|
|
|
169
|
|
|
try { |
170
|
|
|
$federatedUser = |
171
|
|
|
$this->federatedUserService->getFederatedUser($federatedId, $member->getUserType()); |
172
|
|
|
} catch (MemberNotFoundException $e) { |
173
|
|
|
throw new MemberNotFoundException( |
174
|
|
|
ucfirst(Member::$DEF_TYPE[$member->getUserType()]) . ' %s not found', |
175
|
|
|
['member' => $member->getUserId() . '@' . $member->getInstance()] |
176
|
|
|
); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
$member->importFromIFederatedUser($federatedUser); |
180
|
|
|
|
181
|
|
|
try { |
182
|
|
|
$knownMember = $this->memberRequest->searchMember($member); |
|
|
|
|
183
|
|
|
// TODO: maybe member is requesting access |
184
|
|
|
throw new MemberAlreadyExistsException( |
185
|
|
|
ucfirst(Member::$DEF_TYPE[$member->getUserType()]) . ' %s is already a member', |
186
|
|
|
['member' => $member->getUserId() . '@' . $member->getInstance()] |
187
|
|
|
); |
188
|
|
|
} catch (MemberNotFoundException $e) { |
|
|
|
|
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
$member->setId($this->uuid(ManagedModel::ID_LENGTH)); |
192
|
|
|
|
193
|
|
|
// TODO: check Config on Circle to know if we set Level to 1 or just send an invitation |
194
|
|
|
$member->setLevel(Member::LEVEL_MEMBER); |
195
|
|
|
$member->setStatus(Member::STATUS_MEMBER); |
196
|
|
|
$event->setDataOutcome(['member' => $member]); |
197
|
|
|
|
198
|
|
|
// TODO: Managing cached name |
199
|
|
|
// $member->setCachedName($eventMember->getCachedName()); |
200
|
|
|
$this->circleService->confirmCircleNotFull($circle); |
201
|
|
|
|
202
|
|
|
// TODO: check if it is a member or a mail or a circle and fix the returned message |
203
|
|
|
$event->setReadingOutcome( |
204
|
|
|
ucfirst(Member::$DEF_TYPE[$member->getUserType()]) . ' ' . '\'%s\' have been added to Circle', |
205
|
|
|
['userId' => $member->getUserId()] |
206
|
|
|
); |
207
|
|
|
|
208
|
|
|
return; |
209
|
|
|
|
210
|
|
|
|
211
|
|
|
// $member = $this->membersRequest->getFreshNewMember( |
212
|
|
|
// $circle->getUniqueId(), $ident, $eventMember->getType(), $eventMember->getInstance() |
213
|
|
|
// ); |
214
|
|
|
// $member->hasToBeInviteAble() |
215
|
|
|
// |
216
|
|
|
// $this->membersService->addMemberBasedOnItsType($circle, $member); |
217
|
|
|
// |
218
|
|
|
// $password = ''; |
219
|
|
|
// $sendPasswordByMail = false; |
220
|
|
|
// if ($this->configService->enforcePasswordProtection($circle)) { |
221
|
|
|
// if ($circle->getSetting('password_single_enabled') === 'true') { |
222
|
|
|
// $password = $circle->getPasswordSingle(); |
223
|
|
|
// } else { |
224
|
|
|
// $sendPasswordByMail = true; |
225
|
|
|
// $password = $this->miscService->token(15); |
226
|
|
|
// } |
227
|
|
|
// } |
228
|
|
|
// |
229
|
|
|
// $event->setData( |
230
|
|
|
// new SimpleDataStore( |
231
|
|
|
// [ |
232
|
|
|
// 'password' => $password, |
233
|
|
|
// 'passwordByMail' => $sendPasswordByMail |
234
|
|
|
// ] |
235
|
|
|
// ) |
236
|
|
|
// ); |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
|
240
|
|
|
/** |
241
|
|
|
* @param FederatedEvent $event |
242
|
|
|
* |
243
|
|
|
* @throws InvalidIdException |
244
|
|
|
*/ |
245
|
|
|
public function manage(FederatedEvent $event): void { |
246
|
|
|
$member = $event->getMember(); |
247
|
|
|
|
248
|
|
|
try { |
249
|
|
|
$this->memberRequest->getMember($member->getId()); |
250
|
|
|
|
251
|
|
|
return; |
252
|
|
|
} catch (MemberNotFoundException $e) { |
|
|
|
|
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
try { |
256
|
|
|
$federatedUser = new FederatedUser(); |
257
|
|
|
$federatedUser->importFromIFederatedUser($member); |
258
|
|
|
$this->federatedUserService->confirmLocalSingleId($federatedUser); |
259
|
|
|
} catch (FederatedUserException $e) { |
260
|
|
|
$this->e($e, ['member' => $member]); |
261
|
|
|
|
262
|
|
|
return; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
$this->memberRequest->save($member); |
266
|
|
|
|
267
|
|
|
$this->circleEventService->onMemberAdded($event); |
268
|
|
|
|
269
|
|
|
// |
270
|
|
|
// // |
271
|
|
|
// // TODO: verifiez comment se passe le cached name sur un member_add |
272
|
|
|
// // |
273
|
|
|
// $cachedName = $member->getCachedName(); |
274
|
|
|
// $password = $event->getData() |
275
|
|
|
// ->g('password'); |
276
|
|
|
// |
277
|
|
|
// $shares = $this->generateUnknownSharesLinks($circle, $member, $password); |
278
|
|
|
// $result = [ |
279
|
|
|
// 'unknownShares' => $shares, |
280
|
|
|
// 'cachedName' => $cachedName |
281
|
|
|
// ]; |
282
|
|
|
// |
283
|
|
|
// if ($member->getType() === DeprecatedMember::TYPE_CONTACT |
284
|
|
|
// && $this->configService->isLocalInstance($member->getInstance())) { |
285
|
|
|
// $result['contact'] = $this->miscService->getInfosFromContact($member); |
286
|
|
|
// } |
287
|
|
|
// |
288
|
|
|
// $event->setResult(new SimpleDataStore($result)); |
289
|
|
|
// $this->eventsService->onMemberNew($circle, $member); |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
|
293
|
|
|
/** |
294
|
|
|
* @param FederatedEvent[] $events |
295
|
|
|
* |
296
|
|
|
* @throws Exception |
297
|
|
|
*/ |
298
|
|
|
public function result(array $events): void { |
299
|
|
|
// $password = $cachedName = ''; |
300
|
|
|
// $circle = $member = null; |
301
|
|
|
// $links = []; |
302
|
|
|
// $recipients = []; |
303
|
|
|
// foreach ($events as $event) { |
304
|
|
|
// $data = $event->getData(); |
305
|
|
|
// if ($data->gBool('passwordByMail') !== false) { |
306
|
|
|
// $password = $data->g('password'); |
307
|
|
|
// } |
308
|
|
|
// $circle = $event->getDeprecatedCircle(); |
309
|
|
|
// $member = $event->getMember(); |
310
|
|
|
// $result = $event->getResult(); |
311
|
|
|
// if ($result->g('cachedName') !== '') { |
312
|
|
|
// $cachedName = $result->g('cachedName'); |
313
|
|
|
// } |
314
|
|
|
// |
315
|
|
|
// $links = array_merge($links, $result->gArray('unknownShares')); |
316
|
|
|
// $contact = $result->gArray('contact'); |
317
|
|
|
// if (!empty($contact)) { |
318
|
|
|
// $recipients = $contact['emails']; |
319
|
|
|
// } |
320
|
|
|
// } |
321
|
|
|
// |
322
|
|
|
// if (empty($links) || $circle === null || $member === null) { |
323
|
|
|
// return; |
324
|
|
|
// } |
325
|
|
|
// |
326
|
|
|
// if ($cachedName !== '') { |
327
|
|
|
// $member->setCachedName($cachedName); |
328
|
|
|
// $this->membersService->updateMember($member); |
329
|
|
|
// } |
330
|
|
|
// |
331
|
|
|
// if ($member->getType() === DeprecatedMember::TYPE_MAIL |
332
|
|
|
// || $member->getType() === DeprecatedMember::TYPE_CONTACT) { |
333
|
|
|
// if ($member->getType() === DeprecatedMember::TYPE_MAIL) { |
334
|
|
|
// $recipients = [$member->getUserId()]; |
335
|
|
|
// } |
336
|
|
|
// |
337
|
|
|
// foreach ($recipients as $recipient) { |
338
|
|
|
// $this->memberIsMailbox($circle, $recipient, $links, $password); |
339
|
|
|
// } |
340
|
|
|
// } |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
|
344
|
|
|
/** |
345
|
|
|
* confirm the validity of a UserId, based on UserType. |
346
|
|
|
* |
347
|
|
|
* @param IFederatedUser $member |
348
|
|
|
* |
349
|
|
|
* @throws FederatedUserException |
350
|
|
|
* @throws InvalidIdException |
351
|
|
|
* @throws UserTypeNotFoundException |
352
|
|
|
* @throws CircleNotFoundException |
353
|
|
|
* @throws FederatedUserNotFoundException |
354
|
|
|
* @throws OwnerNotFoundException |
355
|
|
|
* @throws RemoteInstanceException |
356
|
|
|
* @throws RemoteNotFoundException |
357
|
|
|
* @throws RemoteResourceNotFoundException |
358
|
|
|
* @throws UnknownRemoteException |
359
|
|
|
* @throws InvalidItemException |
360
|
|
|
* @throws RequestNetworkException |
361
|
|
|
* @throws SignatoryException |
362
|
|
|
*/ |
363
|
|
|
private function confirmMember(IFederatedUser $member): void { |
364
|
|
|
|
365
|
|
|
// TODO: confirm SingleId ??? |
366
|
|
|
// switch ($member->getUserType()) { |
367
|
|
|
// case Member::TYPE_USER: |
368
|
|
|
$this->federatedUserService->getFederatedUser($member->getUserId(), $member->getUserType()); |
369
|
|
|
// break; |
370
|
|
|
// |
371
|
|
|
// // TODO: confirm other UserType |
372
|
|
|
// default: |
373
|
|
|
// break; |
374
|
|
|
//// throw new UserTypeNotFoundException(); |
375
|
|
|
// } |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
|
379
|
|
|
/** |
380
|
|
|
* @param IFederatedUser $member |
381
|
|
|
* |
382
|
|
|
* @throws NoUserException |
383
|
|
|
*/ |
384
|
|
|
private function confirmMemberTypeUser(IFederatedUser $member): void { |
385
|
|
|
if ($this->configService->isLocalInstance($member->getInstance())) { |
386
|
|
|
$user = $this->userManager->get($member->getUserId()); |
387
|
|
|
if ($user === null) { |
388
|
|
|
throw new NoUserException('user not found'); |
389
|
|
|
} |
390
|
|
|
|
391
|
|
|
$member->setUserId($user->getUID()); |
392
|
|
|
|
393
|
|
|
return; |
394
|
|
|
} |
395
|
|
|
|
396
|
|
|
// TODO #M002: request the remote instance and check that user exists |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
// /** |
400
|
|
|
// * Verify if a local account is valid. |
401
|
|
|
// * |
402
|
|
|
// * @param $ident |
403
|
|
|
// * @param $type |
404
|
|
|
// * |
405
|
|
|
// * @param string $instance |
406
|
|
|
// * |
407
|
|
|
// * @throws NoUserException |
408
|
|
|
// */ |
409
|
|
|
// private function verifyIdentLocalMember(&$ident, $type, string $instance = '') { |
410
|
|
|
// if ($type !== DeprecatedMember::TYPE_USER) { |
411
|
|
|
// return; |
412
|
|
|
// } |
413
|
|
|
// |
414
|
|
|
// if ($instance === '') { |
415
|
|
|
// try { |
416
|
|
|
// $ident = $this->miscService->getRealUserId($ident); |
417
|
|
|
// } catch (NoUserException $e) { |
418
|
|
|
// throw new NoUserException($this->l10n->t("This user does not exist")); |
419
|
|
|
// } |
420
|
|
|
// } |
421
|
|
|
// } |
422
|
|
|
// |
423
|
|
|
// |
424
|
|
|
// /** |
425
|
|
|
// * Verify if a mail have a valid format. |
426
|
|
|
// * |
427
|
|
|
// * @param string $ident |
428
|
|
|
// * @param int $type |
429
|
|
|
// * |
430
|
|
|
// * @throws EmailAccountInvalidFormatException |
431
|
|
|
// */ |
432
|
|
|
// private function verifyIdentEmailAddress(string $ident, int $type) { |
433
|
|
|
// if ($type !== DeprecatedMember::TYPE_MAIL) { |
434
|
|
|
// return; |
435
|
|
|
// } |
436
|
|
|
// |
437
|
|
|
// if ($this->configService->isAccountOnly()) { |
438
|
|
|
// throw new EmailAccountInvalidFormatException( |
439
|
|
|
// $this->l10n->t('You cannot add a mail address as member of your Circle') |
440
|
|
|
// ); |
441
|
|
|
// } |
442
|
|
|
// |
443
|
|
|
// if (!filter_var($ident, FILTER_VALIDATE_EMAIL)) { |
444
|
|
|
// throw new EmailAccountInvalidFormatException( |
445
|
|
|
// $this->l10n->t('Email format is not valid') |
446
|
|
|
// ); |
447
|
|
|
// } |
448
|
|
|
// } |
449
|
|
|
// |
450
|
|
|
// |
451
|
|
|
// /** |
452
|
|
|
// * Verify if a contact exist in current user address books. |
453
|
|
|
// * |
454
|
|
|
// * @param $ident |
455
|
|
|
// * @param $type |
456
|
|
|
// * |
457
|
|
|
// * @throws NoUserException |
458
|
|
|
// * @throws EmailAccountInvalidFormatException |
459
|
|
|
// */ |
460
|
|
|
// private function verifyIdentContact(&$ident, $type) { |
461
|
|
|
// if ($type !== DeprecatedMember::TYPE_CONTACT) { |
462
|
|
|
// return; |
463
|
|
|
// } |
464
|
|
|
// |
465
|
|
|
// if ($this->configService->isAccountOnly()) { |
466
|
|
|
// throw new EmailAccountInvalidFormatException( |
467
|
|
|
// $this->l10n->t('You cannot add a contact as member of your Circle') |
468
|
|
|
// ); |
469
|
|
|
// } |
470
|
|
|
// |
471
|
|
|
// $tmpContact = $this->userId . ':' . $ident; |
472
|
|
|
// $result = MiscService::getContactData($tmpContact); |
473
|
|
|
// if (empty($result)) { |
474
|
|
|
// throw new NoUserException($this->l10n->t("This contact is not available")); |
475
|
|
|
// } |
476
|
|
|
// |
477
|
|
|
// $ident = $tmpContact; |
478
|
|
|
// } |
479
|
|
|
|
480
|
|
|
|
481
|
|
|
/** |
482
|
|
|
* @param DeprecatedCircle $circle |
483
|
|
|
* @param string $recipient |
484
|
|
|
* @param array $links |
485
|
|
|
* @param string $password |
486
|
|
|
*/ |
487
|
|
View Code Duplication |
private function memberIsMailbox( |
|
|
|
|
488
|
|
|
DeprecatedCircle $circle, string $recipient, array $links, string $password |
489
|
|
|
) { |
490
|
|
|
if ($circle->getViewer() === null) { |
491
|
|
|
$author = $circle->getOwner() |
492
|
|
|
->getUserId(); |
493
|
|
|
} else { |
494
|
|
|
$author = $circle->getViewer() |
495
|
|
|
->getUserId(); |
496
|
|
|
} |
497
|
|
|
|
498
|
|
|
try { |
499
|
|
|
$template = $this->generateMailExitingShares($author, $circle->getName()); |
500
|
|
|
$this->fillMailExistingShares($template, $links); |
501
|
|
|
$this->sendMailExistingShares($template, $author, $recipient); |
502
|
|
|
$this->sendPasswordExistingShares($author, $recipient, $password); |
503
|
|
|
} catch (Exception $e) { |
504
|
|
|
$this->miscService->log('Failed to send mail about existing share ' . $e->getMessage()); |
|
|
|
|
505
|
|
|
} |
506
|
|
|
} |
507
|
|
|
|
508
|
|
|
|
509
|
|
|
/** |
510
|
|
|
* @param DeprecatedCircle $circle |
511
|
|
|
* @param DeprecatedMember $member |
512
|
|
|
* @param string $password |
513
|
|
|
* |
514
|
|
|
* @return array |
515
|
|
|
*/ |
516
|
|
View Code Duplication |
private function generateUnknownSharesLinks( |
|
|
|
|
517
|
|
|
DeprecatedCircle $circle, DeprecatedMember $member, string $password |
|
|
|
|
518
|
|
|
): array { |
519
|
|
|
$unknownShares = $this->getUnknownShares($member); |
520
|
|
|
|
521
|
|
|
$data = []; |
522
|
|
|
foreach ($unknownShares as $share) { |
523
|
|
|
try { |
524
|
|
|
$data[] = $this->getMailLinkFromShare($share, $member, $password); |
525
|
|
|
} catch (TokenDoesNotExistException $e) { |
|
|
|
|
526
|
|
|
} |
527
|
|
|
} |
528
|
|
|
|
529
|
|
|
return $data; |
530
|
|
|
} |
531
|
|
|
|
532
|
|
|
|
533
|
|
|
/** |
534
|
|
|
* @param DeprecatedMember $member |
535
|
|
|
* |
536
|
|
|
* @return array |
537
|
|
|
*/ |
538
|
|
View Code Duplication |
private function getUnknownShares(DeprecatedMember $member): array { |
|
|
|
|
539
|
|
|
$allShares = $this->fileSharesRequest->getSharesForCircle($member->getCircleId()); |
|
|
|
|
540
|
|
|
$knownShares = array_map( |
541
|
|
|
function(SharesToken $shareToken) { |
542
|
|
|
return $shareToken->getShareId(); |
543
|
|
|
}, |
544
|
|
|
$this->tokensRequest->getTokensFromMember($member) |
|
|
|
|
545
|
|
|
); |
546
|
|
|
|
547
|
|
|
$unknownShares = []; |
548
|
|
|
foreach ($allShares as $share) { |
549
|
|
|
if (!in_array($share['id'], $knownShares)) { |
550
|
|
|
$unknownShares[] = $share; |
551
|
|
|
} |
552
|
|
|
} |
553
|
|
|
|
554
|
|
|
return $unknownShares; |
555
|
|
|
} |
556
|
|
|
|
557
|
|
|
|
558
|
|
|
/** |
559
|
|
|
* @param array $share |
560
|
|
|
* @param DeprecatedMember $member |
561
|
|
|
* @param string $password |
562
|
|
|
* |
563
|
|
|
* @return array |
564
|
|
|
* @throws TokenDoesNotExistException |
565
|
|
|
*/ |
566
|
|
View Code Duplication |
private function getMailLinkFromShare(array $share, DeprecatedMember $member, string $password = '') { |
|
|
|
|
567
|
|
|
$sharesToken = $this->tokensRequest->generateTokenForMember($member, (int)$share['id'], $password); |
568
|
|
|
$link = $this->urlGenerator->linkToRouteAbsolute( |
|
|
|
|
569
|
|
|
'files_sharing.sharecontroller.showShare', |
570
|
|
|
['token' => $sharesToken->getToken()] |
571
|
|
|
); |
572
|
|
|
$author = $share['uid_initiator']; |
573
|
|
|
$filename = basename($share['file_target']); |
574
|
|
|
|
575
|
|
|
return [ |
576
|
|
|
'author' => $author, |
577
|
|
|
'link' => $link, |
578
|
|
|
'filename' => $filename |
579
|
|
|
]; |
580
|
|
|
} |
581
|
|
|
|
582
|
|
|
|
583
|
|
|
/** |
584
|
|
|
* @param string $author |
585
|
|
|
* @param string $circleName |
586
|
|
|
* |
587
|
|
|
* @return IEMailTemplate |
588
|
|
|
*/ |
589
|
|
View Code Duplication |
private function generateMailExitingShares(string $author, string $circleName): IEMailTemplate { |
|
|
|
|
590
|
|
|
$emailTemplate = $this->mailer->createEMailTemplate('circles.ExistingShareNotification', []); |
|
|
|
|
591
|
|
|
$emailTemplate->addHeader(); |
592
|
|
|
|
593
|
|
|
$text = $this->l10n->t('%s shared multiple files with \'%s\'.', [$author, $circleName]); |
|
|
|
|
594
|
|
|
$emailTemplate->addBodyText(htmlspecialchars($text), $text); |
595
|
|
|
|
596
|
|
|
return $emailTemplate; |
597
|
|
|
} |
598
|
|
|
|
599
|
|
|
/** |
600
|
|
|
* @param IEMailTemplate $emailTemplate |
601
|
|
|
* @param array $links |
602
|
|
|
*/ |
603
|
|
View Code Duplication |
private function fillMailExistingShares(IEMailTemplate $emailTemplate, array $links) { |
|
|
|
|
604
|
|
|
foreach ($links as $item) { |
605
|
|
|
$emailTemplate->addBodyButton( |
606
|
|
|
$this->l10n->t('Open »%s«', [htmlspecialchars($item['filename'])]), $item['link'] |
607
|
|
|
); |
608
|
|
|
} |
609
|
|
|
} |
610
|
|
|
|
611
|
|
|
|
612
|
|
|
/** |
613
|
|
|
* @param IEMailTemplate $emailTemplate |
614
|
|
|
* @param string $author |
615
|
|
|
* @param string $recipient |
616
|
|
|
* |
617
|
|
|
* @throws Exception |
618
|
|
|
*/ |
619
|
|
View Code Duplication |
private function sendMailExistingShares(IEMailTemplate $emailTemplate, string $author, string $recipient |
|
|
|
|
620
|
|
|
) { |
621
|
|
|
$subject = $this->l10n->t('%s shared multiple files with you.', [$author]); |
622
|
|
|
|
623
|
|
|
$instanceName = $this->defaults->getName(); |
|
|
|
|
624
|
|
|
$senderName = $this->l10n->t('%s on %s', [$author, $instanceName]); |
625
|
|
|
|
626
|
|
|
$message = $this->mailer->createMessage(); |
627
|
|
|
|
628
|
|
|
$message->setFrom([Util::getDefaultEmailAddress($instanceName) => $senderName]); |
629
|
|
|
$message->setSubject($subject); |
630
|
|
|
$message->setPlainBody($emailTemplate->renderText()); |
631
|
|
|
$message->setHtmlBody($emailTemplate->renderHtml()); |
632
|
|
|
$message->setTo([$recipient]); |
633
|
|
|
|
634
|
|
|
$this->mailer->send($message); |
635
|
|
|
} |
636
|
|
|
|
637
|
|
|
|
638
|
|
|
/** |
639
|
|
|
* @param string $author |
640
|
|
|
* @param string $email |
641
|
|
|
* @param string $password |
642
|
|
|
* |
643
|
|
|
* @throws Exception |
644
|
|
|
*/ |
645
|
|
|
protected function sendPasswordExistingShares(string $author, string $email, string $password) { |
646
|
|
|
if ($password === '') { |
647
|
|
|
return; |
648
|
|
|
} |
649
|
|
|
|
650
|
|
|
$message = $this->mailer->createMessage(); |
651
|
|
|
|
652
|
|
|
$authorUser = $this->userManager->get($author); |
653
|
|
|
$authorName = ($authorUser instanceof IUser) ? $authorUser->getDisplayName() : $author; |
|
|
|
|
654
|
|
|
$authorEmail = ($authorUser instanceof IUser) ? $authorUser->getEMailAddress() : null; |
|
|
|
|
655
|
|
|
|
656
|
|
|
$this->miscService->log("Sending password mail about existing files to '" . $email . "'", 0); |
657
|
|
|
|
658
|
|
|
$plainBodyPart = $this->l10n->t( |
659
|
|
|
"%1\$s shared multiple files with you.\nYou should have already received a separate mail with a link to access them.\n", |
660
|
|
|
[$authorName] |
661
|
|
|
); |
662
|
|
|
$htmlBodyPart = $this->l10n->t( |
663
|
|
|
'%1$s shared multiple files with you. You should have already received a separate mail with a link to access them.', |
664
|
|
|
[$authorName] |
665
|
|
|
); |
666
|
|
|
|
667
|
|
|
$emailTemplate = $this->mailer->createEMailTemplate( |
668
|
|
|
'sharebymail.RecipientPasswordNotification', [ |
669
|
|
|
'password' => $password, |
670
|
|
|
'author' => $author |
671
|
|
|
] |
672
|
|
|
); |
673
|
|
|
|
674
|
|
|
$emailTemplate->setSubject( |
675
|
|
|
$this->l10n->t( |
676
|
|
|
'Password to access files shared to you by %1$s', [$authorName] |
677
|
|
|
) |
678
|
|
|
); |
679
|
|
|
$emailTemplate->addHeader(); |
680
|
|
|
$emailTemplate->addHeading($this->l10n->t('Password to access files'), false); |
681
|
|
|
$emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart); |
682
|
|
|
$emailTemplate->addBodyText($this->l10n->t('It is protected with the following password:')); |
683
|
|
|
$emailTemplate->addBodyText($password); |
684
|
|
|
|
685
|
|
|
// The "From" contains the sharers name |
686
|
|
|
$instanceName = $this->defaults->getName(); |
687
|
|
|
$senderName = $this->l10n->t( |
688
|
|
|
'%1$s via %2$s', |
689
|
|
|
[ |
690
|
|
|
$authorName, |
691
|
|
|
$instanceName |
692
|
|
|
] |
693
|
|
|
); |
694
|
|
|
|
695
|
|
|
$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
696
|
|
|
if ($authorEmail !== null) { |
697
|
|
|
$message->setReplyTo([$authorEmail => $authorName]); |
698
|
|
|
$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); |
699
|
|
|
} else { |
700
|
|
|
$emailTemplate->addFooter(); |
701
|
|
|
} |
702
|
|
|
|
703
|
|
|
$message->setTo([$email]); |
704
|
|
|
$message->useTemplate($emailTemplate); |
705
|
|
|
$this->mailer->send($message); |
706
|
|
|
} |
707
|
|
|
|
708
|
|
|
} |
709
|
|
|
|
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.
Both the
$myVar
assignment in line 1 and the$higher
assignment in line 2 are dead. The first because$myVar
is never used and the second because$higher
is always overwritten for every possible time line.