Completed
Push — master ( 4a5a36...bf8806 )
by Robin
27s
created

ShareesAPIController   F

Complexity

Total Complexity 94

Size/Duplication

Total Lines 630
Duplicated Lines 9.52 %

Coupling/Cohesion

Components 1
Dependencies 20

Importance

Changes 0
Metric Value
dl 60
loc 630
rs 1.4842
c 0
b 0
f 0
wmc 94
lcom 1
cbo 20

13 Methods

Rating   Name   Duplication   Size   Complexity  
A isRemoteSharingAllowed() 0 8 2
A getPaginationLink() 0 11 2
A isV2() 0 3 1
B __construct() 0 26 1
F getUsers() 12 80 17
C getGroups() 12 63 15
C getRemote() 10 63 13
A splitUserRemote() 8 8 2
A fixRemoteURL() 9 9 2
C search() 0 44 11
C searchSharees() 0 62 12
C getEmail() 9 59 12
B getLookup() 0 33 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ShareesAPIController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ShareesAPIController, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Björn Schießle <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Roeland Jago Douma <[email protected]>
8
 * @author Thomas Müller <[email protected]>
9
 *
10
 * @license AGPL-3.0
11
 *
12
 * This code is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License, version 3,
14
 * as published by the Free Software Foundation.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License, version 3,
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
23
 *
24
 */
