Completed
Push — master ( ad24b8...a3569a )
by Lukas
67:23 queued 28:25
created

ShareByMailProvider::removeShareFromTable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 1
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016 Bjoern Schiessle <[email protected]>
4
 *
5
 * @license GNU AGPL version 3 or any later version
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Affero General Public License as
9
 * published by the Free Software Foundation, either version 3 of the
10
 * License, or (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 *
20
 */
21
22
namespace OCA\ShareByMail;
23
24
use OC\HintException;
25
use OC\Share20\Exception\InvalidShare;
26
use OCA\ShareByMail\Settings\SettingsManager;
27
use OCP\Activity\IManager;
28
use OCP\DB\QueryBuilder\IQueryBuilder;
29
use OCP\Defaults;
30
use OCP\Files\Folder;
31
use OCP\Files\IRootFolder;
32
use OCP\Files\Node;
33
use OCP\IDBConnection;
34
use OCP\IL10N;
35
use OCP\ILogger;
36
use OCP\IURLGenerator;
37
use OCP\IUser;
38
use OCP\IUserManager;
39
use OCP\Mail\IMailer;
40
use OCP\Security\ISecureRandom;
41
use OC\Share20\Share;
42
use OCP\Share\Exceptions\ShareNotFound;
43
use OCP\Share\IShare;
44
use OCP\Share\IShareProvider;
45
use OCP\Template;
46
47
/**
48
 * Class ShareByMail
49
 *
50
 * @package OCA\ShareByMail
51
 */
52
class ShareByMailProvider implements IShareProvider {
53
54
	/** @var  IDBConnection */
55
	private $dbConnection;
56
57
	/** @var ILogger */
58
	private $logger;
59
60
	/** @var ISecureRandom */
61
	private $secureRandom;
62
63
	/** @var IUserManager */
64
	private $userManager;
65
66
	/** @var IRootFolder */
67
	private $rootFolder;
68
69
	/** @var IL10N */
70
	private $l;
71
72
	/** @var IMailer */
73
	private $mailer;
74
75
	/** @var IURLGenerator */
76
	private $urlGenerator;
77
78
	/** @var IManager  */
79
	private $activityManager;
80
81
	/** @var SettingsManager */
82
	private $settingsManager;
83
84
	/** @var Defaults */
85
	private $defaults;
86
87
	/**
88
	 * Return the identifier of this provider.
89
	 *
90
	 * @return string Containing only [a-zA-Z0-9]
91
	 */
92
	public function identifier() {
93
		return 'ocMailShare';
94
	}
95
96
	/**
97
	 * DefaultShareProvider constructor.
98
	 *
99
	 * @param IDBConnection $connection
100
	 * @param ISecureRandom $secureRandom
101
	 * @param IUserManager $userManager
102
	 * @param IRootFolder $rootFolder
103
	 * @param IL10N $l
104
	 * @param ILogger $logger
105
	 * @param IMailer $mailer
106
	 * @param IURLGenerator $urlGenerator
107
	 * @param IManager $activityManager
108
	 * @param SettingsManager $settingsManager
109
	 * @param Defaults $defaults
110
	 */
111 View Code Duplication
	public function __construct(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
112
		IDBConnection $connection,
113
		ISecureRandom $secureRandom,
114
		IUserManager $userManager,
115
		IRootFolder $rootFolder,
116
		IL10N $l,
117
		ILogger $logger,
118
		IMailer $mailer,
119
		IURLGenerator $urlGenerator,
120
		IManager $activityManager,
121
		SettingsManager $settingsManager,
122
		Defaults $defaults
123
	) {
124
		$this->dbConnection = $connection;
125
		$this->secureRandom = $secureRandom;
126
		$this->userManager = $userManager;
127
		$this->rootFolder = $rootFolder;
128
		$this->l = $l;
129
		$this->logger = $logger;
130
		$this->mailer = $mailer;
131
		$this->urlGenerator = $urlGenerator;
132
		$this->activityManager = $activityManager;
133
		$this->settingsManager = $settingsManager;
134
		$this->defaults = $defaults;
135
	}
136
137
	/**
138
	 * Share a path
139
	 *
140
	 * @param IShare $share
141
	 * @return IShare The share object
142
	 * @throws ShareNotFound
143
	 * @throws \Exception
144
	 */
145
	public function create(IShare $share) {
146
147
		$shareWith = $share->getSharedWith();
148
		/*
149
		 * Check if file is not already shared with the remote user
150
		 */
151
		$alreadyShared = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_EMAIL, $share->getNode(), 1, 0);
152 View Code Duplication
		if (!empty($alreadyShared)) {
153
			$message = 'Sharing %s failed, this item is already shared with %s';
154
			$message_t = $this->l->t('Sharing %s failed, this item is already shared with %s', array($share->getNode()->getName(), $shareWith));
155
			$this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
156
			throw new \Exception($message_t);
157
		}
158
159
		$shareId = $this->createMailShare($share);
160
		$this->createActivity($share);
161
		$data = $this->getRawShare($shareId);
162
		return $this->createShareObject($data);
163
164
	}
165
166
	/**
167
	 * create activity if a file/folder was shared by mail
168
	 *
169
	 * @param IShare $share
170
	 */
171
	protected function createActivity(IShare $share) {
172
173
		$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
174
175
		$this->publishActivity(
176
			Activity::SUBJECT_SHARED_EMAIL_SELF,
177
			[$userFolder->getRelativePath($share->getNode()->getPath()), $share->getSharedWith()],
178
			$share->getSharedBy(),
179
			$share->getNode()->getId(),
180
			$userFolder->getRelativePath($share->getNode()->getPath())
181
		);
182
183
		if ($share->getShareOwner() !== $share->getSharedBy()) {
184
			$ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
185
			$fileId = $share->getNode()->getId();
186
			$nodes = $ownerFolder->getById($fileId);
187
			$ownerPath = $nodes[0]->getPath();
188
			$this->publishActivity(
189
				Activity::SUBJECT_SHARED_EMAIL_BY,
190
				[$ownerFolder->getRelativePath($ownerPath), $share->getSharedWith(), $share->getSharedBy()],
191
				$share->getShareOwner(),
192
				$fileId,
193
				$ownerFolder->getRelativePath($ownerPath)
194
			);
195
		}
196
197
	}
198
199
	/**
200
	 * publish activity if a file/folder was shared by mail
201
	 *
202
	 * @param $subject
203
	 * @param $parameters
204
	 * @param $affectedUser
205
	 * @param $fileId
206
	 * @param $filePath
207
	 */
208 View Code Duplication
	protected function publishActivity($subject, $parameters, $affectedUser, $fileId, $filePath) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
209
		$event = $this->activityManager->generateEvent();
210
		$event->setApp('sharebymail')
211
			->setType('shared')
212
			->setSubject($subject, $parameters)
213
			->setAffectedUser($affectedUser)
214
			->setObject('files', $fileId, $filePath);
215
		$this->activityManager->publish($event);
216
217
	}
