Passed
Push — master ( 940996...528516 )
by Morris
12:31 queued 10s
created
apps/dav/lib/Connector/Sabre/Principal.php 1 patch
Indentation   +477 added lines, -477 removed lines patch added patch discarded remove patch
@@ -51,481 +51,481 @@
 block discarded – undo
51 51
 
52 52
 class Principal implements BackendInterface {
53 53
 
54
-	/** @var IUserManager */
55
-	private $userManager;
56
-
57
-	/** @var IGroupManager */
58
-	private $groupManager;
59
-
60
-	/** @var IShareManager */
61
-	private $shareManager;
62
-
63
-	/** @var IUserSession */
64
-	private $userSession;
65
-
66
-	/** @var IAppManager */
67
-	private $appManager;
68
-
69
-	/** @var string */
70
-	private $principalPrefix;
71
-
72
-	/** @var bool */
73
-	private $hasGroups;
74
-
75
-	/** @var bool */
76
-	private $hasCircles;
77
-
78
-	/** @var ProxyMapper */
79
-	private $proxyMapper;
80
-
81
-	/** @var IConfig */
82
-	private $config;
83
-
84
-	/**
85
-	 * Principal constructor.
86
-	 *
87
-	 * @param IUserManager $userManager
88
-	 * @param IGroupManager $groupManager
89
-	 * @param IShareManager $shareManager
90
-	 * @param IUserSession $userSession
91
-	 * @param IAppManager $appManager
92
-	 * @param ProxyMapper $proxyMapper
93
-	 * @param IConfig $config
94
-	 * @param string $principalPrefix
95
-	 */
96
-	public function __construct(IUserManager $userManager,
97
-								IGroupManager $groupManager,
98
-								IShareManager $shareManager,
99
-								IUserSession $userSession,
100
-								IAppManager $appManager,
101
-								ProxyMapper $proxyMapper,
102
-								IConfig $config,
103
-								string $principalPrefix = 'principals/users/') {
104
-		$this->userManager = $userManager;
105
-		$this->groupManager = $groupManager;
106
-		$this->shareManager = $shareManager;
107
-		$this->userSession = $userSession;
108
-		$this->appManager = $appManager;
109
-		$this->principalPrefix = trim($principalPrefix, '/');
110
-		$this->hasGroups = $this->hasCircles = ($principalPrefix === 'principals/users/');
111
-		$this->proxyMapper = $proxyMapper;
112
-		$this->config = $config;
113
-	}
114
-
115
-	use PrincipalProxyTrait {
116
-		getGroupMembership as protected traitGetGroupMembership;
117
-	}
118
-
119
-	/**
120
-	 * Returns a list of principals based on a prefix.
121
-	 *
122
-	 * This prefix will often contain something like 'principals'. You are only
123
-	 * expected to return principals that are in this base path.
124
-	 *
125
-	 * You are expected to return at least a 'uri' for every user, you can
126
-	 * return any additional properties if you wish so. Common properties are:
127
-	 *   {DAV:}displayname
128
-	 *
129
-	 * @param string $prefixPath
130
-	 * @return string[]
131
-	 */
132
-	public function getPrincipalsByPrefix($prefixPath) {
133
-		$principals = [];
134
-
135
-		if ($prefixPath === $this->principalPrefix) {
136
-			foreach ($this->userManager->search('') as $user) {
137
-				$principals[] = $this->userToPrincipal($user);
138
-			}
139
-		}
140
-
141
-		return $principals;
142
-	}
143
-
144
-	/**
145
-	 * Returns a specific principal, specified by it's path.
146
-	 * The returned structure should be the exact same as from
147
-	 * getPrincipalsByPrefix.
148
-	 *
149
-	 * @param string $path
150
-	 * @return array
151
-	 */
152
-	public function getPrincipalByPath($path) {
153
-		list($prefix, $name) = \Sabre\Uri\split($path);
154
-
155
-		if ($name === 'calendar-proxy-write' || $name === 'calendar-proxy-read') {
156
-			list($prefix2, $name2) = \Sabre\Uri\split($prefix);
157
-
158
-			if ($prefix2 === $this->principalPrefix) {
159
-				$user = $this->userManager->get($name2);
160
-
161
-				if ($user !== null) {
162
-					return [
163
-						'uri' => 'principals/users/' . $user->getUID() . '/' . $name,
164
-					];
165
-				}
166
-				return null;
167
-			}
168
-		}
169
-
170
-		if ($prefix === $this->principalPrefix) {
171
-			// Depending on where it is called, it may happen that this function
172
-			// is called either with a urlencoded version of the name or with a non-urlencoded one.
173
-			// The urldecode function replaces %## and +, both of which are forbidden in usernames.
174
-			// Hence there can be no ambiguity here and it is safe to call urldecode on all usernames
175
-			$user = $this->userManager->get(urldecode($name));
176
-
177
-			if ($user !== null) {
178
-				return $this->userToPrincipal($user);
179
-			}
180
-		} elseif ($prefix === 'principals/circles') {
181
-			if ($this->userSession->getUser() !== null) {
182
-				return $this->circleToPrincipal($name);
183
-			}
184
-		}
185
-		return null;
186
-	}
187
-
188
-	/**
189
-	 * Returns the list of groups a principal is a member of
190
-	 *
191
-	 * @param string $principal
192
-	 * @param bool $needGroups
193
-	 * @return array
194
-	 * @throws Exception
195
-	 */
196
-	public function getGroupMembership($principal, $needGroups = false) {
197
-		list($prefix, $name) = \Sabre\Uri\split($principal);
198
-
199
-		if ($prefix !== $this->principalPrefix) {
200
-			return [];
201
-		}
202
-
203
-		$user = $this->userManager->get($name);
204
-		if (!$user) {
205
-			throw new Exception('Principal not found');
206
-		}
207
-
208
-		$groups = [];
209
-
210
-		if ($this->hasGroups || $needGroups) {
211
-			$userGroups = $this->groupManager->getUserGroups($user);
212
-			foreach ($userGroups as $userGroup) {
213
-				$groups[] = 'principals/groups/' . urlencode($userGroup->getGID());
214
-			}
215
-		}
216
-
217
-		$groups = array_unique(array_merge(
218
-			$groups,
219
-			$this->traitGetGroupMembership($principal, $needGroups)
220
-		));
221
-
222
-		return $groups;
223
-	}
224
-
225
-	/**
226
-	 * @param string $path
227
-	 * @param PropPatch $propPatch
228
-	 * @return int
229
-	 */
230
-	public function updatePrincipal($path, PropPatch $propPatch) {
231
-		return 0;
232
-	}
233
-
234
-	/**
235
-	 * Search user principals
236
-	 *
237
-	 * @param array $searchProperties
238
-	 * @param string $test
239
-	 * @return array
240
-	 */
241
-	protected function searchUserPrincipals(array $searchProperties, $test = 'allof') {
242
-		$results = [];
243
-
244
-		// If sharing is disabled, return the empty array
245
-		$shareAPIEnabled = $this->shareManager->shareApiEnabled();
246
-		if (!$shareAPIEnabled) {
247
-			return [];
248
-		}
249
-
250
-		$allowEnumeration = $this->shareManager->allowEnumeration();
251
-		$limitEnumeration = $this->shareManager->limitEnumerationToGroups();
252
-
253
-		// If sharing is restricted to group members only,
254
-		// return only members that have groups in common
255
-		$restrictGroups = false;
256
-		if ($this->shareManager->shareWithGroupMembersOnly()) {
257
-			$user = $this->userSession->getUser();
258
-			if (!$user) {
259
-				return [];
260
-			}
261
-
262
-			$restrictGroups = $this->groupManager->getUserGroupIds($user);
263
-		}
264
-
265
-		$currentUserGroups = [];
266
-		if ($limitEnumeration) {
267
-			$currentUser = $this->userSession->getUser();
268
-			if ($currentUser) {
269
-				$currentUserGroups = $this->groupManager->getUserGroupIds($currentUser);
270
-			}
271
-		}
272
-
273
-		foreach ($searchProperties as $prop => $value) {
274
-			switch ($prop) {
275
-				case '{http://sabredav.org/ns}email-address':
276
-					$users = $this->userManager->getByEmail($value);
277
-
278
-					if (!$allowEnumeration) {
279
-						$users = \array_filter($users, static function (IUser $user) use ($value) {
280
-							return $user->getEMailAddress() === $value;
281
-						});
282
-					}
283
-
284
-					if ($limitEnumeration) {
285
-						$users = \array_filter($users, function (IUser $user) use ($currentUserGroups, $value) {
286
-							return !empty(array_intersect(
287
-									$this->groupManager->getUserGroupIds($user),
288
-									$currentUserGroups
289
-								)) || $user->getEMailAddress() === $value;
290
-						});
291
-					}
292
-
293
-					$results[] = array_reduce($users, function (array $carry, IUser $user) use ($restrictGroups) {
294
-						// is sharing restricted to groups only?
295
-						if ($restrictGroups !== false) {
296
-							$userGroups = $this->groupManager->getUserGroupIds($user);
297
-							if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
298
-								return $carry;
299
-							}
300
-						}
301
-
302
-						$carry[] = $this->principalPrefix . '/' . $user->getUID();
303
-						return $carry;
304
-					}, []);
305
-					break;
306
-
307
-				case '{DAV:}displayname':
308
-					$users = $this->userManager->searchDisplayName($value);
309
-
310
-					if (!$allowEnumeration) {
311
-						$users = \array_filter($users, static function (IUser $user) use ($value) {
312
-							return $user->getDisplayName() === $value;
313
-						});
314
-					}
315
-
316
-					if ($limitEnumeration) {
317
-						$users = \array_filter($users, function (IUser $user) use ($currentUserGroups, $value) {
318
-							return !empty(array_intersect(
319
-									$this->groupManager->getUserGroupIds($user),
320
-									$currentUserGroups
321
-								)) || $user->getDisplayName() === $value;
322
-						});
323
-					}
324
-
325
-					$results[] = array_reduce($users, function (array $carry, IUser $user) use ($restrictGroups) {
326
-						// is sharing restricted to groups only?
327
-						if ($restrictGroups !== false) {
328
-							$userGroups = $this->groupManager->getUserGroupIds($user);
329
-							if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
330
-								return $carry;
331
-							}
332
-						}
333
-
334
-						$carry[] = $this->principalPrefix . '/' . $user->getUID();
335
-						return $carry;
336
-					}, []);
337
-					break;
338
-
339
-				case '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set':
340
-					// If you add support for more search properties that qualify as a user-address,
341
-					// please also add them to the array below
342
-					$results[] = $this->searchUserPrincipals([
343
-						// In theory this should also search for principal:principals/users/...
344
-						// but that's used internally only anyway and i don't know of any client querying that
345
-						'{http://sabredav.org/ns}email-address' => $value,
346
-					], 'anyof');
347
-					break;
348
-
349
-				default:
350
-					$results[] = [];
351
-					break;
352
-			}
353
-		}
354
-
355
-		// results is an array of arrays, so this is not the first search result
356
-		// but the results of the first searchProperty
357
-		if (count($results) === 1) {
358
-			return $results[0];
359
-		}
360
-
361
-		switch ($test) {
362
-			case 'anyof':
363
-				return array_values(array_unique(array_merge(...$results)));
364
-
365
-			case 'allof':
366
-			default:
367
-				return array_values(array_intersect(...$results));
368
-		}
369
-	}
370
-
371
-	/**
372
-	 * @param string $prefixPath
373
-	 * @param array $searchProperties
374
-	 * @param string $test
375
-	 * @return array
376
-	 */
377
-	public function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
378
-		if (count($searchProperties) === 0) {
379
-			return [];
380
-		}
381
-
382
-		switch ($prefixPath) {
383
-			case 'principals/users':
384
-				return $this->searchUserPrincipals($searchProperties, $test);
385
-
386
-			default:
387
-				return [];
388
-		}
389
-	}
390
-
391
-	/**
392
-	 * @param string $uri
393
-	 * @param string $principalPrefix
394
-	 * @return string
395
-	 */
396
-	public function findByUri($uri, $principalPrefix) {
397
-		// If sharing is disabled, return the empty array
398
-		$shareAPIEnabled = $this->shareManager->shareApiEnabled();
399
-		if (!$shareAPIEnabled) {
400
-			return null;
401
-		}
402
-
403
-		// If sharing is restricted to group members only,
404
-		// return only members that have groups in common
405
-		$restrictGroups = false;
406
-		if ($this->shareManager->shareWithGroupMembersOnly()) {
407
-			$user = $this->userSession->getUser();
408
-			if (!$user) {
409
-				return null;
410
-			}
411
-
412
-			$restrictGroups = $this->groupManager->getUserGroupIds($user);
413
-		}
414
-
415
-		if (strpos($uri, 'mailto:') === 0) {
416
-			if ($principalPrefix === 'principals/users') {
417
-				$users = $this->userManager->getByEmail(substr($uri, 7));
418
-				if (count($users) !== 1) {
419
-					return null;
420
-				}
421
-				$user = $users[0];
422
-
423
-				if ($restrictGroups !== false) {
424
-					$userGroups = $this->groupManager->getUserGroupIds($user);
425
-					if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
426
-						return null;
427
-					}
428
-				}
429
-
430
-				return $this->principalPrefix . '/' . $user->getUID();
431
-			}
432
-		}
433
-		if (substr($uri, 0, 10) === 'principal:') {
434
-			$principal = substr($uri, 10);
435
-			$principal = $this->getPrincipalByPath($principal);
436
-			if ($principal !== null) {
437
-				return $principal['uri'];
438
-			}
439
-		}
440
-
441
-		return null;
442
-	}
443
-
444
-	/**
445
-	 * @param IUser $user
446
-	 * @return array
447
-	 */
448
-	protected function userToPrincipal($user) {
449
-		$userId = $user->getUID();
450
-		$displayName = $user->getDisplayName();
451
-		$principal = [
452
-			'uri' => $this->principalPrefix . '/' . $userId,
453
-			'{DAV:}displayname' => is_null($displayName) ? $userId : $displayName,
454
-			'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
455
-		];
456
-
457
-		$email = $user->getEMailAddress();
458
-		if (!empty($email)) {
459
-			$principal['{http://sabredav.org/ns}email-address'] = $email;
460
-		}
461
-
462
-		return $principal;
463
-	}
464
-
465
-	public function getPrincipalPrefix() {
466
-		return $this->principalPrefix;
467
-	}
468
-
469
-	/**
470
-	 * @param string $circleUniqueId
471
-	 * @return array|null
472
-	 */
473
-	protected function circleToPrincipal($circleUniqueId) {
474
-		if (!$this->appManager->isEnabledForUser('circles') || !class_exists('\OCA\Circles\Api\v1\Circles')) {
475
-			return null;
476
-		}
477
-
478
-		try {
479
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($circleUniqueId, true);
480
-		} catch (QueryException $ex) {
481
-			return null;
482
-		} catch (CircleDoesNotExistException $ex) {
483
-			return null;
484
-		}
485
-
486
-		if (!$circle) {
487
-			return null;
488
-		}
489
-
490
-		$principal = [
491
-			'uri' => 'principals/circles/' . $circleUniqueId,
492
-			'{DAV:}displayname' => $circle->getName(),
493
-		];
494
-
495
-		return $principal;
496
-	}
497
-
498
-	/**
499
-	 * Returns the list of circles a principal is a member of
500
-	 *
501
-	 * @param string $principal
502
-	 * @return array
503
-	 * @throws Exception
504
-	 * @throws \OCP\AppFramework\QueryException
505
-	 * @suppress PhanUndeclaredClassMethod
506
-	 */
507
-	public function getCircleMembership($principal):array {
508
-		if (!$this->appManager->isEnabledForUser('circles') || !class_exists('\OCA\Circles\Api\v1\Circles')) {
509
-			return [];
510
-		}
511
-
512
-		list($prefix, $name) = \Sabre\Uri\split($principal);
513
-		if ($this->hasCircles && $prefix === $this->principalPrefix) {
514
-			$user = $this->userManager->get($name);
515
-			if (!$user) {
516
-				throw new Exception('Principal not found');
517
-			}
518
-
519
-			$circles = \OCA\Circles\Api\v1\Circles::joinedCircles($name, true);
520
-
521
-			$circles = array_map(function ($circle) {
522
-				/** @var \OCA\Circles\Model\Circle $circle */
523
-				return 'principals/circles/' . urlencode($circle->getUniqueId());
524
-			}, $circles);
525
-
526
-			return $circles;
527
-		}
528
-
529
-		return [];
530
-	}
54
+    /** @var IUserManager */
55
+    private $userManager;
56
+
57
+    /** @var IGroupManager */
58
+    private $groupManager;
59
+
60
+    /** @var IShareManager */
61
+    private $shareManager;
62
+
63
+    /** @var IUserSession */
64
+    private $userSession;
65
+
66
+    /** @var IAppManager */
67
+    private $appManager;
68
+
69
+    /** @var string */
70
+    private $principalPrefix;
71
+
72
+    /** @var bool */
73
+    private $hasGroups;
74
+
75
+    /** @var bool */
76
+    private $hasCircles;
77
+
78
+    /** @var ProxyMapper */
79
+    private $proxyMapper;
80
+
81
+    /** @var IConfig */
82
+    private $config;
83
+
84
+    /**
85
+     * Principal constructor.
86
+     *
87
+     * @param IUserManager $userManager
88
+     * @param IGroupManager $groupManager
89
+     * @param IShareManager $shareManager
90
+     * @param IUserSession $userSession
91
+     * @param IAppManager $appManager
92
+     * @param ProxyMapper $proxyMapper
93
+     * @param IConfig $config
94
+     * @param string $principalPrefix
95
+     */
96
+    public function __construct(IUserManager $userManager,
97
+                                IGroupManager $groupManager,
98
+                                IShareManager $shareManager,
99
+                                IUserSession $userSession,
100
+                                IAppManager $appManager,
101
+                                ProxyMapper $proxyMapper,
102
+                                IConfig $config,
103
+                                string $principalPrefix = 'principals/users/') {
104
+        $this->userManager = $userManager;
105
+        $this->groupManager = $groupManager;
106
+        $this->shareManager = $shareManager;
107
+        $this->userSession = $userSession;
108
+        $this->appManager = $appManager;
109
+        $this->principalPrefix = trim($principalPrefix, '/');
110
+        $this->hasGroups = $this->hasCircles = ($principalPrefix === 'principals/users/');
111
+        $this->proxyMapper = $proxyMapper;
112
+        $this->config = $config;
113
+    }
114
+
115
+    use PrincipalProxyTrait {
116
+        getGroupMembership as protected traitGetGroupMembership;
117
+    }
118
+
119
+    /**
120
+     * Returns a list of principals based on a prefix.
121
+     *
122
+     * This prefix will often contain something like 'principals'. You are only
123
+     * expected to return principals that are in this base path.
124
+     *
125
+     * You are expected to return at least a 'uri' for every user, you can
126
+     * return any additional properties if you wish so. Common properties are:
127
+     *   {DAV:}displayname
128
+     *
129
+     * @param string $prefixPath
130
+     * @return string[]
131
+     */
132
+    public function getPrincipalsByPrefix($prefixPath) {
133
+        $principals = [];
134
+
135
+        if ($prefixPath === $this->principalPrefix) {
136
+            foreach ($this->userManager->search('') as $user) {
137
+                $principals[] = $this->userToPrincipal($user);
138
+            }
139
+        }
140
+
141
+        return $principals;
142
+    }
143
+
144
+    /**
145
+     * Returns a specific principal, specified by it's path.
146
+     * The returned structure should be the exact same as from
147
+     * getPrincipalsByPrefix.
148
+     *
149
+     * @param string $path
150
+     * @return array
151
+     */
152
+    public function getPrincipalByPath($path) {
153
+        list($prefix, $name) = \Sabre\Uri\split($path);
154
+
155
+        if ($name === 'calendar-proxy-write' || $name === 'calendar-proxy-read') {
156
+            list($prefix2, $name2) = \Sabre\Uri\split($prefix);
157
+
158
+            if ($prefix2 === $this->principalPrefix) {
159
+                $user = $this->userManager->get($name2);
160
+
161
+                if ($user !== null) {
162
+                    return [
163
+                        'uri' => 'principals/users/' . $user->getUID() . '/' . $name,
164
+                    ];
165
+                }
166
+                return null;
167
+            }
168
+        }
169
+
170
+        if ($prefix === $this->principalPrefix) {
171
+            // Depending on where it is called, it may happen that this function
172
+            // is called either with a urlencoded version of the name or with a non-urlencoded one.
173
+            // The urldecode function replaces %## and +, both of which are forbidden in usernames.
174
+            // Hence there can be no ambiguity here and it is safe to call urldecode on all usernames
175
+            $user = $this->userManager->get(urldecode($name));
176
+
177
+            if ($user !== null) {
178
+                return $this->userToPrincipal($user);
179
+            }
180
+        } elseif ($prefix === 'principals/circles') {
181
+            if ($this->userSession->getUser() !== null) {
182
+                return $this->circleToPrincipal($name);
183
+            }
184
+        }
185
+        return null;
186
+    }
187
+
188
+    /**
189
+     * Returns the list of groups a principal is a member of
190
+     *
191
+     * @param string $principal
192
+     * @param bool $needGroups
193
+     * @return array
194
+     * @throws Exception
195
+     */
196
+    public function getGroupMembership($principal, $needGroups = false) {
197
+        list($prefix, $name) = \Sabre\Uri\split($principal);
198
+
199
+        if ($prefix !== $this->principalPrefix) {
200
+            return [];
201
+        }
202
+
203
+        $user = $this->userManager->get($name);
204
+        if (!$user) {
205
+            throw new Exception('Principal not found');
206
+        }
207
+
208
+        $groups = [];
209
+
210
+        if ($this->hasGroups || $needGroups) {
211
+            $userGroups = $this->groupManager->getUserGroups($user);
212
+            foreach ($userGroups as $userGroup) {
213
+                $groups[] = 'principals/groups/' . urlencode($userGroup->getGID());
214
+            }
215
+        }
216
+
217
+        $groups = array_unique(array_merge(
218
+            $groups,
219
+            $this->traitGetGroupMembership($principal, $needGroups)
220
+        ));
221
+
222
+        return $groups;
223
+    }
224
+
225
+    /**
226
+     * @param string $path
227
+     * @param PropPatch $propPatch
228
+     * @return int
229
+     */
230
+    public function updatePrincipal($path, PropPatch $propPatch) {
231
+        return 0;
232
+    }
233
+
234
+    /**
235
+     * Search user principals
236
+     *
237
+     * @param array $searchProperties
238
+     * @param string $test
239
+     * @return array
240
+     */
241
+    protected function searchUserPrincipals(array $searchProperties, $test = 'allof') {
242
+        $results = [];
243
+
244
+        // If sharing is disabled, return the empty array
245
+        $shareAPIEnabled = $this->shareManager->shareApiEnabled();
246
+        if (!$shareAPIEnabled) {
247
+            return [];
248
+        }
249
+
250
+        $allowEnumeration = $this->shareManager->allowEnumeration();
251
+        $limitEnumeration = $this->shareManager->limitEnumerationToGroups();
252
+
253
+        // If sharing is restricted to group members only,
254
+        // return only members that have groups in common
255
+        $restrictGroups = false;
256
+        if ($this->shareManager->shareWithGroupMembersOnly()) {
257
+            $user = $this->userSession->getUser();
258
+            if (!$user) {
259
+                return [];
260
+            }
261
+
262
+            $restrictGroups = $this->groupManager->getUserGroupIds($user);
263
+        }
264
+
265
+        $currentUserGroups = [];
266
+        if ($limitEnumeration) {
267
+            $currentUser = $this->userSession->getUser();
268
+            if ($currentUser) {
269
+                $currentUserGroups = $this->groupManager->getUserGroupIds($currentUser);
270
+            }
271
+        }
272
+
273
+        foreach ($searchProperties as $prop => $value) {
274
+            switch ($prop) {
275
+                case '{http://sabredav.org/ns}email-address':
276
+                    $users = $this->userManager->getByEmail($value);
277
+
278
+                    if (!$allowEnumeration) {
279
+                        $users = \array_filter($users, static function (IUser $user) use ($value) {
280
+                            return $user->getEMailAddress() === $value;
281
+                        });
282
+                    }
283
+
284
+                    if ($limitEnumeration) {
285
+                        $users = \array_filter($users, function (IUser $user) use ($currentUserGroups, $value) {
286
+                            return !empty(array_intersect(
287
+                                    $this->groupManager->getUserGroupIds($user),
288
+                                    $currentUserGroups
289
+                                )) || $user->getEMailAddress() === $value;
290
+                        });
291
+                    }
292
+
293
+                    $results[] = array_reduce($users, function (array $carry, IUser $user) use ($restrictGroups) {
294
+                        // is sharing restricted to groups only?
295
+                        if ($restrictGroups !== false) {
296
+                            $userGroups = $this->groupManager->getUserGroupIds($user);
297
+                            if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
298
+                                return $carry;
299
+                            }
300
+                        }
301
+
302
+                        $carry[] = $this->principalPrefix . '/' . $user->getUID();
303
+                        return $carry;
304
+                    }, []);
305
+                    break;
306
+
307
+                case '{DAV:}displayname':
308
+                    $users = $this->userManager->searchDisplayName($value);
309
+
310
+                    if (!$allowEnumeration) {
311
+                        $users = \array_filter($users, static function (IUser $user) use ($value) {
312
+                            return $user->getDisplayName() === $value;
313
+                        });
314
+                    }
315
+
316
+                    if ($limitEnumeration) {
317
+                        $users = \array_filter($users, function (IUser $user) use ($currentUserGroups, $value) {
318
+                            return !empty(array_intersect(
319
+                                    $this->groupManager->getUserGroupIds($user),
320
+                                    $currentUserGroups
321
+                                )) || $user->getDisplayName() === $value;
322
+                        });
323
+                    }
324
+
325
+                    $results[] = array_reduce($users, function (array $carry, IUser $user) use ($restrictGroups) {
326
+                        // is sharing restricted to groups only?
327
+                        if ($restrictGroups !== false) {
328
+                            $userGroups = $this->groupManager->getUserGroupIds($user);
329
+                            if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
330
+                                return $carry;
331
+                            }
332
+                        }
333
+
334
+                        $carry[] = $this->principalPrefix . '/' . $user->getUID();
335
+                        return $carry;
336
+                    }, []);
337
+                    break;
338
+
339
+                case '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set':
340
+                    // If you add support for more search properties that qualify as a user-address,
341
+                    // please also add them to the array below
342
+                    $results[] = $this->searchUserPrincipals([
343
+                        // In theory this should also search for principal:principals/users/...
344
+                        // but that's used internally only anyway and i don't know of any client querying that
345
+                        '{http://sabredav.org/ns}email-address' => $value,
346
+                    ], 'anyof');
347
+                    break;
348
+
349
+                default:
350
+                    $results[] = [];
351
+                    break;
352
+            }
353
+        }
354
+
355
+        // results is an array of arrays, so this is not the first search result
356
+        // but the results of the first searchProperty
357
+        if (count($results) === 1) {
358
+            return $results[0];
359
+        }
360
+
361
+        switch ($test) {
362
+            case 'anyof':
363
+                return array_values(array_unique(array_merge(...$results)));
364
+
365
+            case 'allof':
366
+            default:
367
+                return array_values(array_intersect(...$results));
368
+        }
369
+    }
370
+
371
+    /**
372
+     * @param string $prefixPath
373
+     * @param array $searchProperties
374
+     * @param string $test
375
+     * @return array
376
+     */
377
+    public function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
378
+        if (count($searchProperties) === 0) {
379
+            return [];
380
+        }
381
+
382
+        switch ($prefixPath) {
383
+            case 'principals/users':
384
+                return $this->searchUserPrincipals($searchProperties, $test);
385
+
386
+            default:
387
+                return [];
388
+        }
389
+    }
390
+
391
+    /**
392
+     * @param string $uri
393
+     * @param string $principalPrefix
394
+     * @return string
395
+     */
396
+    public function findByUri($uri, $principalPrefix) {
397
+        // If sharing is disabled, return the empty array
398
+        $shareAPIEnabled = $this->shareManager->shareApiEnabled();
399
+        if (!$shareAPIEnabled) {
400
+            return null;
401
+        }
402
+
403
+        // If sharing is restricted to group members only,
404
+        // return only members that have groups in common
405
+        $restrictGroups = false;
406
+        if ($this->shareManager->shareWithGroupMembersOnly()) {
407
+            $user = $this->userSession->getUser();
408
+            if (!$user) {
409
+                return null;
410
+            }
411
+
412
+            $restrictGroups = $this->groupManager->getUserGroupIds($user);
413
+        }
414
+
415
+        if (strpos($uri, 'mailto:') === 0) {
416
+            if ($principalPrefix === 'principals/users') {
417
+                $users = $this->userManager->getByEmail(substr($uri, 7));
418
+                if (count($users) !== 1) {
419
+                    return null;
420
+                }
421
+                $user = $users[0];
422
+
423
+                if ($restrictGroups !== false) {
424
+                    $userGroups = $this->groupManager->getUserGroupIds($user);
425
+                    if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
426
+                        return null;
427
+                    }
428
+                }
429
+
430
+                return $this->principalPrefix . '/' . $user->getUID();
431
+            }
432
+        }
433
+        if (substr($uri, 0, 10) === 'principal:') {
434
+            $principal = substr($uri, 10);
435
+            $principal = $this->getPrincipalByPath($principal);
436
+            if ($principal !== null) {
437
+                return $principal['uri'];
438
+            }
439
+        }
440
+
441
+        return null;
442
+    }
443
+
444
+    /**
445
+     * @param IUser $user
446
+     * @return array
447
+     */
448
+    protected function userToPrincipal($user) {
449
+        $userId = $user->getUID();
450
+        $displayName = $user->getDisplayName();
451
+        $principal = [
452
+            'uri' => $this->principalPrefix . '/' . $userId,
453
+            '{DAV:}displayname' => is_null($displayName) ? $userId : $displayName,
454
+            '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
455
+        ];
456
+
457
+        $email = $user->getEMailAddress();
458
+        if (!empty($email)) {
459
+            $principal['{http://sabredav.org/ns}email-address'] = $email;
460
+        }
461
+
462
+        return $principal;
463
+    }
464
+
465
+    public function getPrincipalPrefix() {
466
+        return $this->principalPrefix;
467
+    }
468
+
469
+    /**
470
+     * @param string $circleUniqueId
471
+     * @return array|null
472
+     */
473
+    protected function circleToPrincipal($circleUniqueId) {
474
+        if (!$this->appManager->isEnabledForUser('circles') || !class_exists('\OCA\Circles\Api\v1\Circles')) {
475
+            return null;
476
+        }
477
+
478
+        try {
479
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($circleUniqueId, true);
480
+        } catch (QueryException $ex) {
481
+            return null;
482
+        } catch (CircleDoesNotExistException $ex) {
483
+            return null;
484
+        }
485
+
486
+        if (!$circle) {
487
+            return null;
488
+        }
489
+
490
+        $principal = [
491
+            'uri' => 'principals/circles/' . $circleUniqueId,
492
+            '{DAV:}displayname' => $circle->getName(),
493
+        ];
494
+
495
+        return $principal;
496
+    }
497
+
498
+    /**
499
+     * Returns the list of circles a principal is a member of
500
+     *
501
+     * @param string $principal
502
+     * @return array
503
+     * @throws Exception
504
+     * @throws \OCP\AppFramework\QueryException
505
+     * @suppress PhanUndeclaredClassMethod
506
+     */
507
+    public function getCircleMembership($principal):array {
508
+        if (!$this->appManager->isEnabledForUser('circles') || !class_exists('\OCA\Circles\Api\v1\Circles')) {
509
+            return [];
510
+        }
511
+
512
+        list($prefix, $name) = \Sabre\Uri\split($principal);
513
+        if ($this->hasCircles && $prefix === $this->principalPrefix) {
514
+            $user = $this->userManager->get($name);
515
+            if (!$user) {
516
+                throw new Exception('Principal not found');
517
+            }
518
+
519
+            $circles = \OCA\Circles\Api\v1\Circles::joinedCircles($name, true);
520
+
521
+            $circles = array_map(function ($circle) {
522
+                /** @var \OCA\Circles\Model\Circle $circle */
523
+                return 'principals/circles/' . urlencode($circle->getUniqueId());
524
+            }, $circles);
525
+
526
+            return $circles;
527
+        }
528
+
529
+        return [];
530
+    }
531 531
 }
Please login to merge, or discard this patch.