25
namespace OCA\Files_Sharing\Controller;
26
27
use OCP\AppFramework\Http;
28
use OCP\AppFramework\OCS\OCSBadRequestException;
29
use OCP\AppFramework\OCSController;
30
use OCP\Contacts\IManager;
31
use OCP\Federation\ICloudIdManager;
32
use OCP\Http\Client\IClientService;
33
use OCP\IGroup;
34
use OCP\IGroupManager;
35
use OCP\ILogger;
36
use OCP\IRequest;
37
use OCP\IUser;
38
use OCP\IUserManager;
39
use OCP\IConfig;
40
use OCP\IUserSession;
41
use OCP\IURLGenerator;
42
use OCP\Share;
43
44
class ShareesAPIController extends OCSController {
45
46
	/** @var IGroupManager */
47
	protected $groupManager;
48
49
	/** @var IUserManager */
50
	protected $userManager;
51
52
	/** @var IManager */
53
	protected $contactsManager;
54
55
	/** @var IConfig */
56
	protected $config;
57
58
	/** @var IUserSession */
59
	protected $userSession;
60
61
	/** @var IURLGenerator */
62
	protected $urlGenerator;
63
64
	/** @var ILogger */
65
	protected $logger;
66
67
	/** @var \OCP\Share\IManager */
68
	protected $shareManager;
69
70
	/** @var IClientService */
71
	protected $clientService;
72
73
	/** @var ICloudIdManager  */
74
	protected $cloudIdManager;
75
76
	/** @var bool */
77
	protected $shareWithGroupOnly = false;
78
79
	/** @var bool */
80
	protected $shareeEnumeration = true;
81
82
	/** @var int */
83
	protected $offset = 0;
84
85
	/** @var int */
86
	protected $limit = 10;
87
88
	/** @var array */
89
	protected $result = [
90
		'exact' => [
91
			'users' => [],
92
			'groups' => [],
93
			'remotes' => [],
94
			'emails' => [],
95
		],
96
		'users' => [],
97
		'groups' => [],
98
		'remotes' => [],
99
		'emails' => [],
100
		'lookup' => [],
101
	];
102
103
	protected $reachedEndFor = [];
104
105
	/**
106
	 * @param string $appName
107
	 * @param IRequest $request
108
	 * @param IGroupManager $groupManager
109
	 * @param IUserManager $userManager
110
	 * @param IManager $contactsManager
111
	 * @param IConfig $config
112
	 * @param IUserSession $userSession
113
	 * @param IURLGenerator $urlGenerator
114
	 * @param ILogger $logger
115
	 * @param \OCP\Share\IManager $shareManager
116
	 * @param IClientService $clientService
117
	 * @param ICloudIdManager $cloudIdManager
118
	 */
119
	public function __construct($appName,
120
								IRequest $request,
121
								IGroupManager $groupManager,
122
								IUserManager $userManager,
123
								IManager $contactsManager,
124
								IConfig $config,
125
								IUserSession $userSession,
126
								IURLGenerator $urlGenerator,
127
								ILogger $logger,
128
								\OCP\Share\IManager $shareManager,
129
								IClientService $clientService,
130
								ICloudIdManager $cloudIdManager
131
	) {
132
		parent::__construct($appName, $request);
133
134
		$this->groupManager = $groupManager;
135
		$this->userManager = $userManager;
136
		$this->contactsManager = $contactsManager;
137
		$this->config = $config;
138
		$this->userSession = $userSession;
139
		$this->urlGenerator = $urlGenerator;
140
		$this->logger = $logger;
141
		$this->shareManager = $shareManager;
142
		$this->clientService = $clientService;
143
		$this->cloudIdManager = $cloudIdManager;
144
	}
145
146
	/**
147
	 * @param string $search
148
	 */
149
	protected function getUsers($search) {
150
		$this->result['users'] = $this->result['exact']['users'] = $users = [];
151
152
		$userGroups = [];
153
		if ($this->shareWithGroupOnly) {
154
			// Search in all the groups this user is part of
155
			$userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
0 ignored issues
show
Bug introduced by
It seems like $this->userSession->getUser() can be null; however, getUserGroupIds() 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...
156
			foreach ($userGroups as $userGroup) {
157
				$usersTmp = $this->groupManager->displayNamesInGroup($userGroup, $search, $this->limit, $this->offset);
158
				foreach ($usersTmp as $uid => $userDisplayName) {
159
					$users[$uid] = $userDisplayName;
160
				}
161
			}
162
		} else {
163
			// Search in all users
164
			$usersTmp = $this->userManager->searchDisplayName($search, $this->limit, $this->offset);
165
166
			foreach ($usersTmp as $user) {
167
				$users[$user->getUID()] = $user->getDisplayName();
168
			}
169
		}
170
171 View Code Duplication
		if (!$this->shareeEnumeration || sizeof($users) < $this->limit) {
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...
172
			$this->reachedEndFor[] = 'users';
173
		}
174
175
		$foundUserById = false;
176
		$lowerSearch = strtolower($search);
177
		foreach ($users as $uid => $userDisplayName) {
178
			if (strtolower($uid) === $lowerSearch || strtolower($userDisplayName) === $lowerSearch) {
179
				if (strtolower($uid) === $lowerSearch) {
180
					$foundUserById = true;
181
				}
182
				$this->result['exact']['users'][] = [
183
					'label' => $userDisplayName,
184
					'value' => [
185
						'shareType' => Share::SHARE_TYPE_USER,
186
						'shareWith' => $uid,
187
					],
188
				];
189 View Code Duplication
			} else {
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...
190
				$this->result['users'][] = [
191
					'label' => $userDisplayName,
192
					'value' => [
193
						'shareType' => Share::SHARE_TYPE_USER,
194
						'shareWith' => $uid,
195
					],
196
				];
197
			}
198
		}
199
200
		if ($this->offset === 0 && !$foundUserById) {
201
			// On page one we try if the search result has a direct hit on the
202
			// user id and if so, we add that to the exact match list
203
			$user = $this->userManager->get($search);
204
			if ($user instanceof IUser) {
205
				$addUser = true;
206
207
				if ($this->shareWithGroupOnly) {
208
					// Only add, if we have a common group
209
					$commonGroups = array_intersect($userGroups, $this->groupManager->getUserGroupIds($user));
210
					$addUser = !empty($commonGroups);
211
				}
212
213
				if ($addUser) {
214
					array_push($this->result['exact']['users'], [
215
						'label' => $user->getDisplayName(),
216
						'value' => [
217
							'shareType' => Share::SHARE_TYPE_USER,
218
							'shareWith' => $user->getUID(),
219
						],
220
					]);
221
				}
222
			}
223
		}
224
225
		if (!$this->shareeEnumeration) {
226
			$this->result['users'] = [];
227
		}
228
	}
229
230
	/**
231
	 * @param string $search
232
	 */
233
	protected function getGroups($search) {
234
		$this->result['groups'] = $this->result['exact']['groups'] = [];
235
236
		$groups = $this->groupManager->search($search, $this->limit, $this->offset);
237
		$groupIds = array_map(function (IGroup $group) { return $group->getGID(); }, $groups);
238
239 View Code Duplication
		if (!$this->shareeEnumeration || sizeof($groups) < $this->limit) {
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...
240
			$this->reachedEndFor[] = 'groups';
241
		}
242
243
		$userGroups =  [];
244
		if (!empty($groups) && $this->shareWithGroupOnly) {
245
			// Intersect all the groups that match with the groups this user is a member of
246
			$userGroups = $this->groupManager->getUserGroups($this->userSession->getUser());
247
			$userGroups = array_map(function (IGroup $group) { return $group->getGID(); }, $userGroups);
248
			$groupIds = array_intersect($groupIds, $userGroups);
249
		}
250
251
		$lowerSearch = strtolower($search);
252
		foreach ($groups as $group) {
253
			// FIXME: use a more efficient approach
254
			$gid = $group->getGID();
255
			if (!in_array($gid, $groupIds)) {
256
				continue;
257
			}
258
			if (strtolower($gid) === $lowerSearch || strtolower($group->getDisplayName()) === $lowerSearch) {
259
				$this->result['exact']['groups'][] = [
260
					'label' => $group->getDisplayName(),
261
					'value' => [
262
						'shareType' => Share::SHARE_TYPE_GROUP,
263
						'shareWith' => $gid,
264
					],
265
				];
266 View Code Duplication
			} else {
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...
267
				$this->result['groups'][] = [
268
					'label' => $group->getDisplayName(),
269
					'value' => [
270
						'shareType' => Share::SHARE_TYPE_GROUP,
271
						'shareWith' => $gid,
272
					],
273
				];
274
			}
275
		}
276
277
		if ($this->offset === 0 && empty($this->result['exact']['groups'])) {
278
			// On page one we try if the search result has a direct hit on the
279
			// user id and if so, we add that to the exact match list
280
			$group = $this->groupManager->get($search);
281
			if ($group instanceof IGroup && (!$this->shareWithGroupOnly || in_array($group->getGID(), $userGroups))) {
282
				array_push($this->result['exact']['groups'], [
283
					'label' => $group->getDisplayName(),
284
					'value' => [
285
						'shareType' => Share::SHARE_TYPE_GROUP,
286
						'shareWith' => $group->getGID(),
287
					],
288
				]);
289
			}
290
		}
291
292
		if (!$this->shareeEnumeration) {
293
			$this->result['groups'] = [];
294
		}
295
	}
296
297
	/**
298
	 * @param string $search
299
	 * @return array
300
	 */
301
	protected function getRemote($search) {
302
		$result = ['results' => [], 'exact' => []];
303
304
		// Search in contacts
305
		//@todo Pagination missing
306
		$addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN']);
307
		$result['exactIdMatch'] = false;
308
		foreach ($addressBookContacts as $contact) {
309
			if (isset($contact['isLocalSystemBook'])) {
310
				continue;
311
			}
312
			if (isset($contact['CLOUD'])) {
313
				$cloudIds = $contact['CLOUD'];
314
				if (!is_array($cloudIds)) {
315
					$cloudIds = [$cloudIds];
316
				}
317
				$lowerSearch = strtolower($search);
318
				foreach ($cloudIds as $cloudId) {
319
					list(, $serverUrl) = $this->splitUserRemote($cloudId);
320
					if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) {
321
						if (strtolower($cloudId) === $lowerSearch) {
322
							$result['exactIdMatch'] = true;
323
						}
324
						$result['exact'][] = [
325
							'label' => $contact['FN'] . " ($cloudId)",
326
							'value' => [
327
								'shareType' => Share::SHARE_TYPE_REMOTE,
328
								'shareWith' => $cloudId,
329
								'server' => $serverUrl,
330
							],
331
						];
332 View Code Duplication
					} else {
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...
333
						$result['results'][] = [
334
							'label' => $contact['FN'] . " ($cloudId)",
335
							'value' => [
336
								'shareType' => Share::SHARE_TYPE_REMOTE,
337
								'shareWith' => $cloudId,
338
								'server' => $serverUrl,
339
							],
340
						];
341
					}
342
				}
343
			}
344
		}
345
346
		if (!$this->shareeEnumeration) {
347
			$result['results'] = [];
348
		}
349
350
		if (!$result['exactIdMatch'] && $this->cloudIdManager->isValidCloudId($search) && $this->offset === 0) {
351
			$result['exact'][] = [
352
				'label' => $search,
353
				'value' => [
354
					'shareType' => Share::SHARE_TYPE_REMOTE,
355
					'shareWith' => $search,
356
				],
357
			];
358
		}
359
360
		$this->reachedEndFor[] = 'remotes';
361
362
		return $result;
363
	}