218
219
	/**
220
	 * @param IShare $share
221
	 * @return int
222
	 * @throws \Exception
223
	 */
224
	protected function createMailShare(IShare $share) {
225
		$share->setToken($this->generateToken());
226
		$shareId = $this->addShareToDB(
227
			$share->getNodeId(),
228
			$share->getNodeType(),
229
			$share->getSharedWith(),
230
			$share->getSharedBy(),
231
			$share->getShareOwner(),
232
			$share->getPermissions(),
233
			$share->getToken()
234
		);
235
236
		try {
237
			$link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare',
238
				['token' => $share->getToken()]);
239
			$this->sendMailNotification(
240
				$share->getNode()->getName(),
241
				$link,
242
				$share->getShareOwner(),
243
				$share->getSharedBy(),
244
				$share->getSharedWith()
245
			);
246
		} catch (HintException $hintException) {
247
			$this->logger->error('Failed to send share by mail: ' . $hintException->getMessage());
248
			$this->removeShareFromTable($shareId);
249
			throw $hintException;
250
		} catch (\Exception $e) {
251
			$this->logger->error('Failed to send share by mail: ' . $e->getMessage());
252
			$this->removeShareFromTable($shareId);
253
			throw new HintException('Failed to send share by mail',
254
				$this->l->t('Failed to send share by E-mail'));
255
		}
