Completed
Push — master ( 8932ec...0de15a )
by Joas
14:56
created

DefaultShareProvider::userDeleted()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 57
Code Lines 27

Duplication

Lines 14
Ratio 24.56 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 14
loc 57
rs 9.0309
cc 4
eloc 27
nc 4
nop 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @author Joas Schilling <[email protected]>
4
 * @author Roeland Jago Douma <[email protected]>
5
 *
6
 * @copyright Copyright (c) 2016, ownCloud, Inc.
7
 * @license AGPL-3.0
8
 *
9
 * This code is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License, version 3,
11
 * as published by the Free Software Foundation.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License, version 3,
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
20
 *
21
 */
22
namespace OC\Share20;
23
24
use OCP\Files\File;
25
use OCP\Share\IShareProvider;
26
use OC\Share20\Exception\InvalidShare;
27
use OC\Share20\Exception\ProviderException;
28
use OCP\Share\Exceptions\ShareNotFound;
29
use OC\Share20\Exception\BackendError;
30
use OCP\DB\QueryBuilder\IQueryBuilder;
31
use OCP\IGroup;
32
use OCP\IGroupManager;
33
use OCP\IUserManager;
34
use OCP\Files\IRootFolder;
35
use OCP\IDBConnection;
36
use OCP\Files\Node;
37
38
/**
39
 * Class DefaultShareProvider
40
 *
41
 * @package OC\Share20
42
 */
43
class DefaultShareProvider implements IShareProvider {
44
45
	// Special share type for user modified group shares
46
	const SHARE_TYPE_USERGROUP = 2;
47
48
	/** @var IDBConnection */
49
	private $dbConn;
50
51
	/** @var IUserManager */
52
	private $userManager;
53
54
	/** @var IGroupManager */
55
	private $groupManager;
56
57
	/** @var IRootFolder */
58
	private $rootFolder;
59
60
	/**
61
	 * DefaultShareProvider constructor.
62
	 *
63
	 * @param IDBConnection $connection
64
	 * @param IUserManager $userManager
65
	 * @param IGroupManager $groupManager
66
	 * @param IRootFolder $rootFolder
67
	 */
68
	public function __construct(
69
			IDBConnection $connection,
70
			IUserManager $userManager,
71
			IGroupManager $groupManager,
72
			IRootFolder $rootFolder) {
73
		$this->dbConn = $connection;
74
		$this->userManager = $userManager;
75
		$this->groupManager = $groupManager;
76
		$this->rootFolder = $rootFolder;
77
	}
78
79
	/**
80
	 * Return the identifier of this provider.
81
	 *
82
	 * @return string Containing only [a-zA-Z0-9]
83
	 */
84
	public function identifier() {
85
		return 'ocinternal';
86
	}
87
88
	/**
89
	 * Share a path
90
	 *
91
	 * @param \OCP\Share\IShare $share
92
	 * @return \OCP\Share\IShare The share object
93
	 * @throws ShareNotFound
94
	 * @throws \Exception
95
	 */
96
	public function create(\OCP\Share\IShare $share) {
97
		$qb = $this->dbConn->getQueryBuilder();
98
99
		$qb->insert('share');
100
		$qb->setValue('share_type', $qb->createNamedParameter($share->getShareType()));
101
102
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
103
			//Set the UID of the user we share with
104
			$qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()));
105
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
106
			//Set the GID of the group we share with
107
			$qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()));
108
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
109
			//Set the token of the share
110
			$qb->setValue('token', $qb->createNamedParameter($share->getToken()));
111
112
			//If a password is set store it
113
			if ($share->getPassword() !== null) {
114
				$qb->setValue('share_with', $qb->createNamedParameter($share->getPassword()));
115
			}
116
117
			//If an expiration date is set store it
118
			if ($share->getExpirationDate() !== null) {
119
				$qb->setValue('expiration', $qb->createNamedParameter($share->getExpirationDate(), 'datetime'));
120
			}
121
122
			if (method_exists($share, 'getParent')) {
123
				$qb->setValue('parent', $qb->createNamedParameter($share->getParent()));
124
			}