364
365
	/**
366
	 * split user and remote from federated cloud id
367
	 *
368
	 * @param string $address federated share address
369
	 * @return array [user, remoteURL]
370
	 * @throws \Exception
371
	 */
372 View Code Duplication
	public function splitUserRemote($address) {
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...
373
		try {
374
			$cloudId = $this->cloudIdManager->resolveCloudId($address);
375
			return [$cloudId->getUser(), $cloudId->getRemote()];
376
		} catch (\InvalidArgumentException $e) {
377
			throw new \Exception('Invalid Federated Cloud ID', 0, $e);
378
		}
379
	}
380
381
	/**
382
	 * Strips away a potential file names and trailing slashes:
383
	 * - http://localhost
384
	 * - http://localhost/
385
	 * - http://localhost/index.php
386
	 * - http://localhost/index.php/s/{shareToken}
387
	 *
388
	 * all return: http://localhost
389
	 *
390
	 * @param string $remote
391
	 * @return string
392
	 */
393 View Code Duplication
	protected function fixRemoteURL($remote) {
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...
394
		$remote = str_replace('\\', '/', $remote);
395
		if ($fileNamePosition = strpos($remote, '/index.php')) {
396
			$remote = substr($remote, 0, $fileNamePosition);
397
		}
398
		$remote = rtrim($remote, '/');
399
400
		return $remote;
401
	}