256
257
		return $shareId;
258
259
	}
260
261
	/**
262
	 * @param string $filename
263
	 * @param string $link
264
	 * @param string $owner
265
	 * @param string $initiator
266
	 * @param string $shareWith
267
	 * @throws \Exception If mail couldn't be sent
268
	 */
269
	protected function sendMailNotification($filename,
270
											$link,
271
											$owner,
272
											$initiator,
273
											$shareWith) {
274
		$ownerUser = $this->userManager->get($owner);
275
		$initiatorUser = $this->userManager->get($initiator);
276
		$ownerDisplayName = ($ownerUser instanceof IUser) ? $ownerUser->getDisplayName() : $owner;
277
		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
278 View Code Duplication
		if ($owner === $initiator) {
279
			$subject = (string)$this->l->t('%s shared »%s« with you', array($ownerDisplayName, $filename));
280
		} else {
281
			$subject = (string)$this->l->t('%s shared »%s« with you on behalf of %s', array($ownerDisplayName, $filename, $initiatorDisplayName));
282
		}
283
284
		$message = $this->mailer->createMessage();
285
286
		$emailTemplate = $this->mailer->createEMailTemplate();
287
288
		$emailTemplate->addHeader();
289
		$emailTemplate->addHeading($this->l->t('%s shared »%s« with you', [$ownerDisplayName, $filename]), false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
290
291 View Code Duplication
		if ($owner === $initiator) {
292
			$text = $this->l->t('%s shared »%s« with you.', [$ownerDisplayName, $filename]);
293
		} else {
294
			$text= $this->l->t('%s shared »%s« with you on behalf of %s.', [$ownerDisplayName, $filename, $initiator]);
295
		}
296
297
		$emailTemplate->addBodyText(
298
			$text . ' ' . $this->l->t('Click the button below to open it.'),
299
			$text
300
		);
301
302
		$emailTemplate->addBodyButton(
303
			$this->l->t('Open »%s«', [$filename]),
304
			$link
305
		);
306
307
		$message->setTo([$shareWith]);
308
309
		// The "From" contains the sharers name
310
		$instanceName = $this->defaults->getName();
311
		$senderName = $this->l->t(
312
			'%s via %s',
313
			[
314
				$ownerDisplayName,
315
				$instanceName
316
			]
317
		);
318
		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
319
320
		// The "Reply-To" is set to the sharer if an mail address is configured
321
		// also the default footer contains a "Do not reply" which needs to be adjusted.
322
		$ownerEmail = $ownerUser->getEMailAddress();
323
		if($ownerEmail !== null) {
324
			$message->setReplyTo([$ownerEmail => $ownerDisplayName]);
325
			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
326
		} else {
327
			$emailTemplate->addFooter();
328
		}
329
330
		$message->setSubject($subject);
331
		$message->setPlainBody($emailTemplate->renderText());
332
		$message->setHtmlBody($emailTemplate->renderHTML());
333
		$this->mailer->send($message);
334
	}
335
336
	/**
337
	 * send password to recipient of a mail share
338
	 *
339
	 * @param string $filename
340
	 * @param string $initiator
341
	 * @param string $shareWith
342
	 */
343
	protected function sendPassword($filename, $initiator, $shareWith, $password) {
344
345
		if ($this->settingsManager->sendPasswordByMail() === false) {
346
			return;
347
		}
348
349
		$initiatorUser = $this->userManager->get($initiator);
350
		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
351
		$subject = (string)$this->l->t('Password to access »%s« shared to you by %s', [$filename, $initiatorDisplayName]);
352
353
		$message = $this->mailer->createMessage();
354
355
		$emailTemplate = $this->mailer->createEMailTemplate();
356
357
		$emailTemplate->addHeader();
358
		$emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]));
