Passed
Push — master ( a3d936...73b8b5 )
by Roeland
10:48
created
lib/private/Collaboration/Collaborators/LookupPlugin.php 2 patches
Indentation   +74 added lines, -74 removed lines patch added patch discarded remove patch
@@ -36,87 +36,87 @@
 block discarded – undo
36 36
 
37 37
 class LookupPlugin implements ISearchPlugin {
38 38
 
39
-	/** @var IConfig */
40
-	private $config;
41
-	/** @var IClientService */
42
-	private $clientService;
43
-	/** @var string remote part of the current user's cloud id */
44
-	private $currentUserRemote;
45
-	/** @var ICloudIdManager */
46
-	private $cloudIdManager;
47
-	/** @var ILogger */
48
-	private $logger;
39
+    /** @var IConfig */
40
+    private $config;
41
+    /** @var IClientService */
42
+    private $clientService;
43
+    /** @var string remote part of the current user's cloud id */
44
+    private $currentUserRemote;
45
+    /** @var ICloudIdManager */
46
+    private $cloudIdManager;
47
+    /** @var ILogger */
48
+    private $logger;
49 49
 
50
-	public function __construct(IConfig $config,
51
-								IClientService $clientService,
52
-								IUserSession $userSession,
53
-								ICloudIdManager $cloudIdManager,
54
-								ILogger $logger) {
55
-		$this->config = $config;
56
-		$this->clientService = $clientService;
57
-		$this->cloudIdManager = $cloudIdManager;
58
-		$currentUserCloudId = $userSession->getUser()->getCloudId();
59
-		$this->currentUserRemote = $cloudIdManager->resolveCloudId($currentUserCloudId)->getRemote();
60
-		$this->logger = $logger;
61
-	}
50
+    public function __construct(IConfig $config,
51
+                                IClientService $clientService,
52
+                                IUserSession $userSession,
53
+                                ICloudIdManager $cloudIdManager,
54
+                                ILogger $logger) {
55
+        $this->config = $config;
56
+        $this->clientService = $clientService;
57
+        $this->cloudIdManager = $cloudIdManager;
58
+        $currentUserCloudId = $userSession->getUser()->getCloudId();
59
+        $this->currentUserRemote = $cloudIdManager->resolveCloudId($currentUserCloudId)->getRemote();
60
+        $this->logger = $logger;
61
+    }
62 62
 
63
-	public function search($search, $limit, $offset, ISearchResult $searchResult) {
64
-		$isGlobalScaleEnabled = $this->config->getSystemValue('gs.enabled', false);
65
-		$isLookupServerEnabled = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes') === 'yes';
66
-		$hasInternetConnection = (bool)$this->config->getSystemValue('has_internet_connection', true);
63
+    public function search($search, $limit, $offset, ISearchResult $searchResult) {
64
+        $isGlobalScaleEnabled = $this->config->getSystemValue('gs.enabled', false);
65
+        $isLookupServerEnabled = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes') === 'yes';
66
+        $hasInternetConnection = (bool)$this->config->getSystemValue('has_internet_connection', true);
67 67
 
68
-		// if case of Global Scale we always search the lookup server
69
-		if (!$isGlobalScaleEnabled && (!$isLookupServerEnabled || !$hasInternetConnection)) {
70
-			return false;
71
-		}
68
+        // if case of Global Scale we always search the lookup server
69
+        if (!$isGlobalScaleEnabled && (!$isLookupServerEnabled || !$hasInternetConnection)) {
70
+            return false;
71
+        }
72 72
 
73
-		$lookupServerUrl = $this->config->getSystemValue('lookup_server', 'https://lookup.nextcloud.com');
74
-		if(empty($lookupServerUrl)) {
75
-			return false;
76
-		}
77
-		$lookupServerUrl = rtrim($lookupServerUrl, '/');
78
-		$result = [];
73
+        $lookupServerUrl = $this->config->getSystemValue('lookup_server', 'https://lookup.nextcloud.com');
74
+        if(empty($lookupServerUrl)) {
75
+            return false;
76
+        }
77
+        $lookupServerUrl = rtrim($lookupServerUrl, '/');
78
+        $result = [];
79 79
 
80
-		try {
81
-			$client = $this->clientService->newClient();
82
-			$response = $client->get(
83
-				$lookupServerUrl . '/users?search=' . urlencode($search),
84
-				[
85
-					'timeout' => 10,
86
-					'connect_timeout' => 3,
87
-				]
88
-			);
80
+        try {
81
+            $client = $this->clientService->newClient();
82
+            $response = $client->get(
83
+                $lookupServerUrl . '/users?search=' . urlencode($search),
84
+                [
85
+                    'timeout' => 10,
86
+                    'connect_timeout' => 3,
87
+                ]
88
+            );
89 89
 
90
-			$body = json_decode($response->getBody(), true);
90
+            $body = json_decode($response->getBody(), true);
91 91
 
92
-			foreach ($body as $lookup) {
93
-				try {
94
-					$remote = $this->cloudIdManager->resolveCloudId($lookup['federationId'])->getRemote();
95
-				} catch (\Exception $e) {
96
-					$this->logger->error('Can not parse federated cloud ID "' .  $lookup['federationId'] . '"');
97
-					$this->logger->error($e->getMessage());
98
-					continue;
99
-				}
100
-				if ($this->currentUserRemote === $remote) {
101
-					continue;
102
-				}
103
-				$name = isset($lookup['name']['value']) ? $lookup['name']['value'] : '';
104
-				$label = empty($name) ? $lookup['federationId'] : $name . ' (' . $lookup['federationId'] . ')';
105
-				$result[] = [
106
-					'label' => $label,
107
-					'value' => [
108
-						'shareType' => Share::SHARE_TYPE_REMOTE,
109
-						'shareWith' => $lookup['federationId'],
110
-					],
111
-					'extra' => $lookup,
112
-				];
113
-			}
114
-		} catch (\Exception $e) {
115
-		}
92
+            foreach ($body as $lookup) {
93
+                try {
94
+                    $remote = $this->cloudIdManager->resolveCloudId($lookup['federationId'])->getRemote();
95
+                } catch (\Exception $e) {
96
+                    $this->logger->error('Can not parse federated cloud ID "' .  $lookup['federationId'] . '"');
97
+                    $this->logger->error($e->getMessage());
98
+                    continue;
99
+                }
100
+                if ($this->currentUserRemote === $remote) {
101
+                    continue;
102
+                }
103
+                $name = isset($lookup['name']['value']) ? $lookup['name']['value'] : '';
104
+                $label = empty($name) ? $lookup['federationId'] : $name . ' (' . $lookup['federationId'] . ')';
105
+                $result[] = [
106
+                    'label' => $label,
107
+                    'value' => [
108
+                        'shareType' => Share::SHARE_TYPE_REMOTE,
109
+                        'shareWith' => $lookup['federationId'],
110
+                    ],
111
+                    'extra' => $lookup,
112
+                ];
113
+            }
114
+        } catch (\Exception $e) {
115
+        }
116 116
 
117
-		$type = new SearchResultType('lookup');
118
-		$searchResult->addResultSet($type, $result, []);
117
+        $type = new SearchResultType('lookup');
118
+        $searchResult->addResultSet($type, $result, []);
119 119
 
120
-		return false;
121
-	}
120
+        return false;
121
+    }
122 122
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -63,7 +63,7 @@  discard block
 block discarded – undo
63 63
 	public function search($search, $limit, $offset, ISearchResult $searchResult) {
64 64
 		$isGlobalScaleEnabled = $this->config->getSystemValue('gs.enabled', false);
65 65
 		$isLookupServerEnabled = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes') === 'yes';
66
-		$hasInternetConnection = (bool)$this->config->getSystemValue('has_internet_connection', true);
66
+		$hasInternetConnection = (bool) $this->config->getSystemValue('has_internet_connection', true);
67 67
 
68 68
 		// if case of Global Scale we always search the lookup server
69 69
 		if (!$isGlobalScaleEnabled && (!$isLookupServerEnabled || !$hasInternetConnection)) {
@@ -71,7 +71,7 @@  discard block
 block discarded – undo
71 71
 		}
72 72
 
73 73
 		$lookupServerUrl = $this->config->getSystemValue('lookup_server', 'https://lookup.nextcloud.com');
74
-		if(empty($lookupServerUrl)) {
74
+		if (empty($lookupServerUrl)) {
75 75
 			return false;
76 76
 		}
77 77
 		$lookupServerUrl = rtrim($lookupServerUrl, '/');
@@ -80,7 +80,7 @@  discard block
 block discarded – undo
80 80
 		try {
81 81
 			$client = $this->clientService->newClient();
82 82
 			$response = $client->get(
83
-				$lookupServerUrl . '/users?search=' . urlencode($search),
83
+				$lookupServerUrl.'/users?search='.urlencode($search),
84 84
 				[
85 85
 					'timeout' => 10,
86 86
 					'connect_timeout' => 3,
@@ -93,7 +93,7 @@  discard block
 block discarded – undo
93 93
 				try {
94 94
 					$remote = $this->cloudIdManager->resolveCloudId($lookup['federationId'])->getRemote();
95 95
 				} catch (\Exception $e) {
96
-					$this->logger->error('Can not parse federated cloud ID "' .  $lookup['federationId'] . '"');
96
+					$this->logger->error('Can not parse federated cloud ID "'.$lookup['federationId'].'"');
97 97
 					$this->logger->error($e->getMessage());
98 98
 					continue;
99 99
 				}
@@ -101,7 +101,7 @@  discard block
 block discarded – undo
101 101
 					continue;
102 102
 				}
103 103
 				$name = isset($lookup['name']['value']) ? $lookup['name']['value'] : '';
104
-				$label = empty($name) ? $lookup['federationId'] : $name . ' (' . $lookup['federationId'] . ')';
104
+				$label = empty($name) ? $lookup['federationId'] : $name.' ('.$lookup['federationId'].')';
105 105
 				$result[] = [
106 106
 					'label' => $label,
107 107
 					'value' => [
Please login to merge, or discard this patch.
apps/files_sharing/lib/Controller/ShareesAPIController.php 1 patch
Indentation   +371 added lines, -371 removed lines patch added patch discarded remove patch
@@ -49,375 +49,375 @@
 block discarded – undo
49 49
 
50 50
 class ShareesAPIController extends OCSController {
51 51
 
52
-	/** @var userId */
53
-	protected $userId;
54
-
55
-	/** @var IConfig */
56
-	protected $config;
57
-
58
-	/** @var IURLGenerator */
59
-	protected $urlGenerator;
60
-
61
-	/** @var IManager */
62
-	protected $shareManager;
63
-
64
-	/** @var bool */
65
-	protected $shareWithGroupOnly = false;
66
-
67
-	/** @var bool */
68
-	protected $shareeEnumeration = true;
69
-
70
-	/** @var int */
71
-	protected $offset = 0;
72
-
73
-	/** @var int */
74
-	protected $limit = 10;
75
-
76
-	/** @var array */
77
-	protected $result = [
78
-		'exact' => [
79
-			'users' => [],
80
-			'groups' => [],
81
-			'remotes' => [],
82
-			'remote_groups' => [],
83
-			'emails' => [],
84
-			'circles' => [],
85
-			'rooms' => [],
86
-		],
87
-		'users' => [],
88
-		'groups' => [],
89
-		'remotes' => [],
90
-		'remote_groups' => [],
91
-		'emails' => [],
92
-		'lookup' => [],
93
-		'circles' => [],
94
-		'rooms' => [],
95
-		'lookupEnabled' => false,
96
-	];
97
-
98
-	protected $reachedEndFor = [];
99
-	/** @var ISearch */
100
-	private $collaboratorSearch;
101
-
102
-	/**
103
-	 * @param string $UserId
104
-	 * @param string $appName
105
-	 * @param IRequest $request
106
-	 * @param IConfig $config
107
-	 * @param IURLGenerator $urlGenerator
108
-	 * @param IManager $shareManager
109
-	 * @param ISearch $collaboratorSearch
110
-	 */
111
-	public function __construct(
112
-		$UserId,
113
-		string $appName,
114
-		IRequest $request,
115
-		IConfig $config,
116
-		IURLGenerator $urlGenerator,
117
-		IManager $shareManager,
118
-		ISearch $collaboratorSearch
119
-	) {
120
-		parent::__construct($appName, $request);
121
-		$this->userId = $UserId;
122
-		$this->config = $config;
123
-		$this->urlGenerator = $urlGenerator;
124
-		$this->shareManager = $shareManager;
125
-		$this->collaboratorSearch = $collaboratorSearch;
126
-	}
127
-
128
-	/**
129
-	 * @NoAdminRequired
130
-	 *
131
-	 * @param string $search
132
-	 * @param string $itemType
133
-	 * @param int $page
134
-	 * @param int $perPage
135
-	 * @param int|int[] $shareType
136
-	 * @param bool $lookup
137
-	 * @return DataResponse
138
-	 * @throws OCSBadRequestException
139
-	 */
140
-	public function search(string $search = '', string $itemType = null, int $page = 1, int $perPage = 200, $shareType = null, bool $lookup = true): DataResponse {
141
-
142
-		// only search for string larger than a given threshold
143
-		$threshold = (int)$this->config->getSystemValue('sharing.minSearchStringLength', 0);
144
-		if (strlen($search) < $threshold) {
145
-			return new DataResponse($this->result);
146
-		}
147
-
148
-		// never return more than the max. number of results configured in the config.php
149
-		$maxResults = (int)$this->config->getSystemValue('sharing.maxAutocompleteResults', 0);
150
-		if ($maxResults > 0) {
151
-			$perPage = min($perPage, $maxResults);
152
-		}
153
-		if ($perPage <= 0) {
154
-			throw new OCSBadRequestException('Invalid perPage argument');
155
-		}
156
-		if ($page <= 0) {
157
-			throw new OCSBadRequestException('Invalid page');
158
-		}
159
-
160
-		$shareTypes = [
161
-			Share::SHARE_TYPE_USER,
162
-		];
163
-
164
-		if ($itemType === null) {
165
-			throw new OCSBadRequestException('Missing itemType');
166
-		} elseif ($itemType === 'file' || $itemType === 'folder') {
167
-			if ($this->shareManager->allowGroupSharing()) {
168
-				$shareTypes[] = Share::SHARE_TYPE_GROUP;
169
-			}
170
-
171
-			if ($this->isRemoteSharingAllowed($itemType)) {
172
-				$shareTypes[] = Share::SHARE_TYPE_REMOTE;
173
-			}
174
-
175
-			if ($this->isRemoteGroupSharingAllowed($itemType)) {
176
-				$shareTypes[] = Share::SHARE_TYPE_REMOTE_GROUP;
177
-			}
178
-
179
-			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
180
-				$shareTypes[] = Share::SHARE_TYPE_EMAIL;
181
-			}
182
-
183
-			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_ROOM)) {
184
-				$shareTypes[] = Share::SHARE_TYPE_ROOM;
185
-			}
186
-		} else {
187
-			$shareTypes[] = Share::SHARE_TYPE_GROUP;
188
-			$shareTypes[] = Share::SHARE_TYPE_EMAIL;
189
-		}
190
-
191
-		// FIXME: DI
192
-		if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
193
-			$shareTypes[] = Share::SHARE_TYPE_CIRCLE;
194
-		}
195
-
196
-		if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
197
-			$shareTypes = array_intersect($shareTypes, $_GET['shareType']);
198
-			sort($shareTypes);
199
-		} else if (is_numeric($shareType)) {
200
-			$shareTypes = array_intersect($shareTypes, [(int) $shareType]);
201
-			sort($shareTypes);
202
-		}
203
-
204
-		$this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
205
-		$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
206
-		$this->limit = (int) $perPage;
207
-		$this->offset = $perPage * ($page - 1);
208
-
209
-		list($result, $hasMoreResults) = $this->collaboratorSearch->search($search, $shareTypes, $lookup, $this->limit, $this->offset);
210
-
211
-		// extra treatment for 'exact' subarray, with a single merge expected keys might be lost
212
-		if(isset($result['exact'])) {
213
-			$result['exact'] = array_merge($this->result['exact'], $result['exact']);
214
-		}
215
-		$this->result = array_merge($this->result, $result);
216
-		$this->result['lookupEnabled'] = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes') === 'yes';
217
-		$response = new DataResponse($this->result);
218
-
219
-		if ($hasMoreResults) {
220
-			$response->addHeader('Link', $this->getPaginationLink($page, [
221
-				'search' => $search,
222
-				'itemType' => $itemType,
223
-				'shareType' => $shareTypes,
224
-				'perPage' => $perPage,
225
-			]));
226
-		}
227
-
228
-		return $response;
229
-	}
230
-
231
-	/**
232
-	 * @param string $user
233
-	 * @param int $shareType
234
-	 *
235
-	 * @return Generator<array<string>>
236
-	 */
237
-	private function getAllShareesByType(string $user, int $shareType): Generator {
238
-		$offset = 0;
239
-		$pageSize = 50;
240
-
241
-		while (count($page = $this->shareManager->getSharesBy(
242
-			$user,
243
-			$shareType,
244
-			null,
245
-			false,
246
-			$pageSize,
247
-			$offset
248
-		))) {
249
-			foreach ($page as $share) {
250
-				yield [$share->getSharedWith(), $share->getSharedWithDisplayName() ?? $share->getSharedWith()];
251
-			}
252
-
253
-			$offset += $pageSize;
254
-		}
255
-	}
256
-
257
-	private function sortShareesByFrequency(array $sharees): array {
258
-		usort($sharees, function(array $s1, array $s2) {
259
-			return $s2['count'] - $s1['count'];
260
-		});
261
-		return $sharees;
262
-	}
263
-
264
-	private $searchResultTypeMap = [
265
-		Share::SHARE_TYPE_USER => 'users',
266
-		Share::SHARE_TYPE_GROUP => 'groups',
267
-		Share::SHARE_TYPE_REMOTE => 'remotes',
268
-		Share::SHARE_TYPE_REMOTE_GROUP => 'remote_groups',
269
-		Share::SHARE_TYPE_EMAIL => 'emails',
270
-	];
271
-
272
-	private function getAllSharees(string $user, array $shareTypes): ISearchResult {
273
-		$result = [];
274
-		foreach ($shareTypes as $shareType) {
275
-			$sharees = $this->getAllShareesByType($user, $shareType);
276
-			$shareTypeResults = [];
277
-			foreach ($sharees as list($sharee, $displayname)) {
278
-				if (!isset($this->searchResultTypeMap[$shareType])) {
279
-					continue;
280
-				}
281
-
282
-				if (!isset($shareTypeResults[$sharee])) {
283
-					$shareTypeResults[$sharee] = [
284
-						'count' => 1,
285
-						'label' => $displayname,
286
-						'value' => [
287
-							'shareType' => $shareType,
288
-							'shareWith' => $sharee,
289
-						],
290
-					];
291
-				} else {
292
-					$shareTypeResults[$sharee]['count']++;
293
-				}
294
-			}
295
-			$result = array_merge($result, array_values($shareTypeResults));
296
-		}
297
-
298
-		$top5 = array_slice(
299
-			$this->sortShareesByFrequency($result),
300
-			0,
301
-			5
302
-		);
303
-
304
-		$searchResult = new SearchResult();
305
-		foreach ($this->searchResultTypeMap as $int => $str) {
306
-			$searchResult->addResultSet(new SearchResultType($str), [], []);
307
-			foreach ($top5 as $x) {
308
-				if ($x['value']['shareType'] === $int) {
309
-					$searchResult->addResultSet(new SearchResultType($str), [], [$x]);
310
-				}
311
-			}
312
-		}
313
-		return $searchResult;
314
-	}
315
-
316
-	/**
317
-	 * @NoAdminRequired
318
-	 *
319
-	 * @param string $itemType
320
-	 * @return DataResponse
321
-	 * @throws OCSBadRequestException
322
-	 */
323
-	public function findRecommended(string $itemType = null, $shareType = null): DataResponse {
324
-		$shareTypes = [
325
-			Share::SHARE_TYPE_USER,
326
-		];
327
-
328
-		if ($itemType === null) {
329
-			throw new OCSBadRequestException('Missing itemType');
330
-		} elseif ($itemType === 'file' || $itemType === 'folder') {
331
-			if ($this->shareManager->allowGroupSharing()) {
332
-				$shareTypes[] = Share::SHARE_TYPE_GROUP;
333
-			}
334
-
335
-			if ($this->isRemoteSharingAllowed($itemType)) {
336
-				$shareTypes[] = Share::SHARE_TYPE_REMOTE;
337
-			}
338
-
339
-			if ($this->isRemoteGroupSharingAllowed($itemType)) {
340
-				$shareTypes[] = Share::SHARE_TYPE_REMOTE_GROUP;
341
-			}
342
-
343
-			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
344
-				$shareTypes[] = Share::SHARE_TYPE_EMAIL;
345
-			}
346
-
347
-			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_ROOM)) {
348
-				$shareTypes[] = Share::SHARE_TYPE_ROOM;
349
-			}
350
-		} else {
351
-			$shareTypes[] = Share::SHARE_TYPE_GROUP;
352
-			$shareTypes[] = Share::SHARE_TYPE_EMAIL;
353
-		}
354
-
355
-		// FIXME: DI
356
-		if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
357
-			$shareTypes[] = Share::SHARE_TYPE_CIRCLE;
358
-		}
359
-
360
-		if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
361
-			$shareTypes = array_intersect($shareTypes, $_GET['shareType']);
362
-			sort($shareTypes);
363
-		} else if (is_numeric($shareType)) {
364
-			$shareTypes = array_intersect($shareTypes, [(int) $shareType]);
365
-			sort($shareTypes);
366
-		}
367
-
368
-		return new DataResponse(
369
-			$this->getAllSharees($this->userId, $shareTypes)->asArray()
370
-		);
371
-	}
372
-
373
-	/**
374
-	 * Method to get out the static call for better testing
375
-	 *
376
-	 * @param string $itemType
377
-	 * @return bool
378
-	 */
379
-	protected function isRemoteSharingAllowed(string $itemType): bool {
380
-		try {
381
-			// FIXME: static foo makes unit testing unnecessarily difficult
382
-			$backend = \OC\Share\Share::getBackend($itemType);
383
-			return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE);
384
-		} catch (\Exception $e) {
385
-			return false;
386
-		}
387
-	}
388
-
389
-	protected function isRemoteGroupSharingAllowed(string $itemType): bool {
390
-		try {
391
-			// FIXME: static foo makes unit testing unnecessarily difficult
392
-			$backend = \OC\Share\Share::getBackend($itemType);
393
-			return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE_GROUP);
394
-		} catch (\Exception $e) {
395
-			return false;
396
-		}
397
-	}
398
-
399
-
400
-	/**
401
-	 * Generates a bunch of pagination links for the current page
402
-	 *
403
-	 * @param int $page Current page
404
-	 * @param array $params Parameters for the URL
405
-	 * @return string
406
-	 */
407
-	protected function getPaginationLink(int $page, array $params): string {
408
-		if ($this->isV2()) {
409
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
410
-		} else {
411
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
412
-		}
413
-		$params['page'] = $page + 1;
414
-		return '<' . $url . http_build_query($params) . '>; rel="next"';
415
-	}
416
-
417
-	/**
418
-	 * @return bool
419
-	 */
420
-	protected function isV2(): bool {
421
-		return $this->request->getScriptName() === '/ocs/v2.php';
422
-	}
52
+    /** @var userId */
53
+    protected $userId;
54
+
55
+    /** @var IConfig */
56
+    protected $config;
57
+
58
+    /** @var IURLGenerator */
59
+    protected $urlGenerator;
60
+
61
+    /** @var IManager */
62
+    protected $shareManager;
63
+
64
+    /** @var bool */
65
+    protected $shareWithGroupOnly = false;
66
+
67
+    /** @var bool */
68
+    protected $shareeEnumeration = true;
69
+
70
+    /** @var int */
71
+    protected $offset = 0;
72
+
73
+    /** @var int */
74
+    protected $limit = 10;
75
+
76
+    /** @var array */
77
+    protected $result = [
78
+        'exact' => [
79
+            'users' => [],
80
+            'groups' => [],
81
+            'remotes' => [],
82
+            'remote_groups' => [],
83
+            'emails' => [],
84
+            'circles' => [],
85
+            'rooms' => [],
86
+        ],
87
+        'users' => [],
88
+        'groups' => [],
89
+        'remotes' => [],
90
+        'remote_groups' => [],
91
+        'emails' => [],
92
+        'lookup' => [],
93
+        'circles' => [],
94
+        'rooms' => [],
95
+        'lookupEnabled' => false,
96
+    ];
97
+
98
+    protected $reachedEndFor = [];
99
+    /** @var ISearch */
100
+    private $collaboratorSearch;
101
+
102
+    /**
103
+     * @param string $UserId
104
+     * @param string $appName
105
+     * @param IRequest $request
106
+     * @param IConfig $config
107
+     * @param IURLGenerator $urlGenerator
108
+     * @param IManager $shareManager
109
+     * @param ISearch $collaboratorSearch
110
+     */
111
+    public function __construct(
112
+        $UserId,
113
+        string $appName,
114
+        IRequest $request,
115
+        IConfig $config,
116
+        IURLGenerator $urlGenerator,
117
+        IManager $shareManager,
118
+        ISearch $collaboratorSearch
119
+    ) {
120
+        parent::__construct($appName, $request);
121
+        $this->userId = $UserId;
122
+        $this->config = $config;
123
+        $this->urlGenerator = $urlGenerator;
124
+        $this->shareManager = $shareManager;
125
+        $this->collaboratorSearch = $collaboratorSearch;
126
+    }
127
+
128
+    /**
129
+     * @NoAdminRequired
130
+     *
131
+     * @param string $search
132
+     * @param string $itemType
133
+     * @param int $page
134
+     * @param int $perPage
135
+     * @param int|int[] $shareType
136
+     * @param bool $lookup
137
+     * @return DataResponse
138
+     * @throws OCSBadRequestException
139
+     */
140
+    public function search(string $search = '', string $itemType = null, int $page = 1, int $perPage = 200, $shareType = null, bool $lookup = true): DataResponse {
141
+
142
+        // only search for string larger than a given threshold
143
+        $threshold = (int)$this->config->getSystemValue('sharing.minSearchStringLength', 0);
144
+        if (strlen($search) < $threshold) {
145
+            return new DataResponse($this->result);
146
+        }
147
+
148
+        // never return more than the max. number of results configured in the config.php
149
+        $maxResults = (int)$this->config->getSystemValue('sharing.maxAutocompleteResults', 0);
150
+        if ($maxResults > 0) {
151
+            $perPage = min($perPage, $maxResults);
152
+        }
153
+        if ($perPage <= 0) {
154
+            throw new OCSBadRequestException('Invalid perPage argument');
155
+        }
156
+        if ($page <= 0) {
157
+            throw new OCSBadRequestException('Invalid page');
158
+        }
159
+
160
+        $shareTypes = [
161
+            Share::SHARE_TYPE_USER,
162
+        ];
163
+
164
+        if ($itemType === null) {
165
+            throw new OCSBadRequestException('Missing itemType');
166
+        } elseif ($itemType === 'file' || $itemType === 'folder') {
167
+            if ($this->shareManager->allowGroupSharing()) {
168
+                $shareTypes[] = Share::SHARE_TYPE_GROUP;
169
+            }
170
+
171
+            if ($this->isRemoteSharingAllowed($itemType)) {
172
+                $shareTypes[] = Share::SHARE_TYPE_REMOTE;
173
+            }
174
+
175
+            if ($this->isRemoteGroupSharingAllowed($itemType)) {
176
+                $shareTypes[] = Share::SHARE_TYPE_REMOTE_GROUP;
177
+            }
178
+
179
+            if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
180
+                $shareTypes[] = Share::SHARE_TYPE_EMAIL;
181
+            }
182
+
183
+            if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_ROOM)) {
184
+                $shareTypes[] = Share::SHARE_TYPE_ROOM;
185
+            }
186
+        } else {
187
+            $shareTypes[] = Share::SHARE_TYPE_GROUP;
188
+            $shareTypes[] = Share::SHARE_TYPE_EMAIL;
189
+        }
190
+
191
+        // FIXME: DI
192
+        if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
193
+            $shareTypes[] = Share::SHARE_TYPE_CIRCLE;
194
+        }
195
+
196
+        if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
197
+            $shareTypes = array_intersect($shareTypes, $_GET['shareType']);
198
+            sort($shareTypes);
199
+        } else if (is_numeric($shareType)) {
200
+            $shareTypes = array_intersect($shareTypes, [(int) $shareType]);
201
+            sort($shareTypes);
202
+        }
203
+
204
+        $this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
205
+        $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
206
+        $this->limit = (int) $perPage;
207
+        $this->offset = $perPage * ($page - 1);
208
+
209
+        list($result, $hasMoreResults) = $this->collaboratorSearch->search($search, $shareTypes, $lookup, $this->limit, $this->offset);
210
+
211
+        // extra treatment for 'exact' subarray, with a single merge expected keys might be lost
212
+        if(isset($result['exact'])) {
213
+            $result['exact'] = array_merge($this->result['exact'], $result['exact']);
214
+        }
215
+        $this->result = array_merge($this->result, $result);
216
+        $this->result['lookupEnabled'] = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes') === 'yes';
217
+        $response = new DataResponse($this->result);
218
+
219
+        if ($hasMoreResults) {
220
+            $response->addHeader('Link', $this->getPaginationLink($page, [
221
+                'search' => $search,
222
+                'itemType' => $itemType,
223
+                'shareType' => $shareTypes,
224
+                'perPage' => $perPage,
225
+            ]));
226
+        }
227
+
228
+        return $response;
229
+    }
230
+
231
+    /**
232
+     * @param string $user
233
+     * @param int $shareType
234
+     *
235
+     * @return Generator<array<string>>
236
+     */
237
+    private function getAllShareesByType(string $user, int $shareType): Generator {
238
+        $offset = 0;
239
+        $pageSize = 50;
240
+
241
+        while (count($page = $this->shareManager->getSharesBy(
242
+            $user,
243
+            $shareType,
244
+            null,
245
+            false,
246
+            $pageSize,
247
+            $offset
248
+        ))) {
249
+            foreach ($page as $share) {
250
+                yield [$share->getSharedWith(), $share->getSharedWithDisplayName() ?? $share->getSharedWith()];
251
+            }
252
+
253
+            $offset += $pageSize;
254
+        }
255
+    }
256
+
257
+    private function sortShareesByFrequency(array $sharees): array {
258
+        usort($sharees, function(array $s1, array $s2) {
259
+            return $s2['count'] - $s1['count'];
260
+        });
261
+        return $sharees;
262
+    }
263
+
264
+    private $searchResultTypeMap = [
265
+        Share::SHARE_TYPE_USER => 'users',
266
+        Share::SHARE_TYPE_GROUP => 'groups',
267
+        Share::SHARE_TYPE_REMOTE => 'remotes',
268
+        Share::SHARE_TYPE_REMOTE_GROUP => 'remote_groups',
269
+        Share::SHARE_TYPE_EMAIL => 'emails',
270
+    ];
271
+
272
+    private function getAllSharees(string $user, array $shareTypes): ISearchResult {
273
+        $result = [];
274
+        foreach ($shareTypes as $shareType) {
275
+            $sharees = $this->getAllShareesByType($user, $shareType);
276
+            $shareTypeResults = [];
277
+            foreach ($sharees as list($sharee, $displayname)) {
278
+                if (!isset($this->searchResultTypeMap[$shareType])) {
279
+                    continue;
280
+                }
281
+
282
+                if (!isset($shareTypeResults[$sharee])) {
283
+                    $shareTypeResults[$sharee] = [
284
+                        'count' => 1,
285
+                        'label' => $displayname,
286
+                        'value' => [
287
+                            'shareType' => $shareType,
288
+                            'shareWith' => $sharee,
289
+                        ],
290
+                    ];
291
+                } else {
292
+                    $shareTypeResults[$sharee]['count']++;
293
+                }
294
+            }
295
+            $result = array_merge($result, array_values($shareTypeResults));
296
+        }
297
+
298
+        $top5 = array_slice(
299
+            $this->sortShareesByFrequency($result),
300
+            0,
301
+            5
302
+        );
303
+
304
+        $searchResult = new SearchResult();
305
+        foreach ($this->searchResultTypeMap as $int => $str) {
306
+            $searchResult->addResultSet(new SearchResultType($str), [], []);
307
+            foreach ($top5 as $x) {
308
+                if ($x['value']['shareType'] === $int) {
309
+                    $searchResult->addResultSet(new SearchResultType($str), [], [$x]);
310
+                }
311
+            }
312
+        }
313
+        return $searchResult;
314
+    }
315
+
316
+    /**
317
+     * @NoAdminRequired
318
+     *
319
+     * @param string $itemType
320
+     * @return DataResponse
321
+     * @throws OCSBadRequestException
322
+     */
323
+    public function findRecommended(string $itemType = null, $shareType = null): DataResponse {
324
+        $shareTypes = [
325
+            Share::SHARE_TYPE_USER,
326
+        ];
327
+
328
+        if ($itemType === null) {
329
+            throw new OCSBadRequestException('Missing itemType');
330
+        } elseif ($itemType === 'file' || $itemType === 'folder') {
331
+            if ($this->shareManager->allowGroupSharing()) {
332
+                $shareTypes[] = Share::SHARE_TYPE_GROUP;
333
+            }
334
+
335
+            if ($this->isRemoteSharingAllowed($itemType)) {
336
+                $shareTypes[] = Share::SHARE_TYPE_REMOTE;
337
+            }
338
+
339
+            if ($this->isRemoteGroupSharingAllowed($itemType)) {
340
+                $shareTypes[] = Share::SHARE_TYPE_REMOTE_GROUP;
341
+            }
342
+
343
+            if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
344
+                $shareTypes[] = Share::SHARE_TYPE_EMAIL;
345
+            }
346
+
347
+            if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_ROOM)) {
348
+                $shareTypes[] = Share::SHARE_TYPE_ROOM;
349
+            }
350
+        } else {
351
+            $shareTypes[] = Share::SHARE_TYPE_GROUP;
352
+            $shareTypes[] = Share::SHARE_TYPE_EMAIL;
353
+        }
354
+
355
+        // FIXME: DI
356
+        if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
357
+            $shareTypes[] = Share::SHARE_TYPE_CIRCLE;
358
+        }
359
+
360
+        if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
361
+            $shareTypes = array_intersect($shareTypes, $_GET['shareType']);
362
+            sort($shareTypes);
363
+        } else if (is_numeric($shareType)) {
364
+            $shareTypes = array_intersect($shareTypes, [(int) $shareType]);
365
+            sort($shareTypes);
366
+        }
367
+
368
+        return new DataResponse(
369
+            $this->getAllSharees($this->userId, $shareTypes)->asArray()
370
+        );
371
+    }
372
+
373
+    /**
374
+     * Method to get out the static call for better testing
375
+     *
376
+     * @param string $itemType
377
+     * @return bool
378
+     */
379
+    protected function isRemoteSharingAllowed(string $itemType): bool {
380
+        try {
381
+            // FIXME: static foo makes unit testing unnecessarily difficult
382
+            $backend = \OC\Share\Share::getBackend($itemType);
383
+            return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE);
384
+        } catch (\Exception $e) {
385
+            return false;
386
+        }
387
+    }
388
+
389
+    protected function isRemoteGroupSharingAllowed(string $itemType): bool {
390
+        try {
391
+            // FIXME: static foo makes unit testing unnecessarily difficult
392
+            $backend = \OC\Share\Share::getBackend($itemType);
393
+            return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE_GROUP);
394
+        } catch (\Exception $e) {
395
+            return false;
396
+        }
397
+    }
398
+
399
+
400
+    /**
401
+     * Generates a bunch of pagination links for the current page
402
+     *
403
+     * @param int $page Current page
404
+     * @param array $params Parameters for the URL
405
+     * @return string
406
+     */
407
+    protected function getPaginationLink(int $page, array $params): string {
408
+        if ($this->isV2()) {
409
+            $url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
410
+        } else {
411
+            $url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
412
+        }
413
+        $params['page'] = $page + 1;
414
+        return '<' . $url . http_build_query($params) . '>; rel="next"';
415
+    }
416
+
417
+    /**
418
+     * @return bool
419
+     */
420
+    protected function isV2(): bool {
421
+        return $this->request->getScriptName() === '/ocs/v2.php';
422
+    }
423 423
 }
Please login to merge, or discard this patch.