402
403
	/**
404
	 * @NoAdminRequired
405
	 *
406
	 * @param string $search
407
	 * @param string $itemType
408
	 * @param int $page
409
	 * @param int $perPage
410
	 * @param int|int[] $shareType
411
	 * @param bool $lookup
412
	 * @return Http\DataResponse
413
	 * @throws OCSBadRequestException
414
	 */
415
	public function search($search = '', $itemType = null, $page = 1, $perPage = 200, $shareType = null, $lookup = true) {
416
		if ($perPage <= 0) {
417
			throw new OCSBadRequestException('Invalid perPage argument');
418
		}
419
		if ($page <= 0) {
420
			throw new OCSBadRequestException('Invalid page');
421
		}
422
423
		$shareTypes = [
424
			Share::SHARE_TYPE_USER,
425
		];
426
427
		if ($itemType === 'file' || $itemType === 'folder') {
428
			if ($this->shareManager->allowGroupSharing()) {
429
				$shareTypes[] = Share::SHARE_TYPE_GROUP;
430
			}
431
432
			if ($this->isRemoteSharingAllowed($itemType)) {
433
				$shareTypes[] = Share::SHARE_TYPE_REMOTE;
434
			}
435
436
			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
437
				$shareTypes[] = Share::SHARE_TYPE_EMAIL;
438
			}
439
		} else {
440
			$shareTypes[] = Share::SHARE_TYPE_GROUP;
441
			$shareTypes[] = Share::SHARE_TYPE_EMAIL;
442
		}