125
		} else {
126
			throw new \Exception('invalid share type!');
127
		}
128
129
		// Set what is shares
130
		$qb->setValue('item_type', $qb->createParameter('itemType'));
131
		if ($share->getNode() instanceof \OCP\Files\File) {
132
			$qb->setParameter('itemType', 'file');
133
		} else {
134
			$qb->setParameter('itemType', 'folder');
135
		}
136
137
		// Set the file id
138
		$qb->setValue('item_source', $qb->createNamedParameter($share->getNode()->getId()));
139
		$qb->setValue('file_source', $qb->createNamedParameter($share->getNode()->getId()));
140
141
		// set the permissions
142
		$qb->setValue('permissions', $qb->createNamedParameter($share->getPermissions()));
143
144
		// Set who created this share
145
		$qb->setValue('uid_initiator', $qb->createNamedParameter($share->getSharedBy()));
146
147
		// Set who is the owner of this file/folder (and this the owner of the share)
148
		$qb->setValue('uid_owner', $qb->createNamedParameter($share->getShareOwner()));
149
150
		// Set the file target
151
		$qb->setValue('file_target', $qb->createNamedParameter($share->getTarget()));
152
153
		// Set the time this share was created
154
		$qb->setValue('stime', $qb->createNamedParameter(time()));
155
156
		// insert the data and fetch the id of the share
157
		$this->dbConn->beginTransaction();
158
		$qb->execute();
159
		$id = $this->dbConn->lastInsertId('*PREFIX*share');
160
		$this->dbConn->commit();
161
162
		// Now fetch the inserted share and create a complete share object
163
		$qb = $this->dbConn->getQueryBuilder();
164
		$qb->select('*')
165
			->from('share')
166
			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
167
168
		$cursor = $qb->execute();
169
		$data = $cursor->fetch();
170
		$cursor->closeCursor();
171
172
		if ($data === false) {
173
			throw new ShareNotFound();
174
		}
175
176
		$share = $this->createShare($data);
177
		return $share;
178
	}
179
180
	/**
181
	 * Update a share
182
	 *
183
	 * @param \OCP\Share\IShare $share
184
	 * @return \OCP\Share\IShare The share object
185
	 */
186
	public function update(\OCP\Share\IShare $share) {
187
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
188
			/*
189
			 * We allow updating the recipient on user shares.
190
			 */
191
			$qb = $this->dbConn->getQueryBuilder();
192
			$qb->update('share')
193
				->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
194
				->set('share_with', $qb->createNamedParameter($share->getSharedWith()))
195
				->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
196
				->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
197
				->set('permissions', $qb->createNamedParameter($share->getPermissions()))
198
				->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
199
				->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
200
				->execute();
201
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
202
			$qb = $this->dbConn->getQueryBuilder();
203
			$qb->update('share')
204
				->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
205
				->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
206
				->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
207
				->set('permissions', $qb->createNamedParameter($share->getPermissions()))
208
				->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
209
				->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
210
				->execute();
211
212
			/*
213
			 * Update all user defined group shares
214
			 */
215
			$qb = $this->dbConn->getQueryBuilder();
216
			$qb->update('share')
217
				->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
218
				->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
219
				->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
220
				->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
221
				->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
222
				->execute();
223
224
			/*
225
			 * Now update the permissions for all children that have not set it to 0
226
			 */
227
			$qb = $this->dbConn->getQueryBuilder();
228
			$qb->update('share')
229
				->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
230
				->andWhere($qb->expr()->neq('permissions', $qb->createNamedParameter(0)))
231
				->set('permissions', $qb->createNamedParameter($share->getPermissions()))
232
				->execute();
233
234
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
235
			$qb = $this->dbConn->getQueryBuilder();
236
			$qb->update('share')
237
				->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
238
				->set('share_with', $qb->createNamedParameter($share->getPassword()))
239
				->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
240
				->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
241
				->set('permissions', $qb->createNamedParameter($share->getPermissions()))
242
				->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
243
				->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
244
				->set('token', $qb->createNamedParameter($share->getToken()))
245
				->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
246
				->execute();
247
		}