359
360
		$emailTemplate->addBodyText($this->l->t(
361
			'%s shared »%s« with you. You should have already received a separate mail with a link to access it.',
362
				[$initiatorDisplayName, $filename]
363
		));
364
		$emailTemplate->addBodyText($this->l->t('It is protected with the following password: %s', [$password]));
365
366
		$emailTemplate->addFooter();
367
368
		$message->setTo([$shareWith]);
369
		$message->setSubject($subject);
370
		$message->setBody($emailTemplate->renderText(), 'text/plain');
371
		$message->setHtmlBody($emailTemplate->renderHTML());
372
		$this->mailer->send($message);
373
374
	}
375
376
377
	/**
378
	 * generate share token
379
	 *
380
	 * @return string
381
	 */
382
	protected function generateToken() {
383
		$token = $this->secureRandom->generate(
384
			15, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS);
385
		return $token;
386
	}
387
388
	/**
389
	 * Get all children of this share
390
	 *
391
	 * @param IShare $parent
392
	 * @return IShare[]
393
	 */
394 View Code Duplication
	public function getChildren(IShare $parent) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
395
		$children = [];
396
397
		$qb = $this->dbConnection->getQueryBuilder();
398
		$qb->select('*')
399
			->from('share')
400
			->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
401
			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
402
			->orderBy('id');
403
404
		$cursor = $qb->execute();
405
		while($data = $cursor->fetch()) {
406
			$children[] = $this->createShareObject($data);
407
		}
408
		$cursor->closeCursor();
409
410
		return $children;
411
	}
412
413
	/**
414
	 * add share to the database and return the ID
415
	 *
416
	 * @param int $itemSource
417
	 * @param string $itemType
418
	 * @param string $shareWith
419
	 * @param string $sharedBy
420
	 * @param string $uidOwner
421
	 * @param int $permissions
422
	 * @param string $token
423
	 * @return int
424
	 */
425 View Code Duplication
	protected function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
426
		$qb = $this->dbConnection->getQueryBuilder();
427
		$qb->insert('share')
428
			->setValue('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
429
			->setValue('item_type', $qb->createNamedParameter($itemType))
430
			->setValue('item_source', $qb->createNamedParameter($itemSource))
431
			->setValue('file_source', $qb->createNamedParameter($itemSource))
432
			->setValue('share_with', $qb->createNamedParameter($shareWith))
433
			->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
434
			->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
435
			->setValue('permissions', $qb->createNamedParameter($permissions))
436
			->setValue('token', $qb->createNamedParameter($token))
437
			->setValue('stime', $qb->createNamedParameter(time()));
438
439
		/*
440
		 * Added to fix https://github.com/owncloud/core/issues/22215
441
		 * Can be removed once we get rid of ajax/share.php
442
		 */
443
		$qb->setValue('file_target', $qb->createNamedParameter(''));
444
445
		$qb->execute();
446
		$id = $qb->getLastInsertId();
447
448
		return (int)$id;
449
	}
450
451
	/**
452
	 * Update a share
453
	 *
454
	 * @param IShare $share
455
	 * @param string|null $plainTextPassword
456
	 * @return IShare The share object
457
	 */