443
444
		if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
445
			$shareTypes = array_intersect($shareTypes, $_GET['shareType']);
446
			sort($shareTypes);
447
		} else if (is_numeric($shareType)) {
448
			$shareTypes = array_intersect($shareTypes, [(int) $shareType]);
449
			sort($shareTypes);
450
		}
451
452
		$this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
453
		$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
454
		$this->limit = (int) $perPage;
455
		$this->offset = $perPage * ($page - 1);
456
457
		return $this->searchSharees($search, $itemType, $shareTypes, $page, $perPage, $lookup);
458
	}
459
460
	/**
461
	 * Method to get out the static call for better testing
462
	 *
463
	 * @param string $itemType
464
	 * @return bool
465
	 */
466
	protected function isRemoteSharingAllowed($itemType) {
467
		try {
468
			$backend = Share::getBackend($itemType);
469
			return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE);
470
		} catch (\Exception $e) {
471
			return false;
472
		}
473
	}
474
475
	/**
476
	 * Testable search function that does not need globals
477
	 *
478
	 * @param string $search
479
	 * @param string $itemType
480
	 * @param array $shareTypes
481
	 * @param int $page
482
	 * @param int $perPage
483
	 * @param bool $lookup
484
	 * @return Http\DataResponse
485
	 * @throws OCSBadRequestException
486
	 */
487
	protected function searchSharees($search, $itemType, array $shareTypes, $page, $perPage, $lookup) {
488
		// Verify arguments
489
		if ($itemType === null) {
490
			throw new OCSBadRequestException('Missing itemType');
491
		}
492
493
		// Get users
494
		if (in_array(Share::SHARE_TYPE_USER, $shareTypes)) {
495
			$this->getUsers($search);
496
		}
497
498
		// Get groups
499
		if (in_array(Share::SHARE_TYPE_GROUP, $shareTypes)) {
500
			$this->getGroups($search);
501
		}
502
503
		// Get remote
504
		$remoteResults = ['results' => [], 'exact' => [], 'exactIdMatch' => false];
505
		if (in_array(Share::SHARE_TYPE_REMOTE, $shareTypes)) {
506
			$remoteResults = $this->getRemote($search);
507
		}
508
509
		// Get emails
510
		$mailResults = ['results' => [], 'exact' => [], 'exactIdMatch' => false];
511
		if (in_array(Share::SHARE_TYPE_EMAIL, $shareTypes)) {
512
			$mailResults = $this->getEmail($search);
513
		}
514
515
		// Get from lookup server
516
		if ($lookup) {
517
			$this->getLookup($search);
518
		}
519
520
		// if we have a exact match, either for the federated cloud id or for the
521
		// email address we only return the exact match. It is highly unlikely
522
		// that the exact same email address and federated cloud id exists
523
		if ($mailResults['exactIdMatch'] && !$remoteResults['exactIdMatch']) {
524
			$this->result['emails'] = $mailResults['results'];
525
			$this->result['exact']['emails'] = $mailResults['exact'];
526
		} else if (!$mailResults['exactIdMatch'] && $remoteResults['exactIdMatch']) {
527
			$this->result['remotes'] = $remoteResults['results'];
528
			$this->result['exact']['remotes'] = $remoteResults['exact'];
529
		} else {
530
			$this->result['remotes'] = $remoteResults['results'];
531
			$this->result['exact']['remotes'] = $remoteResults['exact'];
532
			$this->result['emails'] = $mailResults['results'];
533
			$this->result['exact']['emails'] = $mailResults['exact'];
534
		}
535
536
		$response = new Http\DataResponse($this->result);
537
538
		if (sizeof($this->reachedEndFor) < 3) {
539
			$response->addHeader('Link', $this->getPaginationLink($page, [
540
				'search' => $search,
541
				'itemType' => $itemType,
542
				'shareType' => $shareTypes,
543
				'perPage' => $perPage,
544
			]));
545
		}
546
547
		return $response;
548
	}