248
249
		return $share;
250
	}
251
252
	/**
253
	 * Get all children of this share
254
	 * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
255
	 *
256
	 * @param \OCP\Share\IShare $parent
257
	 * @return \OCP\Share\IShare[]
258
	 */
259
	public function getChildren(\OCP\Share\IShare $parent) {
260
		$children = [];
261
262
		$qb = $this->dbConn->getQueryBuilder();
263
		$qb->select('*')
264
			->from('share')
265
			->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
266
			->andWhere(
267
				$qb->expr()->in(
268
					'share_type',
269
					$qb->createNamedParameter([
270
						\OCP\Share::SHARE_TYPE_USER,
271
						\OCP\Share::SHARE_TYPE_GROUP,
272
						\OCP\Share::SHARE_TYPE_LINK,
273
					], IQueryBuilder::PARAM_INT_ARRAY)
274
				)
275
			)
276
			->andWhere($qb->expr()->orX(
277
				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
278
				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::orX() has too many arguments starting with $qb->expr()->eq('item_ty...medParameter('folder')).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
279
			))
280
			->orderBy('id');
281
282
		$cursor = $qb->execute();
283
		while($data = $cursor->fetch()) {
284
			$children[] = $this->createShare($data);
285
		}
286
		$cursor->closeCursor();
287
288
		return $children;
289
	}
290
291
	/**
292
	 * Delete a share
293
	 *
294
	 * @param \OCP\Share\IShare $share
295
	 */
296 View Code Duplication
	public function delete(\OCP\Share\IShare $share) {
297
		$qb = $this->dbConn->getQueryBuilder();
298
		$qb->delete('share')
299
			->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())));
300
301
		/*
302
		 * If the share is a group share delete all possible
303
		 * user defined groups shares.
304
		 */
305
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
306
			$qb->orWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())));
307
		}
308
309
		$qb->execute();
310
	}
311
312
	/**
313
	 * Unshare a share from the recipient. If this is a group share
314
	 * this means we need a special entry in the share db.
315
	 *
316
	 * @param \OCP\Share\IShare $share
317
	 * @param string $recipient UserId of recipient
318
	 * @throws BackendError
319
	 * @throws ProviderException
320
	 */
321
	public function deleteFromSelf(\OCP\Share\IShare $share, $recipient) {
322
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
323
324
			$group = $this->groupManager->get($share->getSharedWith());
325
			$user = $this->userManager->get($recipient);
326
327
			if (!$group->inGroup($user)) {
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userManager->get($recipient) on line 325 can be null; however, OCP\IGroup::inGroup() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
328
				throw new ProviderException('Recipient not in receiving group');
329
			}
330
331
			// Try to fetch user specific share
332
			$qb = $this->dbConn->getQueryBuilder();
333
			$stmt = $qb->select('*')
334
				->from('share')
335
				->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
336
				->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient)))
337
				->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
338
				->andWhere($qb->expr()->orX(
339
					$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
340
					$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::orX() has too many arguments starting with $qb->expr()->eq('item_ty...medParameter('folder')).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
341
				))
342
				->execute();
343
344
			$data = $stmt->fetch();
345
346
			/*
347
			 * Check if there already is a user specific group share.
348
			 * If there is update it (if required).
349
			 */
350
			if ($data === false) {
351
				$qb = $this->dbConn->getQueryBuilder();
352
353
				$type = $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder';
354
355
				//Insert new share
356
				$qb->insert('share')
357
					->values([
358
						'share_type' => $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP),
359
						'share_with' => $qb->createNamedParameter($recipient),
360
						'uid_owner' => $qb->createNamedParameter($share->getShareOwner()),
361
						'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()),
362
						'parent' => $qb->createNamedParameter($share->getId()),
363
						'item_type' => $qb->createNamedParameter($type),
364
						'item_source' => $qb->createNamedParameter($share->getNode()->getId()),
365
						'file_source' => $qb->createNamedParameter($share->getNode()->getId()),
366
						'file_target' => $qb->createNamedParameter($share->getTarget()),
367
						'permissions' => $qb->createNamedParameter(0),
368
						'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()),
369
					])->execute();
370
371
			} else if ($data['permissions'] !== 0) {
372
373
				// Update existing usergroup share
374
				$qb = $this->dbConn->getQueryBuilder();
375
				$qb->update('share')
376
					->set('permissions', $qb->createNamedParameter(0))
377
					->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id'])))
378
					->execute();
379
			}