458
	public function update(IShare $share, $plainTextPassword = null) {
459
460
		$originalShare = $this->getShareById($share->getId());
461
462
		// a real password was given
463
		$validPassword = $plainTextPassword !== null && $plainTextPassword !== '';
464
465
		if($validPassword && $originalShare->getPassword() !== $share->getPassword()) {
466
			$this->sendPassword($share->getNode()->getName(), $share->getSharedBy(), $share->getSharedWith(), $plainTextPassword);
467
		}
468
		/*
469
		 * We allow updating the permissions and password of mail shares
470
		 */
471
		$qb = $this->dbConnection->getQueryBuilder();
472
		$qb->update('share')
473
			->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
474
			->set('permissions', $qb->createNamedParameter($share->getPermissions()))
475
			->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
476
			->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
477
			->set('password', $qb->createNamedParameter($share->getPassword()))
478
			->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
479
			->execute();
480
481
		return $share;
482
	}
483
484
	/**
485
	 * @inheritdoc
486
	 */
487
	public function move(IShare $share, $recipient) {
488
		/**
489
		 * nothing to do here, mail shares are only outgoing shares
490
		 */
491
		return $share;
492
	}
493
494
	/**
495
	 * Delete a share (owner unShares the file)
496
	 *
497
	 * @param IShare $share
498
	 */
499
	public function delete(IShare $share) {
500
		$this->removeShareFromTable($share->getId());
501
	}
502
503
	/**
504
	 * @inheritdoc
505
	 */
506
	public function deleteFromSelf(IShare $share, $recipient) {
507
		// nothing to do here, mail shares are only outgoing shares
508
		return;
509
	}
510
511
	/**
512
	 * @inheritdoc
513
	 */
514 View Code Duplication
	public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
515
		$qb = $this->dbConnection->getQueryBuilder();
516
		$qb->select('*')
517
			->from('share');
518
519
		$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
520
521
		/**
522
		 * Reshares for this user are shares where they are the owner.
523
		 */
524
		if ($reshares === false) {
525
			//Special case for old shares created via the web UI
526
			$or1 = $qb->expr()->andX(
527
				$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
528
				$qb->expr()->isNull('uid_initiator')
529
			);
530
531
			$qb->andWhere(
532
				$qb->expr()->orX(
533
					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
534
					$or1
535
				)
536
			);
537
		} else {
538
			$qb->andWhere(
539
				$qb->expr()->orX(
540
					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
541
					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
542
				)
543
			);
544
		}
545
546
		if ($node !== null) {
547
			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
548
		}
549
550
		if ($limit !== -1) {
551
			$qb->setMaxResults($limit);
552
		}
553
554
		$qb->setFirstResult($offset);
555
		$qb->orderBy('id');
556
557
		$cursor = $qb->execute();
558
		$shares = [];
559
		while($data = $cursor->fetch()) {
560
			$shares[] = $this->createShareObject($data);
561
		}
562
		$cursor->closeCursor();
563
564
		return $shares;
565
	}
566
567
	/**
568
	 * @inheritdoc
569
	 */
570 View Code Duplication
	public function getShareById($id, $recipientId = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
571
		$qb = $this->dbConnection->getQueryBuilder();
572
573
		$qb->select('*')
574
			->from('share')
575
			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
576
			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
577
578
		$cursor = $qb->execute();
579
		$data = $cursor->fetch();
580
		$cursor->closeCursor();
581
582
		if ($data === false) {
583
			throw new ShareNotFound();
584
		}
585
586
		try {
587
			$share = $this->createShareObject($data);
588
		} catch (InvalidShare $e) {
589
			throw new ShareNotFound();
590
		}
591
592
		return $share;
593
	}
594
595
	/**
596
	 * Get shares for a given path
597
	 *
598
	 * @param \OCP\Files\Node $path
599
	 * @return IShare[]
600
	 */
601 View Code Duplication
	public function getSharesByPath(Node $path) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
602
		$qb = $this->dbConnection->getQueryBuilder();
603
604
		$cursor = $qb->select('*')
605
			->from('share')
606
			->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
607
			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
608
			->execute();
609
610
		$shares = [];