549
550
	/**
551
	 * @param string $search
552
	 * @return array
553
	 */
554
	protected function getEmail($search) {
555
		$result = ['results' => [], 'exact' => []];
556
557
		// Search in contacts
558
		//@todo Pagination missing
559
		$addressBookContacts = $this->contactsManager->search($search, ['EMAIL', 'FN']);
560
		$result['exactIdMatch'] = false;
561
		foreach ($addressBookContacts as $contact) {
562
			if (isset($contact['isLocalSystemBook'])) {
563
				continue;
564
			}
565
			if (isset($contact['EMAIL'])) {
566
				$emailAddresses = $contact['EMAIL'];
567
				if (!is_array($emailAddresses)) {
568
					$emailAddresses = [$emailAddresses];
569
				}
570
				foreach ($emailAddresses as $emailAddress) {
571
					if (strtolower($contact['FN']) === strtolower($search) || strtolower($emailAddress) === strtolower($search)) {
572
						if (strtolower($emailAddress) === strtolower($search)) {
573
							$result['exactIdMatch'] = true;
574
						}
575
						$result['exact'][] = [
576
							'label' => $contact['FN'] . " ($emailAddress)",
577
							'value' => [
578
								'shareType' => Share::SHARE_TYPE_EMAIL,
579
								'shareWith' => $emailAddress,
580
							],
581
						];
582 View Code Duplication
					} else {
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...
583
						$result['results'][] = [
584
							'label' => $contact['FN'] . " ($emailAddress)",
585
							'value' => [
586
								'shareType' => Share::SHARE_TYPE_EMAIL,
587
								'shareWith' => $emailAddress,
588
							],
589
						];
590
					}
591
				}
592
			}
593
		}
594
595
		if (!$this->shareeEnumeration) {
596
			$result['results'] = [];
597
		}
598
599
		if (!$result['exactIdMatch'] && filter_var($search, FILTER_VALIDATE_EMAIL)) {
600
			$result['exact'][] = [
601
				'label' => $search,
602
				'value' => [
603
					'shareType' => Share::SHARE_TYPE_EMAIL,
604
					'shareWith' => $search,
605
				],
606
			];
607
		}
608
609
		$this->reachedEndFor[] = 'emails';
610
611
		return $result;
612
	}
613
614
	protected function getLookup($search) {
615
		$isEnabled = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no');
616
		$result = [];
617
618
		if($isEnabled === 'yes') {
619
			try {
620
				$client = $this->clientService->newClient();
621
				$response = $client->get(
622
					'https://lookup.nextcloud.com/users?search=' . urlencode($search),
623
					[
624
						'timeout' => 10,
625
						'connect_timeout' => 3,
626
					]
627
				);
628
629
				$body = json_decode($response->getBody(), true);
630
631
				$result = [];
632
				foreach ($body as $lookup) {
633
					$result[] = [
634
						'label' => $lookup['federationId'],
635
						'value' => [
636
							'shareType' => Share::SHARE_TYPE_REMOTE,
637
							'shareWith' => $lookup['federationId'],
638
						],
639
						'extra' => $lookup,
640
					];
641
				}
642
			} catch (\Exception $e) {}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
643
		}
644
645
		$this->result['lookup'] = $result;
646
	}
647
648
	/**
649
	 * Generates a bunch of pagination links for the current page
650
	 *
651
	 * @param int $page Current page
652
	 * @param array $params Parameters for the URL
653
	 * @return string
654
	 */
655
	protected function getPaginationLink($page, array $params) {
656
		if ($this->isV2()) {
657
			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
658
		} else {
659
			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
660
		}
661
		$params['page'] = $page + 1;
662
		$link = '<' . $url . http_build_query($params) . '>; rel="next"';
663
664
		return $link;
665
	}
666
667
	/**
668
	 * @return bool
669
	 */
670
	protected function isV2() {
671
		return $this->request->getScriptName() === '/ocs/v2.php';
672
	}
673
}
674