380
381
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
382
383
			if ($share->getSharedWith() !== $recipient) {
384
				throw new ProviderException('Recipient does not match');
385
			}
386
387
			// We can just delete user and link shares
388
			$this->delete($share);
389
		} else {
390
			throw new ProviderException('Invalid shareType');
391
		}
392
	}
393
394
	/**
395
	 * @inheritdoc
396
	 */
397
	public function move(\OCP\Share\IShare $share, $recipient) {
398
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
399
			// Just update the target
400
			$qb = $this->dbConn->getQueryBuilder();
401
			$qb->update('share')
402
				->set('file_target', $qb->createNamedParameter($share->getTarget()))
403
				->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
404
				->execute();
405
406
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
407
408
			// Check if there is a usergroup share
409
			$qb = $this->dbConn->getQueryBuilder();
410
			$stmt = $qb->select('id')
411
				->from('share')
412
				->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
413
				->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient)))
414
				->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
415
				->andWhere($qb->expr()->orX(
416
					$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
417
					$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::orX() has too many arguments starting with $qb->expr()->eq('item_ty...medParameter('folder')).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
418
				))
419
				->setMaxResults(1)
420
				->execute();
421
422
			$data = $stmt->fetch();
423
			$stmt->closeCursor();
424
425
			if ($data === false) {
426
				// No usergroup share yet. Create one.
427
				$qb = $this->dbConn->getQueryBuilder();
428
				$qb->insert('share')
429
					->values([
430
						'share_type' => $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP),
431
						'share_with' => $qb->createNamedParameter($recipient),
432
						'uid_owner' => $qb->createNamedParameter($share->getShareOwner()),
433
						'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()),
434
						'parent' => $qb->createNamedParameter($share->getId()),
435
						'item_type' => $qb->createNamedParameter($share->getNode() instanceof File ? 'file' : 'folder'),
436
						'item_source' => $qb->createNamedParameter($share->getNode()->getId()),
437
						'file_source' => $qb->createNamedParameter($share->getNode()->getId()),
438
						'file_target' => $qb->createNamedParameter($share->getTarget()),
439
						'permissions' => $qb->createNamedParameter($share->getPermissions()),
440
						'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()),
441
					])->execute();
442
			} else {
443
				// Already a usergroup share. Update it.
444
				$qb = $this->dbConn->getQueryBuilder();
445
				$qb->update('share')
446
					->set('file_target', $qb->createNamedParameter($share->getTarget()))
447
					->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id'])))
448
					->execute();
449
			}
450
		}
451
452
		return $share;
453
	}
454
455
	/**
456
	 * @inheritdoc
457
	 */
458
	public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
459
		$qb = $this->dbConn->getQueryBuilder();
460
		$qb->select('*')
461
			->from('share')
462
			->andWhere($qb->expr()->orX(
463
				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
464
				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::orX() has too many arguments starting with $qb->expr()->eq('item_ty...medParameter('folder')).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
465
			));
466
467
		$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType)));
468
469
		/**
470
		 * Reshares for this user are shares where they are the owner.
471
		 */