611
		while($data = $cursor->fetch()) {
612
			$shares[] = $this->createShareObject($data);
613
		}
614
		$cursor->closeCursor();
615
616
		return $shares;
617
	}
618
619
	/**
620
	 * @inheritdoc
621
	 */
622 View Code Duplication
	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
623
		/** @var IShare[] $shares */
624
		$shares = [];
625
626
		//Get shares directly with this user
627
		$qb = $this->dbConnection->getQueryBuilder();
628
		$qb->select('*')
629
			->from('share');
630
631
		// Order by id
632
		$qb->orderBy('id');
633
634
		// Set limit and offset
635
		if ($limit !== -1) {
636
			$qb->setMaxResults($limit);
637
		}
638
		$qb->setFirstResult($offset);
639
640
		$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
641
		$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
642
643
		// Filter by node if provided
644
		if ($node !== null) {
645
			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
646
		}
647
648
		$cursor = $qb->execute();
649
650
		while($data = $cursor->fetch()) {
651
			$shares[] = $this->createShareObject($data);
652
		}
653
		$cursor->closeCursor();
654
655
656
		return $shares;
657
	}
658
659
	/**
660
	 * Get a share by token
661
	 *
662
	 * @param string $token
663
	 * @return IShare
664
	 * @throws ShareNotFound
665
	 */
666 View Code Duplication
	public function getShareByToken($token) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
667
		$qb = $this->dbConnection->getQueryBuilder();
668
669
		$cursor = $qb->select('*')
670
			->from('share')
671
			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
672
			->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
673
			->execute();
674
675
		$data = $cursor->fetch();
676
677
		if ($data === false) {
678
			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
679
		}
680
681
		try {
682
			$share = $this->createShareObject($data);
683
		} catch (InvalidShare $e) {
684
			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
685
		}
686
687
		return $share;
688
	}
689
690
	/**
691
	 * remove share from table
692
	 *
693
	 * @param string $shareId
694
	 */
695
	protected function removeShareFromTable($shareId) {
696
		$qb = $this->dbConnection->getQueryBuilder();
697
		$qb->delete('share')
698
			->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
699
		$qb->execute();
700
	}
701
702
	/**
703
	 * Create a share object from an database row
704
	 *
705
	 * @param array $data
706
	 * @return IShare
707
	 * @throws InvalidShare
708
	 * @throws ShareNotFound
709
	 */
710
	protected function createShareObject($data) {
711
712
		$share = new Share($this->rootFolder, $this->userManager);
713
		$share->setId((int)$data['id'])
714
			->setShareType((int)$data['share_type'])
715
			->setPermissions((int)$data['permissions'])
716
			->setTarget($data['file_target'])
717
			->setMailSend((bool)$data['mail_send'])
718
			->setToken($data['token']);
719
720
		$shareTime = new \DateTime();
721
		$shareTime->setTimestamp((int)$data['stime']);
722
		$share->setShareTime($shareTime);
723
		$share->setSharedWith($data['share_with']);
724
		$share->setPassword($data['password']);
725
726
		if ($data['uid_initiator'] !== null) {
727
			$share->setShareOwner($data['uid_owner']);
728
			$share->setSharedBy($data['uid_initiator']);
729
		} else {
730
			//OLD SHARE
731
			$share->setSharedBy($data['uid_owner']);
732
			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
733
734
			$owner = $path->getOwner();
735
			$share->setShareOwner($owner->getUID());
736
		}
737
738 View Code Duplication
		if ($data['expiration'] !== null) {
739
			$expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
740
			if ($expiration !== false) {
741
				$share->setExpirationDate($expiration);
742
			}
743
		}
744
745
		$share->setNodeId((int)$data['file_source']);
746
		$share->setNodeType($data['item_type']);
747
748
		$share->setProviderId($this->identifier());
749
750
		return $share;
751
	}