472 View Code Duplication
		if ($reshares === false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
473
			$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
474
		} else {
475
			$qb->andWhere(
476
				$qb->expr()->orX(
477
					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
478
					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::orX() has too many arguments starting with $qb->expr()->eq('uid_ini...amedParameter($userId)).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
479
				)
480
			);
481
		}
482
483
		if ($node !== null) {
484
			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
485
		}
486
487
		if ($limit !== -1) {
488
			$qb->setMaxResults($limit);
489
		}
490
491
		$qb->setFirstResult($offset);
492
		$qb->orderBy('id');
493
494
		$cursor = $qb->execute();
495
		$shares = [];
496
		while($data = $cursor->fetch()) {
497
			$shares[] = $this->createShare($data);
498
		}
499
		$cursor->closeCursor();
500
501
		return $shares;
502
	}
503
504
	/**
505
	 * @inheritdoc
506
	 */
507
	public function getShareById($id, $recipientId = null) {
508
		$qb = $this->dbConn->getQueryBuilder();
509
510
		$qb->select('*')
511
			->from('share')
512
			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
513
			->andWhere(
514
				$qb->expr()->in(
515
					'share_type',
516
					$qb->createNamedParameter([
517
						\OCP\Share::SHARE_TYPE_USER,
518
						\OCP\Share::SHARE_TYPE_GROUP,
519
						\OCP\Share::SHARE_TYPE_LINK,
520
					], IQueryBuilder::PARAM_INT_ARRAY)
521
				)
522
			)
523
			->andWhere($qb->expr()->orX(
524
				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
525
				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::orX() has too many arguments starting with $qb->expr()->eq('item_ty...medParameter('folder')).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
526
			));
527
		
528
		$cursor = $qb->execute();
529
		$data = $cursor->fetch();
530
		$cursor->closeCursor();
531
532
		if ($data === false) {
533
			throw new ShareNotFound();
534
		}
535
536
		try {
537
			$share = $this->createShare($data);
538
		} catch (InvalidShare $e) {
539
			throw new ShareNotFound();
540
		}
541
542
		// If the recipient is set for a group share resolve to that user
543
		if ($recipientId !== null && $share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
544
			$share = $this->resolveGroupShare($share, $recipientId);
545
		}
546
547
		return $share;
548
	}
549
550
	/**
551
	 * Get shares for a given path
552
	 *
553
	 * @param \OCP\Files\Node $path
554
	 * @return \OCP\Share\IShare[]
555
	 */
556
	public function getSharesByPath(Node $path) {
557
		$qb = $this->dbConn->getQueryBuilder();
558
559
		$cursor = $qb->select('*')
560
			->from('share')
561
			->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
562
			->andWhere(
563
				$qb->expr()->orX(
564
					$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)),
565
					$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::orX() has too many arguments starting with $qb->expr()->eq('share_t...are::SHARE_TYPE_GROUP)).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
566
				)
567
			)
568
			->andWhere($qb->expr()->orX(
569
				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
570
				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::orX() has too many arguments starting with $qb->expr()->eq('item_ty...medParameter('folder')).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
571
			))
572
			->execute();
573
574
		$shares = [];
575
		while($data = $cursor->fetch()) {
576
			$shares[] = $this->createShare($data);
577
		}
578
		$cursor->closeCursor();
579
580
		return $shares;
581
	}
582
583
	/**
584
	 * @inheritdoc
585
	 */
586
	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
587
		/** @var Share[] $shares */
588
		$shares = [];
589
590
		if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
591
			//Get shares directly with this user
592
			$qb = $this->dbConn->getQueryBuilder();
593
			$qb->select('*')
594
				->from('share');
595
596
			// Order by id
597
			$qb->orderBy('id');
598
599
			// Set limit and offset
600
			if ($limit !== -1) {
601
				$qb->setMaxResults($limit);
602
			}
603
			$qb->setFirstResult($offset);
604
605
			$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)))
606
				->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)))
607
				->andWhere($qb->expr()->orX(
608
					$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
609
					$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::orX() has too many arguments starting with $qb->expr()->eq('item_ty...medParameter('folder')).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
610
				));
611
612
			// Filter by node if provided
613
			if ($node !== null) {
614
				$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
615
			}
616
617
			$cursor = $qb->execute();
618
619
			while($data = $cursor->fetch()) {
620
				$shares[] = $this->createShare($data);
621
			}
622
			$cursor->closeCursor();
623
624
		} else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