752
753
	/**
754
	 * Get the node with file $id for $user
755
	 *
756
	 * @param string $userId
757
	 * @param int $id
758
	 * @return \OCP\Files\File|\OCP\Files\Folder
759
	 * @throws InvalidShare
760
	 */
761 View Code Duplication
	private function getNode($userId, $id) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
762
		try {
763
			$userFolder = $this->rootFolder->getUserFolder($userId);
764
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class OCA\ShareByMail\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
765
			throw new InvalidShare();
766
		}
767
768
		$nodes = $userFolder->getById($id);
769
770
		if (empty($nodes)) {
771
			throw new InvalidShare();
772
		}
773
774
		return $nodes[0];
775
	}
776
777
	/**
778
	 * A user is deleted from the system
779
	 * So clean up the relevant shares.
780
	 *
781
	 * @param string $uid
782
	 * @param int $shareType
783
	 */
784 View Code Duplication
	public function userDeleted($uid, $shareType) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
785
		$qb = $this->dbConnection->getQueryBuilder();
786
787
		$qb->delete('share')
788
			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
789
			->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
790
			->execute();
791
	}
792
793
	/**
794
	 * This provider does not support group shares
795
	 *
796
	 * @param string $gid
797
	 */
798
	public function groupDeleted($gid) {
799
		return;
800
	}
801
802
	/**
803
	 * This provider does not support group shares
804
	 *
805
	 * @param string $uid
806
	 * @param string $gid
807
	 */
808
	public function userDeletedFromGroup($uid, $gid) {
809
		return;
810
	}
811
812
	/**
813
	 * get database row of a give share
814
	 *
815
	 * @param $id
816
	 * @return array
817
	 * @throws ShareNotFound
818
	 */
819 View Code Duplication
	protected function getRawShare($id) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
820
821
		// Now fetch the inserted share and create a complete share object
822
		$qb = $this->dbConnection->getQueryBuilder();
823
		$qb->select('*')
824
			->from('share')
825
			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
826
827
		$cursor = $qb->execute();
828
		$data = $cursor->fetch();
829
		$cursor->closeCursor();
830
831
		if ($data === false) {
832
			throw new ShareNotFound;
833
		}
834
835
		return $data;
836
	}
837
838 View Code Duplication
	public function getSharesInFolder($userId, Folder $node, $reshares) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
839
		$qb = $this->dbConnection->getQueryBuilder();
840
		$qb->select('*')
841
			->from('share', 's')
842
			->andWhere($qb->expr()->orX(
843
				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
844
				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
845
			))
846
			->andWhere(
847
				$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
848
			);
849
850
		/**
851
		 * Reshares for this user are shares where they are the owner.
852
		 */
853
		if ($reshares === false) {
854
			$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
855
		} else {
856
			$qb->andWhere(
857
				$qb->expr()->orX(
858
					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
859
					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
860
				)
861
			);
862
		}
863
864
		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
865
		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
866
867
		$qb->orderBy('id');
868
869
		$cursor = $qb->execute();
870
		$shares = [];
871
		while ($data = $cursor->fetch()) {
872
			$shares[$data['fileid']][] = $this->createShareObject($data);
873
		}
874
		$cursor->closeCursor();
875
876
		return $shares;
877
	}
878
879
	/**
880
	 * @inheritdoc
881
	 */
882
	public function getAccessList($nodes, $currentAccess) {
883
		$ids = [];
884
		foreach ($nodes as $node) {
885
			$ids[] = $node->getId();
886
		}
887
888
		$qb = $this->dbConnection->getQueryBuilder();
889
		$qb->select('share_with')
890
			->from('share')
891
			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
892
			->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
893
			->andWhere($qb->expr()->orX(
894
				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
895
				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
896
			))
897
			->setMaxResults(1);
898
		$cursor = $qb->execute();
899
900
		$mail = $cursor->fetch() !== false;
901
		$cursor->closeCursor();
902
903
		return ['public' => $mail];
904
	}
905
906
}
907