625
			$user = $this->userManager->get($userId);
626
			$allGroups = $this->groupManager->getUserGroups($user);
627
628
			/** @var Share[] $shares2 */
629
			$shares2 = [];
630
631
			$start = 0;
632
			while(true) {
633
				$groups = array_slice($allGroups, $start, 100);
634
				$start += 100;
635
636
				if ($groups === []) {
637
					break;
638
				}
639
640
				$qb = $this->dbConn->getQueryBuilder();
641
				$qb->select('*')
642
					->from('share')
643
					->orderBy('id')
644
					->setFirstResult(0);
645
646
				if ($limit !== -1) {
647
					$qb->setMaxResults($limit - count($shares));
648
				}
649
650
				// Filter by node if provided
651
				if ($node !== null) {
652
					$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
653
				}
654
655
				$groups = array_map(function(IGroup $group) { return $group->getGID(); }, $groups);
656
657
				$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)))
658
					->andWhere($qb->expr()->in('share_with', $qb->createNamedParameter(
659
						$groups,
660
						IQueryBuilder::PARAM_STR_ARRAY
661
					)))
662
					->andWhere($qb->expr()->orX(
663
						$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
664
						$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::orX() has too many arguments starting with $qb->expr()->eq('item_ty...medParameter('folder')).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
665
					));
666
667
				$cursor = $qb->execute();
668
				while($data = $cursor->fetch()) {
669
					if ($offset > 0) {
670
						$offset--;
671
						continue;
672
					}
673
					$shares2[] = $this->createShare($data);
674
				}
675
				$cursor->closeCursor();
676
			}
677
678
			/*
679
 			 * Resolve all group shares to user specific shares
680
 			 * TODO: Optmize this!
681
 			 */
682
			foreach($shares2 as $share) {
683
				$shares[] = $this->resolveGroupShare($share, $userId);
684
			}
685
		} else {
686
			throw new BackendError('Invalid backend');
687
		}
688
689
690
		return $shares;
691
	}
692
693
	/**
694
	 * Get a share by token
695
	 *
696
	 * @param string $token
697
	 * @return \OCP\Share\IShare
698
	 * @throws ShareNotFound
699
	 */
700
	public function getShareByToken($token) {
701
		$qb = $this->dbConn->getQueryBuilder();
702
703
		$cursor = $qb->select('*')
704
			->from('share')
705
			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_LINK)))
706
			->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
707
			->andWhere($qb->expr()->orX(
708
				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
709
				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::orX() has too many arguments starting with $qb->expr()->eq('item_ty...medParameter('folder')).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
710
			))
711
			->execute();
712
713
		$data = $cursor->fetch();
714
715
		if ($data === false) {
716
			throw new ShareNotFound();
717
		}
718
719
		try {
720
			$share = $this->createShare($data);
721
		} catch (InvalidShare $e) {
722
			throw new ShareNotFound();
723
		}
724
725
		return $share;
726
	}
727
	
728
	/**
729
	 * Create a share object from an database row
730
	 *
731
	 * @param mixed[] $data
732
	 * @return \OCP\Share\IShare
733
	 * @throws InvalidShare
734
	 */
735
	private function createShare($data) {
736
		$share = new Share($this->rootFolder);
737
		$share->setId((int)$data['id'])
738
			->setShareType((int)$data['share_type'])
739
			->setPermissions((int)$data['permissions'])
740
			->setTarget($data['file_target'])
741
			->setMailSend((bool)$data['mail_send']);
742
743
		$shareTime = new \DateTime();
744
		$shareTime->setTimestamp((int)$data['stime']);
745
		$share->setShareTime($shareTime);
746
747
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
748
			$share->setSharedWith($data['share_with']);
749
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
750
			$share->setSharedWith($data['share_with']);
751
		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
752
			$share->setPassword($data['share_with']);
753
			$share->setToken($data['token']);
754
		}
755
756
		$share->setSharedBy($data['uid_initiator']);
757
		$share->setShareOwner($data['uid_owner']);
758
759
		$share->setNodeId((int)$data['file_source']);
760
		$share->setNodeType($data['item_type']);
761
762
		if ($data['expiration'] !== null) {
763
			$expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
764
			$share->setExpirationDate($expiration);
0 ignored issues
show
Security Bug introduced by
It seems like $expiration defined by \DateTime::createFromFor...', $data['expiration']) on line 763 can also be of type false; however, OC\Share20\Share::setExpirationDate() does only seem to accept object<DateTime>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
765
		}
766
767
		$share->setProviderId($this->identifier());
768
769
		return $share;
770
	}
771
772
	/**
773
	 * Resolve a group share to a user specific share
774
	 * Thus if the user moved their group share make sure this is properly reflected here.
775
	 *
776
	 * @param \OCP\Share\IShare $share
777
	 * @param string $userId
778
	 * @return Share Returns the updated share if one was found else return the original share.
779
	 */
780
	private function resolveGroupShare(\OCP\Share\IShare $share, $userId) {
781
		$qb = $this->dbConn->getQueryBuilder();
782
783
		$stmt = $qb->select('*')
784
			->from('share')
785
			->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
786
			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
787
			->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)))
788
			->andWhere($qb->expr()->orX(
789
				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
790
				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::orX() has too many arguments starting with $qb->expr()->eq('item_ty...medParameter('folder')).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
791
			))
792
			->setMaxResults(1)
793
			->execute();
794
795
		$data = $stmt->fetch();
796
		$stmt->closeCursor();
797
798
		if ($data !== false) {
799
			$share->setPermissions((int)$data['permissions']);
800
			$share->setTarget($data['file_target']);
801
		}
802
803
		return $share;
804
	}
805
806
	/**
807
	 * A user is deleted from the system
808
	 * So clean up the relevant shares.
809
	 *
810
	 * @param string $uid
811
	 * @param int $shareType
812
	 */
813
	public function userDeleted($uid, $shareType) {
814
		$qb = $this->dbConn->getQueryBuilder();
815
816
		$qb->delete('share');
817
818
		if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
819
			/*
820
			 * Delete all user shares that are owned by this user
821
			 * or that are received by this user
822
			 */
823
824
			$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)));
825
826
			$qb->andWhere(
827
				$qb->expr()->orX(
828
					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)),
829
					$qb->expr()->eq('share_with', $qb->createNamedParameter($uid))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::orX() has too many arguments starting with $qb->expr()->eq('share_w...teNamedParameter($uid)).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
830
				)
831
			);
832
		} else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
833
			/*
834
			 * Delete all group shares that are owned by this user
835
			 * Or special user group shares that are received by this user
836
			 */
837
			$qb->where(
838
				$qb->expr()->andX(
839
					$qb->expr()->orX(
840
						$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)),
841
						$qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::orX() has too many arguments starting with $qb->expr()->eq('share_t...:SHARE_TYPE_USERGROUP)).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
842
					),
843
					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::andX() has too many arguments starting with $qb->expr()->eq('uid_own...teNamedParameter($uid)).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
844
				)
845
			);
846
847
			$qb->orWhere(
848
				$qb->expr()->andX(
849
					$qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)),
850
					$qb->expr()->eq('share_with', $qb->createNamedParameter($uid))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::andX() has too many arguments starting with $qb->expr()->eq('share_w...teNamedParameter($uid)).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
851
				)
852
			);
853 View Code Duplication
		} else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
854
			/*
855
			 * Delete all link shares owned by this user.
856
			 * And all link shares initiated by this user (until #22327 is in)
857
			 */
858
			$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_LINK)));
859
860
			$qb->andWhere(
861
				$qb->expr()->orX(
862
					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)),
863
					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($uid))
0 ignored issues
show
Unused Code introduced by
The call to IExpressionBuilder::orX() has too many arguments starting with $qb->expr()->eq('uid_ini...teNamedParameter($uid)).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
864
				)
865
			);
866
		}
867
868
		$qb->execute();
869
	}
870
}
871