Passed
Push — master ( f5c0ea...973ccd )
by Morris
11:28 queued 10s
created
apps/dav/lib/CalDAV/ResourceBooking/AbstractPrincipalBackend.php 1 patch
Indentation   +342 added lines, -342 removed lines patch added patch discarded remove patch
@@ -32,346 +32,346 @@
 block discarded – undo
32 32
 
33 33
 abstract class AbstractPrincipalBackend implements BackendInterface {
34 34
 
35
-	/** @var IDBConnection */
36
-	private $db;
37
-
38
-	/** @var IUserSession */
39
-	private $userSession;
40
-
41
-	/** @var IGroupManager */
42
-	private $groupManager;
43
-
44
-	/** @var ILogger */
45
-	private $logger;
46
-
47
-	/** @var string */
48
-	private $principalPrefix;
49
-
50
-	/** @var string */
51
-	private $dbTableName;
52
-
53
-	/** @var string */
54
-	private $cuType;
55
-
56
-	/**
57
-	 * @param IDBConnection $dbConnection
58
-	 * @param IUserSession $userSession
59
-	 * @param IGroupManager $groupManager
60
-	 * @param ILogger $logger
61
-	 * @param string $principalPrefix
62
-	 * @param string $dbPrefix
63
-	 * @param string $cuType
64
-	 */
65
-	public function __construct(IDBConnection $dbConnection,
66
-								IUserSession $userSession,
67
-								IGroupManager $groupManager,
68
-								ILogger $logger,
69
-								string $principalPrefix,
70
-								string $dbPrefix,
71
-								string $cuType) {
72
-		$this->db = $dbConnection;
73
-		$this->userSession = $userSession;
74
-		$this->groupManager = $groupManager;
75
-		$this->logger = $logger;
76
-		$this->principalPrefix = $principalPrefix;
77
-		$this->dbTableName = 'calendar_' . $dbPrefix;
78
-		$this->cuType = $cuType;
79
-	}
80
-
81
-	/**
82
-	 * Returns a list of principals based on a prefix.
83
-	 *
84
-	 * This prefix will often contain something like 'principals'. You are only
85
-	 * expected to return principals that are in this base path.
86
-	 *
87
-	 * You are expected to return at least a 'uri' for every user, you can
88
-	 * return any additional properties if you wish so. Common properties are:
89
-	 *   {DAV:}displayname
90
-	 *
91
-	 * @param string $prefixPath
92
-	 * @return string[]
93
-	 */
94
-	public function getPrincipalsByPrefix($prefixPath) {
95
-		$principals = [];
96
-
97
-		if ($prefixPath === $this->principalPrefix) {
98
-			$query = $this->db->getQueryBuilder();
99
-			$query->select(['id', 'backend_id', 'resource_id', 'email', 'displayname'])
100
-				->from($this->dbTableName);
101
-			$stmt = $query->execute();
102
-
103
-			while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
104
-				$principals[] = $this->rowToPrincipal($row);
105
-			}
106
-
107
-			$stmt->closeCursor();
108
-		}
109
-
110
-		return $principals;
111
-	}
112
-
113
-	/**
114
-	 * Returns a specific principal, specified by it's path.
115
-	 * The returned structure should be the exact same as from
116
-	 * getPrincipalsByPrefix.
117
-	 *
118
-	 * @param string $path
119
-	 * @return array
120
-	 */
121
-	public function getPrincipalByPath($path) {
122
-		if (strpos($path, $this->principalPrefix) !== 0) {
123
-			return null;
124
-		}
125
-		list(, $name) = \Sabre\Uri\split($path);
126
-
127
-		list($backendId, $resourceId) = explode('-',  $name, 2);
128
-
129
-		$query = $this->db->getQueryBuilder();
130
-		$query->select(['id', 'backend_id', 'resource_id', 'email', 'displayname'])
131
-			->from($this->dbTableName)
132
-			->where($query->expr()->eq('backend_id', $query->createNamedParameter($backendId)))
133
-			->andWhere($query->expr()->eq('resource_id', $query->createNamedParameter($resourceId)));
134
-		$stmt = $query->execute();
135
-		$row = $stmt->fetch(\PDO::FETCH_ASSOC);
136
-
137
-		if(!$row) {
138
-			return null;
139
-		}
140
-
141
-		return $this->rowToPrincipal($row);
142
-	}
143
-
144
-	/**
145
-	 * Returns the list of members for a group-principal
146
-	 *
147
-	 * @param string $principal
148
-	 * @return string[]
149
-	 */
150
-	public function getGroupMemberSet($principal) {
151
-		return [];
152
-	}
153
-
154
-	/**
155
-	 * Returns the list of groups a principal is a member of
156
-	 *
157
-	 * @param string $principal
158
-	 * @return array
159
-	 */
160
-	public function getGroupMembership($principal) {
161
-		return [];
162
-	}
163
-
164
-	/**
165
-	 * Updates the list of group members for a group principal.
166
-	 *
167
-	 * The principals should be passed as a list of uri's.
168
-	 *
169
-	 * @param string $principal
170
-	 * @param string[] $members
171
-	 * @throws Exception
172
-	 */
173
-	public function setGroupMemberSet($principal, array $members) {
174
-		throw new Exception('Setting members of the group is not supported yet');
175
-	}
176
-
177
-	/**
178
-	 * @param string $path
179
-	 * @param PropPatch $propPatch
180
-	 * @return int
181
-	 */
182
-	function updatePrincipal($path, PropPatch $propPatch) {
183
-		return 0;
184
-	}
185
-
186
-	/**
187
-	 * @param string $prefixPath
188
-	 * @param array $searchProperties
189
-	 * @param string $test
190
-	 * @return array
191
-	 */
192
-	function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
193
-		$results = [];
194
-		if (\count($searchProperties) === 0) {
195
-			return [];
196
-		}
197
-		if ($prefixPath !== $this->principalPrefix) {
198
-			return [];
199
-		}
200
-
201
-		$user = $this->userSession->getUser();
202
-		if (!$user) {
203
-			return [];
204
-		}
205
-		$usersGroups = $this->groupManager->getUserGroupIds($user);
206
-
207
-		foreach ($searchProperties as $prop => $value) {
208
-			switch ($prop) {
209
-				case '{http://sabredav.org/ns}email-address':
210
-					$query = $this->db->getQueryBuilder();
211
-					$query->select(['id', 'backend_id', 'resource_id', 'email', 'displayname', 'group_restrictions'])
212
-						->from($this->dbTableName)
213
-						->where($query->expr()->iLike('email', $query->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%')));
214
-
215
-					$stmt = $query->execute();
216
-					$principals = [];
217
-					while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
218
-						if (!$this->isAllowedToAccessResource($row, $usersGroups)) {
219
-							continue;
220
-						}
221
-						$principals[] = $this->rowToPrincipal($row)['uri'];
222
-					}
223
-					$results[] = $principals;
224
-
225
-					$stmt->closeCursor();
226
-					break;
227
-
228
-				case '{DAV:}displayname':
229
-					$query = $this->db->getQueryBuilder();
230
-					$query->select(['id', 'backend_id', 'resource_id', 'email', 'displayname', 'group_restrictions'])
231
-						->from($this->dbTableName)
232
-						->where($query->expr()->iLike('displayname', $query->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%')));
233
-
234
-					$stmt = $query->execute();
235
-					$principals = [];
236
-					while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
237
-						if (!$this->isAllowedToAccessResource($row, $usersGroups)) {
238
-							continue;
239
-						}
240
-						$principals[] = $this->rowToPrincipal($row)['uri'];
241
-					}
242
-					$results[] = $principals;
243
-
244
-					$stmt->closeCursor();
245
-					break;
246
-
247
-				case '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set':
248
-					// If you add support for more search properties that qualify as a user-address,
249
-					// please also add them to the array below
250
-					$results[] = $this->searchPrincipals($this->principalPrefix, [
251
-						'{http://sabredav.org/ns}email-address' => $value,
252
-					], 'anyof');
253
-					break;
254
-
255
-				default:
256
-					$results[] = [];
257
-					break;
258
-			}
259
-		}
260
-
261
-		// results is an array of arrays, so this is not the first search result
262
-		// but the results of the first searchProperty
263
-		if (count($results) === 1) {
264
-			return $results[0];
265
-		}
266
-
267
-		switch ($test) {
268
-			case 'anyof':
269
-				return array_values(array_unique(array_merge(...$results)));
270
-
271
-			case 'allof':
272
-			default:
273
-				return array_values(array_intersect(...$results));
274
-		}
275
-	}
276
-
277
-	/**
278
-	 * @param string $uri
279
-	 * @param string $principalPrefix
280
-	 * @return null|string
281
-	 */
282
-	function findByUri($uri, $principalPrefix) {
283
-		$user = $this->userSession->getUser();
284
-		if (!$user) {
285
-			return null;
286
-		}
287
-		$usersGroups = $this->groupManager->getUserGroupIds($user);
288
-
289
-		if (strpos($uri, 'mailto:') === 0) {
290
-			$email = substr($uri, 7);
291
-			$query = $this->db->getQueryBuilder();
292
-			$query->select(['id', 'backend_id', 'resource_id', 'email', 'displayname', 'group_restrictions'])
293
-				->from($this->dbTableName)
294
-				->where($query->expr()->eq('email', $query->createNamedParameter($email)));
295
-
296
-			$stmt = $query->execute();
297
-			$row = $stmt->fetch(\PDO::FETCH_ASSOC);
298
-
299
-			if(!$row) {
300
-				return null;
301
-			}
302
-			if (!$this->isAllowedToAccessResource($row, $usersGroups)) {
303
-				return null;
304
-			}
305
-
306
-			return $this->rowToPrincipal($row)['uri'];
307
-		}
308
-
309
-		if (strpos($uri, 'principal:') === 0) {
310
-			$path = substr($uri, 10);
311
-			if (strpos($path, $this->principalPrefix) !== 0) {
312
-				return null;
313
-			}
314
-
315
-			list(, $name) = \Sabre\Uri\split($path);
316
-			list($backendId, $resourceId) = explode('-',  $name, 2);
317
-
318
-			$query = $this->db->getQueryBuilder();
319
-			$query->select(['id', 'backend_id', 'resource_id', 'email', 'displayname', 'group_restrictions'])
320
-				->from($this->dbTableName)
321
-				->where($query->expr()->eq('backend_id', $query->createNamedParameter($backendId)))
322
-				->andWhere($query->expr()->eq('resource_id', $query->createNamedParameter($resourceId)));
323
-			$stmt = $query->execute();
324
-			$row = $stmt->fetch(\PDO::FETCH_ASSOC);
325
-
326
-			if(!$row) {
327
-				return null;
328
-			}
329
-			if (!$this->isAllowedToAccessResource($row, $usersGroups)) {
330
-				return null;
331
-			}
332
-
333
-			return $this->rowToPrincipal($row)['uri'];
334
-		}
335
-
336
-		return null;
337
-	}
338
-
339
-	/**
340
-	 * convert database row to principal
341
-	 */
342
-	private function rowToPrincipal($row) {
343
-		return [
344
-			'uri' => $this->principalPrefix . '/' . $row['backend_id'] . '-' . $row['resource_id'],
345
-			'{DAV:}displayname' => $row['displayname'],
346
-			'{http://sabredav.org/ns}email-address' => $row['email'],
347
-			'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => $this->cuType,
348
-		];
349
-	}
350
-
351
-	/**
352
-	 * @param $row
353
-	 * @param $userGroups
354
-	 * @return bool
355
-	 */
356
-	private function isAllowedToAccessResource($row, $userGroups) {
357
-		if (!isset($row['group_restrictions']) ||
358
-			$row['group_restrictions'] === null ||
359
-			$row['group_restrictions'] === '') {
360
-			return true;
361
-		}
362
-
363
-		// group restrictions contains something, but not parsable, deny access and log warning
364
-		$json = json_decode($row['group_restrictions']);
365
-		if (!\is_array($json)) {
366
-			$this->logger->info('group_restrictions field could not be parsed for ' . $this->dbTableName . '::' . $row['id'] . ', denying access to resource');
367
-			return false;
368
-		}
369
-
370
-		// empty array => no group restrictions
371
-		if (empty($json)) {
372
-			return true;
373
-		}
374
-
375
-		return !empty(array_intersect($json, $userGroups));
376
-	}
35
+    /** @var IDBConnection */
36
+    private $db;
37
+
38
+    /** @var IUserSession */
39
+    private $userSession;
40
+
41
+    /** @var IGroupManager */
42
+    private $groupManager;
43
+
44
+    /** @var ILogger */
45
+    private $logger;
46
+
47
+    /** @var string */
48
+    private $principalPrefix;
49
+
50
+    /** @var string */
51
+    private $dbTableName;
52
+
53
+    /** @var string */
54
+    private $cuType;
55
+
56
+    /**
57
+     * @param IDBConnection $dbConnection
58
+     * @param IUserSession $userSession
59
+     * @param IGroupManager $groupManager
60
+     * @param ILogger $logger
61
+     * @param string $principalPrefix
62
+     * @param string $dbPrefix
63
+     * @param string $cuType
64
+     */
65
+    public function __construct(IDBConnection $dbConnection,
66
+                                IUserSession $userSession,
67
+                                IGroupManager $groupManager,
68
+                                ILogger $logger,
69
+                                string $principalPrefix,
70
+                                string $dbPrefix,
71
+                                string $cuType) {
72
+        $this->db = $dbConnection;
73
+        $this->userSession = $userSession;
74
+        $this->groupManager = $groupManager;
75
+        $this->logger = $logger;
76
+        $this->principalPrefix = $principalPrefix;
77
+        $this->dbTableName = 'calendar_' . $dbPrefix;
78
+        $this->cuType = $cuType;
79
+    }
80
+
81
+    /**
82
+     * Returns a list of principals based on a prefix.
83
+     *
84
+     * This prefix will often contain something like 'principals'. You are only
85
+     * expected to return principals that are in this base path.
86
+     *
87
+     * You are expected to return at least a 'uri' for every user, you can
88
+     * return any additional properties if you wish so. Common properties are:
89
+     *   {DAV:}displayname
90
+     *
91
+     * @param string $prefixPath
92
+     * @return string[]
93
+     */
94
+    public function getPrincipalsByPrefix($prefixPath) {
95
+        $principals = [];
96
+
97
+        if ($prefixPath === $this->principalPrefix) {
98
+            $query = $this->db->getQueryBuilder();
99
+            $query->select(['id', 'backend_id', 'resource_id', 'email', 'displayname'])
100
+                ->from($this->dbTableName);
101
+            $stmt = $query->execute();
102
+
103
+            while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
104
+                $principals[] = $this->rowToPrincipal($row);
105
+            }
106
+
107
+            $stmt->closeCursor();
108
+        }
109
+
110
+        return $principals;
111
+    }
112
+
113
+    /**
114
+     * Returns a specific principal, specified by it's path.
115
+     * The returned structure should be the exact same as from
116
+     * getPrincipalsByPrefix.
117
+     *
118
+     * @param string $path
119
+     * @return array
120
+     */
121
+    public function getPrincipalByPath($path) {
122
+        if (strpos($path, $this->principalPrefix) !== 0) {
123
+            return null;
124
+        }
125
+        list(, $name) = \Sabre\Uri\split($path);
126
+
127
+        list($backendId, $resourceId) = explode('-',  $name, 2);
128
+
129
+        $query = $this->db->getQueryBuilder();
130
+        $query->select(['id', 'backend_id', 'resource_id', 'email', 'displayname'])
131
+            ->from($this->dbTableName)
132
+            ->where($query->expr()->eq('backend_id', $query->createNamedParameter($backendId)))
133
+            ->andWhere($query->expr()->eq('resource_id', $query->createNamedParameter($resourceId)));
134
+        $stmt = $query->execute();
135
+        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
136
+
137
+        if(!$row) {
138
+            return null;
139
+        }
140
+
141
+        return $this->rowToPrincipal($row);
142
+    }
143
+
144
+    /**
145
+     * Returns the list of members for a group-principal
146
+     *
147
+     * @param string $principal
148
+     * @return string[]
149
+     */
150
+    public function getGroupMemberSet($principal) {
151
+        return [];
152
+    }
153
+
154
+    /**
155
+     * Returns the list of groups a principal is a member of
156
+     *
157
+     * @param string $principal
158
+     * @return array
159
+     */
160
+    public function getGroupMembership($principal) {
161
+        return [];
162
+    }
163
+
164
+    /**
165
+     * Updates the list of group members for a group principal.
166
+     *
167
+     * The principals should be passed as a list of uri's.
168
+     *
169
+     * @param string $principal
170
+     * @param string[] $members
171
+     * @throws Exception
172
+     */
173
+    public function setGroupMemberSet($principal, array $members) {
174
+        throw new Exception('Setting members of the group is not supported yet');
175
+    }
176
+
177
+    /**
178
+     * @param string $path
179
+     * @param PropPatch $propPatch
180
+     * @return int
181
+     */
182
+    function updatePrincipal($path, PropPatch $propPatch) {
183
+        return 0;
184
+    }
185
+
186
+    /**
187
+     * @param string $prefixPath
188
+     * @param array $searchProperties
189
+     * @param string $test
190
+     * @return array
191
+     */
192
+    function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
193
+        $results = [];
194
+        if (\count($searchProperties) === 0) {
195
+            return [];
196
+        }
197
+        if ($prefixPath !== $this->principalPrefix) {
198
+            return [];
199
+        }
200
+
201
+        $user = $this->userSession->getUser();
202
+        if (!$user) {
203
+            return [];
204
+        }
205
+        $usersGroups = $this->groupManager->getUserGroupIds($user);
206
+
207
+        foreach ($searchProperties as $prop => $value) {
208
+            switch ($prop) {
209
+                case '{http://sabredav.org/ns}email-address':
210
+                    $query = $this->db->getQueryBuilder();
211
+                    $query->select(['id', 'backend_id', 'resource_id', 'email', 'displayname', 'group_restrictions'])
212
+                        ->from($this->dbTableName)
213
+                        ->where($query->expr()->iLike('email', $query->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%')));
214
+
215
+                    $stmt = $query->execute();
216
+                    $principals = [];
217
+                    while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
218
+                        if (!$this->isAllowedToAccessResource($row, $usersGroups)) {
219
+                            continue;
220
+                        }
221
+                        $principals[] = $this->rowToPrincipal($row)['uri'];
222
+                    }
223
+                    $results[] = $principals;
224
+
225
+                    $stmt->closeCursor();
226
+                    break;
227
+
228
+                case '{DAV:}displayname':
229
+                    $query = $this->db->getQueryBuilder();
230
+                    $query->select(['id', 'backend_id', 'resource_id', 'email', 'displayname', 'group_restrictions'])
231
+                        ->from($this->dbTableName)
232
+                        ->where($query->expr()->iLike('displayname', $query->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%')));
233
+
234
+                    $stmt = $query->execute();
235
+                    $principals = [];
236
+                    while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
237
+                        if (!$this->isAllowedToAccessResource($row, $usersGroups)) {
238
+                            continue;
239
+                        }
240
+                        $principals[] = $this->rowToPrincipal($row)['uri'];
241
+                    }
242
+                    $results[] = $principals;
243
+
244
+                    $stmt->closeCursor();
245
+                    break;
246
+
247
+                case '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set':
248
+                    // If you add support for more search properties that qualify as a user-address,
249
+                    // please also add them to the array below
250
+                    $results[] = $this->searchPrincipals($this->principalPrefix, [
251
+                        '{http://sabredav.org/ns}email-address' => $value,
252
+                    ], 'anyof');
253
+                    break;
254
+
255
+                default:
256
+                    $results[] = [];
257
+                    break;
258
+            }
259
+        }
260
+
261
+        // results is an array of arrays, so this is not the first search result
262
+        // but the results of the first searchProperty
263
+        if (count($results) === 1) {
264
+            return $results[0];
265
+        }
266
+
267
+        switch ($test) {
268
+            case 'anyof':
269
+                return array_values(array_unique(array_merge(...$results)));
270
+
271
+            case 'allof':
272
+            default:
273
+                return array_values(array_intersect(...$results));
274
+        }
275
+    }
276
+
277
+    /**
278
+     * @param string $uri
279
+     * @param string $principalPrefix
280
+     * @return null|string
281
+     */
282
+    function findByUri($uri, $principalPrefix) {
283
+        $user = $this->userSession->getUser();
284
+        if (!$user) {
285
+            return null;
286
+        }
287
+        $usersGroups = $this->groupManager->getUserGroupIds($user);
288
+
289
+        if (strpos($uri, 'mailto:') === 0) {
290
+            $email = substr($uri, 7);
291
+            $query = $this->db->getQueryBuilder();
292
+            $query->select(['id', 'backend_id', 'resource_id', 'email', 'displayname', 'group_restrictions'])
293
+                ->from($this->dbTableName)
294
+                ->where($query->expr()->eq('email', $query->createNamedParameter($email)));
295
+
296
+            $stmt = $query->execute();
297
+            $row = $stmt->fetch(\PDO::FETCH_ASSOC);
298
+
299
+            if(!$row) {
300
+                return null;
301
+            }
302
+            if (!$this->isAllowedToAccessResource($row, $usersGroups)) {
303
+                return null;
304
+            }
305
+
306
+            return $this->rowToPrincipal($row)['uri'];
307
+        }
308
+
309
+        if (strpos($uri, 'principal:') === 0) {
310
+            $path = substr($uri, 10);
311
+            if (strpos($path, $this->principalPrefix) !== 0) {
312
+                return null;
313
+            }
314
+
315
+            list(, $name) = \Sabre\Uri\split($path);
316
+            list($backendId, $resourceId) = explode('-',  $name, 2);
317
+
318
+            $query = $this->db->getQueryBuilder();
319
+            $query->select(['id', 'backend_id', 'resource_id', 'email', 'displayname', 'group_restrictions'])
320
+                ->from($this->dbTableName)
321
+                ->where($query->expr()->eq('backend_id', $query->createNamedParameter($backendId)))
322
+                ->andWhere($query->expr()->eq('resource_id', $query->createNamedParameter($resourceId)));
323
+            $stmt = $query->execute();
324
+            $row = $stmt->fetch(\PDO::FETCH_ASSOC);
325
+
326
+            if(!$row) {
327
+                return null;
328
+            }
329
+            if (!$this->isAllowedToAccessResource($row, $usersGroups)) {
330
+                return null;
331
+            }
332
+
333
+            return $this->rowToPrincipal($row)['uri'];
334
+        }
335
+
336
+        return null;
337
+    }
338
+
339
+    /**
340
+     * convert database row to principal
341
+     */
342
+    private function rowToPrincipal($row) {
343
+        return [
344
+            'uri' => $this->principalPrefix . '/' . $row['backend_id'] . '-' . $row['resource_id'],
345
+            '{DAV:}displayname' => $row['displayname'],
346
+            '{http://sabredav.org/ns}email-address' => $row['email'],
347
+            '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => $this->cuType,
348
+        ];
349
+    }
350
+
351
+    /**
352
+     * @param $row
353
+     * @param $userGroups
354
+     * @return bool
355
+     */
356
+    private function isAllowedToAccessResource($row, $userGroups) {
357
+        if (!isset($row['group_restrictions']) ||
358
+            $row['group_restrictions'] === null ||
359
+            $row['group_restrictions'] === '') {
360
+            return true;
361
+        }
362
+
363
+        // group restrictions contains something, but not parsable, deny access and log warning
364
+        $json = json_decode($row['group_restrictions']);
365
+        if (!\is_array($json)) {
366
+            $this->logger->info('group_restrictions field could not be parsed for ' . $this->dbTableName . '::' . $row['id'] . ', denying access to resource');
367
+            return false;
368
+        }
369
+
370
+        // empty array => no group restrictions
371
+        if (empty($json)) {
372
+            return true;
373
+        }
374
+
375
+        return !empty(array_intersect($json, $userGroups));
376
+    }
377 377
 }
Please login to merge, or discard this patch.
apps/dav/lib/Connector/Sabre/Principal.php 1 patch
Indentation   +432 added lines, -432 removed lines patch added patch discarded remove patch
@@ -50,437 +50,437 @@
 block discarded – undo
50 50
 
51 51
 class Principal implements BackendInterface {
52 52
 
53
-	/** @var IUserManager */
54
-	private $userManager;
55
-
56
-	/** @var IGroupManager */
57
-	private $groupManager;
58
-
59
-	/** @var IShareManager */
60
-	private $shareManager;
61
-
62
-	/** @var IUserSession */
63
-	private $userSession;
64
-
65
-	/** @var IConfig */
66
-	private $config;
67
-
68
-	/** @var IAppManager */
69
-	private $appManager;
70
-
71
-	/** @var string */
72
-	private $principalPrefix;
73
-
74
-	/** @var bool */
75
-	private $hasGroups;
76
-
77
-	/** @var bool */
78
-	private $hasCircles;
79
-
80
-	/**
81
-	 * @param IUserManager $userManager
82
-	 * @param IGroupManager $groupManager
83
-	 * @param IShareManager $shareManager
84
-	 * @param IUserSession $userSession
85
-	 * @param IConfig $config
86
-	 * @param string $principalPrefix
87
-	 */
88
-	public function __construct(IUserManager $userManager,
89
-								IGroupManager $groupManager,
90
-								IShareManager $shareManager,
91
-								IUserSession $userSession,
92
-								IConfig $config,
93
-								IAppManager $appManager,
94
-								$principalPrefix = 'principals/users/') {
95
-		$this->userManager = $userManager;
96
-		$this->groupManager = $groupManager;
97
-		$this->shareManager = $shareManager;
98
-		$this->userSession = $userSession;
99
-		$this->config = $config;
100
-		$this->appManager = $appManager;
101
-		$this->principalPrefix = trim($principalPrefix, '/');
102
-		$this->hasGroups = $this->hasCircles = ($principalPrefix === 'principals/users/');
103
-	}
104
-
105
-	/**
106
-	 * Returns a list of principals based on a prefix.
107
-	 *
108
-	 * This prefix will often contain something like 'principals'. You are only
109
-	 * expected to return principals that are in this base path.
110
-	 *
111
-	 * You are expected to return at least a 'uri' for every user, you can
112
-	 * return any additional properties if you wish so. Common properties are:
113
-	 *   {DAV:}displayname
114
-	 *
115
-	 * @param string $prefixPath
116
-	 * @return string[]
117
-	 */
118
-	public function getPrincipalsByPrefix($prefixPath) {
119
-		$principals = [];
120
-
121
-		if ($prefixPath === $this->principalPrefix) {
122
-			foreach($this->userManager->search('') as $user) {
123
-				$principals[] = $this->userToPrincipal($user);
124
-			}
125
-		}
126
-
127
-		return $principals;
128
-	}
129
-
130
-	/**
131
-	 * Returns a specific principal, specified by it's path.
132
-	 * The returned structure should be the exact same as from
133
-	 * getPrincipalsByPrefix.
134
-	 *
135
-	 * @param string $path
136
-	 * @return array
137
-	 */
138
-	public function getPrincipalByPath($path) {
139
-		list($prefix, $name) = \Sabre\Uri\split($path);
140
-
141
-		if ($prefix === $this->principalPrefix) {
142
-			$user = $this->userManager->get($name);
143
-
144
-			if ($user !== null) {
145
-				return $this->userToPrincipal($user);
146
-			}
147
-		} else if ($prefix === 'principals/circles') {
148
-			try {
149
-				return $this->circleToPrincipal($name);
150
-			} catch (QueryException $e) {
151
-				return null;
152
-			}
153
-		}
154
-		return null;
155
-	}
156
-
157
-	/**
158
-	 * Returns the list of members for a group-principal
159
-	 *
160
-	 * @param string $principal
161
-	 * @return string[]
162
-	 * @throws Exception
163
-	 */
164
-	public function getGroupMemberSet($principal) {
165
-		// TODO: for now the group principal has only one member, the user itself
166
-		$principal = $this->getPrincipalByPath($principal);
167
-		if (!$principal) {
168
-			throw new Exception('Principal not found');
169
-		}
170
-
171
-		return [$principal['uri']];
172
-	}
173
-
174
-	/**
175
-	 * Returns the list of groups a principal is a member of
176
-	 *
177
-	 * @param string $principal
178
-	 * @param bool $needGroups
179
-	 * @return array
180
-	 * @throws Exception
181
-	 */
182
-	public function getGroupMembership($principal, $needGroups = false) {
183
-		list($prefix, $name) = \Sabre\Uri\split($principal);
184
-
185
-		if ($prefix === $this->principalPrefix) {
186
-			$user = $this->userManager->get($name);
187
-			if (!$user) {
188
-				throw new Exception('Principal not found');
189
-			}
190
-
191
-			if ($this->hasGroups || $needGroups) {
192
-				$groups = $this->groupManager->getUserGroups($user);
193
-				$groups = array_map(function($group) {
194
-					/** @var IGroup $group */
195
-					return 'principals/groups/' . urlencode($group->getGID());
196
-				}, $groups);
197
-
198
-				return $groups;
199
-			}
200
-		}
201
-		return [];
202
-	}
203
-
204
-	/**
205
-	 * Updates the list of group members for a group principal.
206
-	 *
207
-	 * The principals should be passed as a list of uri's.
208
-	 *
209
-	 * @param string $principal
210
-	 * @param string[] $members
211
-	 * @throws Exception
212
-	 */
213
-	public function setGroupMemberSet($principal, array $members) {
214
-		throw new Exception('Setting members of the group is not supported yet');
215
-	}
216
-
217
-	/**
218
-	 * @param string $path
219
-	 * @param PropPatch $propPatch
220
-	 * @return int
221
-	 */
222
-	function updatePrincipal($path, PropPatch $propPatch) {
223
-		return 0;
224
-	}
225
-
226
-	/**
227
-	 * Search user principals
228
-	 *
229
-	 * @param array $searchProperties
230
-	 * @param string $test
231
-	 * @return array
232
-	 */
233
-	protected function searchUserPrincipals(array $searchProperties, $test = 'allof') {
234
-		$results = [];
235
-
236
-		// If sharing is disabled, return the empty array
237
-		$shareAPIEnabled = $this->shareManager->shareApiEnabled();
238
-		if (!$shareAPIEnabled) {
239
-			return [];
240
-		}
241
-
242
-		// If sharing is restricted to group members only,
243
-		// return only members that have groups in common
244
-		$restrictGroups = false;
245
-		if ($this->shareManager->shareWithGroupMembersOnly()) {
246
-			$user = $this->userSession->getUser();
247
-			if (!$user) {
248
-				return [];
249
-			}
250
-
251
-			$restrictGroups = $this->groupManager->getUserGroupIds($user);
252
-		}
253
-
254
-		foreach ($searchProperties as $prop => $value) {
255
-			switch ($prop) {
256
-				case '{http://sabredav.org/ns}email-address':
257
-					$users = $this->userManager->getByEmail($value);
258
-
259
-					$results[] = array_reduce($users, function(array $carry, IUser $user) use ($restrictGroups) {
260
-						// is sharing restricted to groups only?
261
-						if ($restrictGroups !== false) {
262
-							$userGroups = $this->groupManager->getUserGroupIds($user);
263
-							if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
264
-								return $carry;
265
-							}
266
-						}
267
-
268
-						$carry[] = $this->principalPrefix . '/' . $user->getUID();
269
-						return $carry;
270
-					}, []);
271
-					break;
272
-
273
-				case '{DAV:}displayname':
274
-					$users = $this->userManager->searchDisplayName($value);
275
-
276
-					$results[] = array_reduce($users, function(array $carry, IUser $user) use ($restrictGroups) {
277
-						// is sharing restricted to groups only?
278
-						if ($restrictGroups !== false) {
279
-							$userGroups = $this->groupManager->getUserGroupIds($user);
280
-							if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
281
-								return $carry;
282
-							}
283
-						}
284
-
285
-						$carry[] = $this->principalPrefix . '/' . $user->getUID();
286
-						return $carry;
287
-					}, []);
288
-					break;
289
-
290
-				case '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set':
291
-					// If you add support for more search properties that qualify as a user-address,
292
-					// please also add them to the array below
293
-					$results[] = $this->searchUserPrincipals([
294
-						// In theory this should also search for principal:principals/users/...
295
-						// but that's used internally only anyway and i don't know of any client querying that
296
-						'{http://sabredav.org/ns}email-address' => $value,
297
-					], 'anyof');
298
-					break;
299
-
300
-				default:
301
-					$results[] = [];
302
-					break;
303
-			}
304
-		}
305
-
306
-		// results is an array of arrays, so this is not the first search result
307
-		// but the results of the first searchProperty
308
-		if (count($results) === 1) {
309
-			return $results[0];
310
-		}
311
-
312
-		switch ($test) {
313
-			case 'anyof':
314
-				return array_values(array_unique(array_merge(...$results)));
315
-
316
-			case 'allof':
317
-			default:
318
-				return array_values(array_intersect(...$results));
319
-		}
320
-	}
321
-
322
-	/**
323
-	 * @param string $prefixPath
324
-	 * @param array $searchProperties
325
-	 * @param string $test
326
-	 * @return array
327
-	 */
328
-	function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
329
-		if (count($searchProperties) === 0) {
330
-			return [];
331
-		}
332
-
333
-		switch ($prefixPath) {
334
-			case 'principals/users':
335
-				return $this->searchUserPrincipals($searchProperties, $test);
336
-
337
-			default:
338
-				return [];
339
-		}
340
-	}
341
-
342
-	/**
343
-	 * @param string $uri
344
-	 * @param string $principalPrefix
345
-	 * @return string
346
-	 */
347
-	function findByUri($uri, $principalPrefix) {
348
-		// If sharing is disabled, return the empty array
349
-		$shareAPIEnabled = $this->shareManager->shareApiEnabled();
350
-		if (!$shareAPIEnabled) {
351
-			return null;
352
-		}
353
-
354
-		// If sharing is restricted to group members only,
355
-		// return only members that have groups in common
356
-		$restrictGroups = false;
357
-		if ($this->shareManager->shareWithGroupMembersOnly()) {
358
-			$user = $this->userSession->getUser();
359
-			if (!$user) {
360
-				return null;
361
-			}
362
-
363
-			$restrictGroups = $this->groupManager->getUserGroupIds($user);
364
-		}
365
-
366
-		if (strpos($uri, 'mailto:') === 0) {
367
-			if ($principalPrefix === 'principals/users') {
368
-				$users = $this->userManager->getByEmail(substr($uri, 7));
369
-				if (count($users) !== 1) {
370
-					return null;
371
-				}
372
-				$user = $users[0];
373
-
374
-				if ($restrictGroups !== false) {
375
-					$userGroups = $this->groupManager->getUserGroupIds($user);
376
-					if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
377
-						return null;
378
-					}
379
-				}
380
-
381
-				return $this->principalPrefix . '/' . $user->getUID();
382
-			}
383
-		}
384
-		if (substr($uri, 0, 10) === 'principal:') {
385
-			$principal = substr($uri, 10);
386
-			$principal = $this->getPrincipalByPath($principal);
387
-			if ($principal !== null) {
388
-				return $principal['uri'];
389
-			}
390
-		}
391
-
392
-		return null;
393
-	}
394
-
395
-	/**
396
-	 * @param IUser $user
397
-	 * @return array
398
-	 */
399
-	protected function userToPrincipal($user) {
400
-		$userId = $user->getUID();
401
-		$displayName = $user->getDisplayName();
402
-		$principal = [
403
-				'uri' => $this->principalPrefix . '/' . $userId,
404
-				'{DAV:}displayname' => is_null($displayName) ? $userId : $displayName,
405
-				'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
406
-		];
407
-
408
-		$email = $user->getEMailAddress();
409
-		if (!empty($email)) {
410
-			$principal['{http://sabredav.org/ns}email-address'] = $email;
411
-		}
412
-
413
-		return $principal;
414
-	}
415
-
416
-	public function getPrincipalPrefix() {
417
-		return $this->principalPrefix;
418
-	}
419
-
420
-	/**
421
-	 * @param string $circleUniqueId
422
-	 * @return array|null
423
-	 * @throws \OCP\AppFramework\QueryException
424
-	 * @suppress PhanUndeclaredClassMethod
425
-	 * @suppress PhanUndeclaredClassCatch
426
-	 */
427
-	protected function circleToPrincipal($circleUniqueId) {
428
-		if (!$this->appManager->isEnabledForUser('circles') || !class_exists('\OCA\Circles\Api\v1\Circles')) {
429
-			return null;
430
-		}
431
-
432
-		try {
433
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($circleUniqueId, true);
434
-		} catch(QueryException $ex) {
435
-			return null;
436
-		} catch(CircleDoesNotExistException $ex) {
437
-			return null;
438
-		}
439
-
440
-		if (!$circle) {
441
-			return null;
442
-		}
443
-
444
-		$principal = [
445
-			'uri' => 'principals/circles/' . $circleUniqueId,
446
-			'{DAV:}displayname' => $circle->getName(),
447
-		];
448
-
449
-		return $principal;
450
-	}
451
-
452
-	/**
453
-	 * Returns the list of circles a principal is a member of
454
-	 *
455
-	 * @param string $principal
456
-	 * @return array
457
-	 * @throws Exception
458
-	 * @throws \OCP\AppFramework\QueryException
459
-	 * @suppress PhanUndeclaredClassMethod
460
-	 */
461
-	public function getCircleMembership($principal):array {
462
-		if (!$this->appManager->isEnabledForUser('circles') || !class_exists('\OCA\Circles\Api\v1\Circles')) {
463
-			return [];
464
-		}
465
-
466
-		list($prefix, $name) = \Sabre\Uri\split($principal);
467
-		if ($this->hasCircles && $prefix === $this->principalPrefix) {
468
-			$user = $this->userManager->get($name);
469
-			if (!$user) {
470
-				throw new Exception('Principal not found');
471
-			}
472
-
473
-			$circles = \OCA\Circles\Api\v1\Circles::joinedCircles($name, true);
474
-
475
-			$circles = array_map(function($circle) {
476
-				/** @var \OCA\Circles\Model\Circle $circle */
477
-				return 'principals/circles/' . urlencode($circle->getUniqueId());
478
-			}, $circles);
479
-
480
-			return $circles;
481
-		}
482
-
483
-		return [];
484
-	}
53
+    /** @var IUserManager */
54
+    private $userManager;
55
+
56
+    /** @var IGroupManager */
57
+    private $groupManager;
58
+
59
+    /** @var IShareManager */
60
+    private $shareManager;
61
+
62
+    /** @var IUserSession */
63
+    private $userSession;
64
+
65
+    /** @var IConfig */
66
+    private $config;
67
+
68
+    /** @var IAppManager */
69
+    private $appManager;
70
+
71
+    /** @var string */
72
+    private $principalPrefix;
73
+
74
+    /** @var bool */
75
+    private $hasGroups;
76
+
77
+    /** @var bool */
78
+    private $hasCircles;
79
+
80
+    /**
81
+     * @param IUserManager $userManager
82
+     * @param IGroupManager $groupManager
83
+     * @param IShareManager $shareManager
84
+     * @param IUserSession $userSession
85
+     * @param IConfig $config
86
+     * @param string $principalPrefix
87
+     */
88
+    public function __construct(IUserManager $userManager,
89
+                                IGroupManager $groupManager,
90
+                                IShareManager $shareManager,
91
+                                IUserSession $userSession,
92
+                                IConfig $config,
93
+                                IAppManager $appManager,
94
+                                $principalPrefix = 'principals/users/') {
95
+        $this->userManager = $userManager;
96
+        $this->groupManager = $groupManager;
97
+        $this->shareManager = $shareManager;
98
+        $this->userSession = $userSession;
99
+        $this->config = $config;
100
+        $this->appManager = $appManager;
101
+        $this->principalPrefix = trim($principalPrefix, '/');
102
+        $this->hasGroups = $this->hasCircles = ($principalPrefix === 'principals/users/');
103
+    }
104
+
105
+    /**
106
+     * Returns a list of principals based on a prefix.
107
+     *
108
+     * This prefix will often contain something like 'principals'. You are only
109
+     * expected to return principals that are in this base path.
110
+     *
111
+     * You are expected to return at least a 'uri' for every user, you can
112
+     * return any additional properties if you wish so. Common properties are:
113
+     *   {DAV:}displayname
114
+     *
115
+     * @param string $prefixPath
116
+     * @return string[]
117
+     */
118
+    public function getPrincipalsByPrefix($prefixPath) {
119
+        $principals = [];
120
+
121
+        if ($prefixPath === $this->principalPrefix) {
122
+            foreach($this->userManager->search('') as $user) {
123
+                $principals[] = $this->userToPrincipal($user);
124
+            }
125
+        }
126
+
127
+        return $principals;
128
+    }
129
+
130
+    /**
131
+     * Returns a specific principal, specified by it's path.
132
+     * The returned structure should be the exact same as from
133
+     * getPrincipalsByPrefix.
134
+     *
135
+     * @param string $path
136
+     * @return array
137
+     */
138
+    public function getPrincipalByPath($path) {
139
+        list($prefix, $name) = \Sabre\Uri\split($path);
140
+
141
+        if ($prefix === $this->principalPrefix) {
142
+            $user = $this->userManager->get($name);
143
+
144
+            if ($user !== null) {
145
+                return $this->userToPrincipal($user);
146
+            }
147
+        } else if ($prefix === 'principals/circles') {
148
+            try {
149
+                return $this->circleToPrincipal($name);
150
+            } catch (QueryException $e) {
151
+                return null;
152
+            }
153
+        }
154
+        return null;
155
+    }
156
+
157
+    /**
158
+     * Returns the list of members for a group-principal
159
+     *
160
+     * @param string $principal
161
+     * @return string[]
162
+     * @throws Exception
163
+     */
164
+    public function getGroupMemberSet($principal) {
165
+        // TODO: for now the group principal has only one member, the user itself
166
+        $principal = $this->getPrincipalByPath($principal);
167
+        if (!$principal) {
168
+            throw new Exception('Principal not found');
169
+        }
170
+
171
+        return [$principal['uri']];
172
+    }
173
+
174
+    /**
175
+     * Returns the list of groups a principal is a member of
176
+     *
177
+     * @param string $principal
178
+     * @param bool $needGroups
179
+     * @return array
180
+     * @throws Exception
181
+     */
182
+    public function getGroupMembership($principal, $needGroups = false) {
183
+        list($prefix, $name) = \Sabre\Uri\split($principal);
184
+
185
+        if ($prefix === $this->principalPrefix) {
186
+            $user = $this->userManager->get($name);
187
+            if (!$user) {
188
+                throw new Exception('Principal not found');
189
+            }
190
+
191
+            if ($this->hasGroups || $needGroups) {
192
+                $groups = $this->groupManager->getUserGroups($user);
193
+                $groups = array_map(function($group) {
194
+                    /** @var IGroup $group */
195
+                    return 'principals/groups/' . urlencode($group->getGID());
196
+                }, $groups);
197
+
198
+                return $groups;
199
+            }
200
+        }
201
+        return [];
202
+    }
203
+
204
+    /**
205
+     * Updates the list of group members for a group principal.
206
+     *
207
+     * The principals should be passed as a list of uri's.
208
+     *
209
+     * @param string $principal
210
+     * @param string[] $members
211
+     * @throws Exception
212
+     */
213
+    public function setGroupMemberSet($principal, array $members) {
214
+        throw new Exception('Setting members of the group is not supported yet');
215
+    }
216
+
217
+    /**
218
+     * @param string $path
219
+     * @param PropPatch $propPatch
220
+     * @return int
221
+     */
222
+    function updatePrincipal($path, PropPatch $propPatch) {
223
+        return 0;
224
+    }
225
+
226
+    /**
227
+     * Search user principals
228
+     *
229
+     * @param array $searchProperties
230
+     * @param string $test
231
+     * @return array
232
+     */
233
+    protected function searchUserPrincipals(array $searchProperties, $test = 'allof') {
234
+        $results = [];
235
+
236
+        // If sharing is disabled, return the empty array
237
+        $shareAPIEnabled = $this->shareManager->shareApiEnabled();
238
+        if (!$shareAPIEnabled) {
239
+            return [];
240
+        }
241
+
242
+        // If sharing is restricted to group members only,
243
+        // return only members that have groups in common
244
+        $restrictGroups = false;
245
+        if ($this->shareManager->shareWithGroupMembersOnly()) {
246
+            $user = $this->userSession->getUser();
247
+            if (!$user) {
248
+                return [];
249
+            }
250
+
251
+            $restrictGroups = $this->groupManager->getUserGroupIds($user);
252
+        }
253
+
254
+        foreach ($searchProperties as $prop => $value) {
255
+            switch ($prop) {
256
+                case '{http://sabredav.org/ns}email-address':
257
+                    $users = $this->userManager->getByEmail($value);
258
+
259
+                    $results[] = array_reduce($users, function(array $carry, IUser $user) use ($restrictGroups) {
260
+                        // is sharing restricted to groups only?
261
+                        if ($restrictGroups !== false) {
262
+                            $userGroups = $this->groupManager->getUserGroupIds($user);
263
+                            if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
264
+                                return $carry;
265
+                            }
266
+                        }
267
+
268
+                        $carry[] = $this->principalPrefix . '/' . $user->getUID();
269
+                        return $carry;
270
+                    }, []);
271
+                    break;
272
+
273
+                case '{DAV:}displayname':
274
+                    $users = $this->userManager->searchDisplayName($value);
275
+
276
+                    $results[] = array_reduce($users, function(array $carry, IUser $user) use ($restrictGroups) {
277
+                        // is sharing restricted to groups only?
278
+                        if ($restrictGroups !== false) {
279
+                            $userGroups = $this->groupManager->getUserGroupIds($user);
280
+                            if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
281
+                                return $carry;
282
+                            }
283
+                        }
284
+
285
+                        $carry[] = $this->principalPrefix . '/' . $user->getUID();
286
+                        return $carry;
287
+                    }, []);
288
+                    break;
289
+
290
+                case '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set':
291
+                    // If you add support for more search properties that qualify as a user-address,
292
+                    // please also add them to the array below
293
+                    $results[] = $this->searchUserPrincipals([
294
+                        // In theory this should also search for principal:principals/users/...
295
+                        // but that's used internally only anyway and i don't know of any client querying that
296
+                        '{http://sabredav.org/ns}email-address' => $value,
297
+                    ], 'anyof');
298
+                    break;
299
+
300
+                default:
301
+                    $results[] = [];
302
+                    break;
303
+            }
304
+        }
305
+
306
+        // results is an array of arrays, so this is not the first search result
307
+        // but the results of the first searchProperty
308
+        if (count($results) === 1) {
309
+            return $results[0];
310
+        }
311
+
312
+        switch ($test) {
313
+            case 'anyof':
314
+                return array_values(array_unique(array_merge(...$results)));
315
+
316
+            case 'allof':
317
+            default:
318
+                return array_values(array_intersect(...$results));
319
+        }
320
+    }
321
+
322
+    /**
323
+     * @param string $prefixPath
324
+     * @param array $searchProperties
325
+     * @param string $test
326
+     * @return array
327
+     */
328
+    function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
329
+        if (count($searchProperties) === 0) {
330
+            return [];
331
+        }
332
+
333
+        switch ($prefixPath) {
334
+            case 'principals/users':
335
+                return $this->searchUserPrincipals($searchProperties, $test);
336
+
337
+            default:
338
+                return [];
339
+        }
340
+    }
341
+
342
+    /**
343
+     * @param string $uri
344
+     * @param string $principalPrefix
345
+     * @return string
346
+     */
347
+    function findByUri($uri, $principalPrefix) {
348
+        // If sharing is disabled, return the empty array
349
+        $shareAPIEnabled = $this->shareManager->shareApiEnabled();
350
+        if (!$shareAPIEnabled) {
351
+            return null;
352
+        }
353
+
354
+        // If sharing is restricted to group members only,
355
+        // return only members that have groups in common
356
+        $restrictGroups = false;
357
+        if ($this->shareManager->shareWithGroupMembersOnly()) {
358
+            $user = $this->userSession->getUser();
359
+            if (!$user) {
360
+                return null;
361
+            }
362
+
363
+            $restrictGroups = $this->groupManager->getUserGroupIds($user);
364
+        }
365
+
366
+        if (strpos($uri, 'mailto:') === 0) {
367
+            if ($principalPrefix === 'principals/users') {
368
+                $users = $this->userManager->getByEmail(substr($uri, 7));
369
+                if (count($users) !== 1) {
370
+                    return null;
371
+                }
372
+                $user = $users[0];
373
+
374
+                if ($restrictGroups !== false) {
375
+                    $userGroups = $this->groupManager->getUserGroupIds($user);
376
+                    if (count(array_intersect($userGroups, $restrictGroups)) === 0) {
377
+                        return null;
378
+                    }
379
+                }
380
+
381
+                return $this->principalPrefix . '/' . $user->getUID();
382
+            }
383
+        }
384
+        if (substr($uri, 0, 10) === 'principal:') {
385
+            $principal = substr($uri, 10);
386
+            $principal = $this->getPrincipalByPath($principal);
387
+            if ($principal !== null) {
388
+                return $principal['uri'];
389
+            }
390
+        }
391
+
392
+        return null;
393
+    }
394
+
395
+    /**
396
+     * @param IUser $user
397
+     * @return array
398
+     */
399
+    protected function userToPrincipal($user) {
400
+        $userId = $user->getUID();
401
+        $displayName = $user->getDisplayName();
402
+        $principal = [
403
+                'uri' => $this->principalPrefix . '/' . $userId,
404
+                '{DAV:}displayname' => is_null($displayName) ? $userId : $displayName,
405
+                '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
406
+        ];
407
+
408
+        $email = $user->getEMailAddress();
409
+        if (!empty($email)) {
410
+            $principal['{http://sabredav.org/ns}email-address'] = $email;
411
+        }
412
+
413
+        return $principal;
414
+    }
415
+
416
+    public function getPrincipalPrefix() {
417
+        return $this->principalPrefix;
418
+    }
419
+
420
+    /**
421
+     * @param string $circleUniqueId
422
+     * @return array|null
423
+     * @throws \OCP\AppFramework\QueryException
424
+     * @suppress PhanUndeclaredClassMethod
425
+     * @suppress PhanUndeclaredClassCatch
426
+     */
427
+    protected function circleToPrincipal($circleUniqueId) {
428
+        if (!$this->appManager->isEnabledForUser('circles') || !class_exists('\OCA\Circles\Api\v1\Circles')) {
429
+            return null;
430
+        }
431
+
432
+        try {
433
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($circleUniqueId, true);
434
+        } catch(QueryException $ex) {
435
+            return null;
436
+        } catch(CircleDoesNotExistException $ex) {
437
+            return null;
438
+        }
439
+
440
+        if (!$circle) {
441
+            return null;
442
+        }
443
+
444
+        $principal = [
445
+            'uri' => 'principals/circles/' . $circleUniqueId,
446
+            '{DAV:}displayname' => $circle->getName(),
447
+        ];
448
+
449
+        return $principal;
450
+    }
451
+
452
+    /**
453
+     * Returns the list of circles a principal is a member of
454
+     *
455
+     * @param string $principal
456
+     * @return array
457
+     * @throws Exception
458
+     * @throws \OCP\AppFramework\QueryException
459
+     * @suppress PhanUndeclaredClassMethod
460
+     */
461
+    public function getCircleMembership($principal):array {
462
+        if (!$this->appManager->isEnabledForUser('circles') || !class_exists('\OCA\Circles\Api\v1\Circles')) {
463
+            return [];
464
+        }
465
+
466
+        list($prefix, $name) = \Sabre\Uri\split($principal);
467
+        if ($this->hasCircles && $prefix === $this->principalPrefix) {
468
+            $user = $this->userManager->get($name);
469
+            if (!$user) {
470
+                throw new Exception('Principal not found');
471
+            }
472
+
473
+            $circles = \OCA\Circles\Api\v1\Circles::joinedCircles($name, true);
474
+
475
+            $circles = array_map(function($circle) {
476
+                /** @var \OCA\Circles\Model\Circle $circle */
477
+                return 'principals/circles/' . urlencode($circle->getUniqueId());
478
+            }, $circles);
479
+
480
+            return $circles;
481
+        }
482
+
483
+        return [];
484
+    }
485 485
 
486 486
 }
Please login to merge, or discard this patch.
apps/dav/lib/DAV/GroupPrincipalBackend.php 1 patch
Indentation   +290 added lines, -290 removed lines patch added patch discarded remove patch
@@ -35,294 +35,294 @@
 block discarded – undo
35 35
 
36 36
 class GroupPrincipalBackend implements BackendInterface {
37 37
 
38
-	const PRINCIPAL_PREFIX = 'principals/groups';
39
-
40
-	/** @var IGroupManager */
41
-	private $groupManager;
42
-
43
-	/** @var IUserSession */
44
-	private $userSession;
45
-
46
-	/** @var IShareManager */
47
-	private $shareManager;
48
-
49
-	/**
50
-	 * @param IGroupManager $IGroupManager
51
-	 * @param IUserSession $userSession
52
-	 * @param IShareManager $shareManager
53
-	 */
54
-	public function __construct(IGroupManager $IGroupManager,
55
-								IUserSession $userSession,
56
-								IShareManager $shareManager) {
57
-		$this->groupManager = $IGroupManager;
58
-		$this->userSession = $userSession;
59
-		$this->shareManager = $shareManager;
60
-	}
61
-
62
-	/**
63
-	 * Returns a list of principals based on a prefix.
64
-	 *
65
-	 * This prefix will often contain something like 'principals'. You are only
66
-	 * expected to return principals that are in this base path.
67
-	 *
68
-	 * You are expected to return at least a 'uri' for every user, you can
69
-	 * return any additional properties if you wish so. Common properties are:
70
-	 *   {DAV:}displayname
71
-	 *
72
-	 * @param string $prefixPath
73
-	 * @return string[]
74
-	 */
75
-	public function getPrincipalsByPrefix($prefixPath) {
76
-		$principals = [];
77
-
78
-		if ($prefixPath === self::PRINCIPAL_PREFIX) {
79
-			foreach($this->groupManager->search('') as $user) {
80
-				$principals[] = $this->groupToPrincipal($user);
81
-			}
82
-		}
83
-
84
-		return $principals;
85
-	}
86
-
87
-	/**
88
-	 * Returns a specific principal, specified by it's path.
89
-	 * The returned structure should be the exact same as from
90
-	 * getPrincipalsByPrefix.
91
-	 *
92
-	 * @param string $path
93
-	 * @return array
94
-	 */
95
-	public function getPrincipalByPath($path) {
96
-		$elements = explode('/', $path,  3);
97
-		if ($elements[0] !== 'principals') {
98
-			return null;
99
-		}
100
-		if ($elements[1] !== 'groups') {
101
-			return null;
102
-		}
103
-		$name = urldecode($elements[2]);
104
-		$group = $this->groupManager->get($name);
105
-
106
-		if (!is_null($group)) {
107
-			return $this->groupToPrincipal($group);
108
-		}
109
-
110
-		return null;
111
-	}
112
-
113
-	/**
114
-	 * Returns the list of members for a group-principal
115
-	 *
116
-	 * @param string $principal
117
-	 * @return string[]
118
-	 * @throws Exception
119
-	 */
120
-	public function getGroupMemberSet($principal) {
121
-		$elements = explode('/', $principal);
122
-		if ($elements[0] !== 'principals') {
123
-			return [];
124
-		}
125
-		if ($elements[1] !== 'groups') {
126
-			return [];
127
-		}
128
-		$name = $elements[2];
129
-		$group = $this->groupManager->get($name);
130
-
131
-		if (is_null($group)) {
132
-			return [];
133
-		}
134
-
135
-		return array_map(function($user) {
136
-			return $this->userToPrincipal($user);
137
-		}, $group->getUsers());
138
-	}
139
-
140
-	/**
141
-	 * Returns the list of groups a principal is a member of
142
-	 *
143
-	 * @param string $principal
144
-	 * @return array
145
-	 * @throws Exception
146
-	 */
147
-	public function getGroupMembership($principal) {
148
-		return [];
149
-	}
150
-
151
-	/**
152
-	 * Updates the list of group members for a group principal.
153
-	 *
154
-	 * The principals should be passed as a list of uri's.
155
-	 *
156
-	 * @param string $principal
157
-	 * @param string[] $members
158
-	 * @throws Exception
159
-	 */
160
-	public function setGroupMemberSet($principal, array $members) {
161
-		throw new Exception('Setting members of the group is not supported yet');
162
-	}
163
-
164
-	/**
165
-	 * @param string $path
166
-	 * @param PropPatch $propPatch
167
-	 * @return int
168
-	 */
169
-	function updatePrincipal($path, PropPatch $propPatch) {
170
-		return 0;
171
-	}
172
-
173
-	/**
174
-	 * @param string $prefixPath
175
-	 * @param array $searchProperties
176
-	 * @param string $test
177
-	 * @return array
178
-	 */
179
-	function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
180
-		$results = [];
181
-
182
-		if (\count($searchProperties) === 0) {
183
-			return [];
184
-		}
185
-		if ($prefixPath !== self::PRINCIPAL_PREFIX) {
186
-			return [];
187
-		}
188
-		// If sharing is disabled, return the empty array
189
-		$shareAPIEnabled = $this->shareManager->shareApiEnabled();
190
-		if (!$shareAPIEnabled) {
191
-			return [];
192
-		}
193
-
194
-		// If sharing is restricted to group members only,
195
-		// return only members that have groups in common
196
-		$restrictGroups = false;
197
-		if ($this->shareManager->shareWithGroupMembersOnly()) {
198
-			$user = $this->userSession->getUser();
199
-			if (!$user) {
200
-				return [];
201
-			}
202
-
203
-			$restrictGroups = $this->groupManager->getUserGroupIds($user);
204
-		}
205
-
206
-		foreach ($searchProperties as $prop => $value) {
207
-			switch ($prop) {
208
-				case '{DAV:}displayname':
209
-					$groups = $this->groupManager->search($value);
210
-
211
-					$results[] = array_reduce($groups, function(array $carry, IGroup $group) use ($restrictGroups) {
212
-						$gid = $group->getGID();
213
-						// is sharing restricted to groups only?
214
-						if ($restrictGroups !== false) {
215
-							if (!\in_array($gid, $restrictGroups, true)) {
216
-								return $carry;
217
-							}
218
-						}
219
-
220
-						$carry[] = self::PRINCIPAL_PREFIX . '/' . $gid;
221
-						return $carry;
222
-					}, []);
223
-					break;
224
-
225
-				case '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set':
226
-					// If you add support for more search properties that qualify as a user-address,
227
-					// please also add them to the array below
228
-					$results[] = $this->searchPrincipals(self::PRINCIPAL_PREFIX, [
229
-					], 'anyof');
230
-					break;
231
-
232
-				default:
233
-					$results[] = [];
234
-					break;
235
-			}
236
-		}
237
-
238
-		// results is an array of arrays, so this is not the first search result
239
-		// but the results of the first searchProperty
240
-		if (count($results) === 1) {
241
-			return $results[0];
242
-		}
243
-
244
-		switch ($test) {
245
-			case 'anyof':
246
-				return array_values(array_unique(array_merge(...$results)));
247
-
248
-			case 'allof':
249
-			default:
250
-				return array_values(array_intersect(...$results));
251
-		}
252
-	}
253
-
254
-	/**
255
-	 * @param string $uri
256
-	 * @param string $principalPrefix
257
-	 * @return string
258
-	 */
259
-	function findByUri($uri, $principalPrefix) {
260
-		// If sharing is disabled, return the empty array
261
-		$shareAPIEnabled = $this->shareManager->shareApiEnabled();
262
-		if (!$shareAPIEnabled) {
263
-			return null;
264
-		}
265
-
266
-		// If sharing is restricted to group members only,
267
-		// return only members that have groups in common
268
-		$restrictGroups = false;
269
-		if ($this->shareManager->shareWithGroupMembersOnly()) {
270
-			$user = $this->userSession->getUser();
271
-			if (!$user) {
272
-				return null;
273
-			}
274
-
275
-			$restrictGroups = $this->groupManager->getUserGroupIds($user);
276
-		}
277
-
278
-		if (strpos($uri, 'principal:principals/groups/') === 0) {
279
-			$name = urlencode(substr($uri, 28));
280
-			if ($restrictGroups !== false && !\in_array($name, $restrictGroups, true)) {
281
-				return null;
282
-			}
283
-
284
-			return substr($uri, 10);
285
-		}
286
-
287
-		return null;
288
-	}
289
-
290
-	/**
291
-	 * @param IGroup $group
292
-	 * @return array
293
-	 */
294
-	protected function groupToPrincipal($group) {
295
-		$groupId = $group->getGID();
296
-		// getDisplayName returns UID if none
297
-		$displayName = $group->getDisplayName();
298
-
299
-		return [
300
-			'uri' => 'principals/groups/' . urlencode($groupId),
301
-			'{DAV:}displayname' => $displayName,
302
-			'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'GROUP',
303
-		];
304
-	}
305
-
306
-	/**
307
-	 * @param IUser $user
308
-	 * @return array
309
-	 */
310
-	protected function userToPrincipal($user) {
311
-		$userId = $user->getUID();
312
-		// getDisplayName returns UID if none
313
-		$displayName = $user->getDisplayName();
314
-
315
-		$principal = [
316
-			'uri' => 'principals/users/' . $userId,
317
-			'{DAV:}displayname' => $displayName,
318
-			'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
319
-		];
320
-
321
-		$email = $user->getEMailAddress();
322
-		if (!empty($email)) {
323
-			$principal['{http://sabredav.org/ns}email-address'] = $email;
324
-		}
325
-
326
-		return $principal;
327
-	}
38
+    const PRINCIPAL_PREFIX = 'principals/groups';
39
+
40
+    /** @var IGroupManager */
41
+    private $groupManager;
42
+
43
+    /** @var IUserSession */
44
+    private $userSession;
45
+
46
+    /** @var IShareManager */
47
+    private $shareManager;
48
+
49
+    /**
50
+     * @param IGroupManager $IGroupManager
51
+     * @param IUserSession $userSession
52
+     * @param IShareManager $shareManager
53
+     */
54
+    public function __construct(IGroupManager $IGroupManager,
55
+                                IUserSession $userSession,
56
+                                IShareManager $shareManager) {
57
+        $this->groupManager = $IGroupManager;
58
+        $this->userSession = $userSession;
59
+        $this->shareManager = $shareManager;
60
+    }
61
+
62
+    /**
63
+     * Returns a list of principals based on a prefix.
64
+     *
65
+     * This prefix will often contain something like 'principals'. You are only
66
+     * expected to return principals that are in this base path.
67
+     *
68
+     * You are expected to return at least a 'uri' for every user, you can
69
+     * return any additional properties if you wish so. Common properties are:
70
+     *   {DAV:}displayname
71
+     *
72
+     * @param string $prefixPath
73
+     * @return string[]
74
+     */
75
+    public function getPrincipalsByPrefix($prefixPath) {
76
+        $principals = [];
77
+
78
+        if ($prefixPath === self::PRINCIPAL_PREFIX) {
79
+            foreach($this->groupManager->search('') as $user) {
80
+                $principals[] = $this->groupToPrincipal($user);
81
+            }
82
+        }
83
+
84
+        return $principals;
85
+    }
86
+
87
+    /**
88
+     * Returns a specific principal, specified by it's path.
89
+     * The returned structure should be the exact same as from
90
+     * getPrincipalsByPrefix.
91
+     *
92
+     * @param string $path
93
+     * @return array
94
+     */
95
+    public function getPrincipalByPath($path) {
96
+        $elements = explode('/', $path,  3);
97
+        if ($elements[0] !== 'principals') {
98
+            return null;
99
+        }
100
+        if ($elements[1] !== 'groups') {
101
+            return null;
102
+        }
103
+        $name = urldecode($elements[2]);
104
+        $group = $this->groupManager->get($name);
105
+
106
+        if (!is_null($group)) {
107
+            return $this->groupToPrincipal($group);
108
+        }
109
+
110
+        return null;
111
+    }
112
+
113
+    /**
114
+     * Returns the list of members for a group-principal
115
+     *
116
+     * @param string $principal
117
+     * @return string[]
118
+     * @throws Exception
119
+     */
120
+    public function getGroupMemberSet($principal) {
121
+        $elements = explode('/', $principal);
122
+        if ($elements[0] !== 'principals') {
123
+            return [];
124
+        }
125
+        if ($elements[1] !== 'groups') {
126
+            return [];
127
+        }
128
+        $name = $elements[2];
129
+        $group = $this->groupManager->get($name);
130
+
131
+        if (is_null($group)) {
132
+            return [];
133
+        }
134
+
135
+        return array_map(function($user) {
136
+            return $this->userToPrincipal($user);
137
+        }, $group->getUsers());
138
+    }
139
+
140
+    /**
141
+     * Returns the list of groups a principal is a member of
142
+     *
143
+     * @param string $principal
144
+     * @return array
145
+     * @throws Exception
146
+     */
147
+    public function getGroupMembership($principal) {
148
+        return [];
149
+    }
150
+
151
+    /**
152
+     * Updates the list of group members for a group principal.
153
+     *
154
+     * The principals should be passed as a list of uri's.
155
+     *
156
+     * @param string $principal
157
+     * @param string[] $members
158
+     * @throws Exception
159
+     */
160
+    public function setGroupMemberSet($principal, array $members) {
161
+        throw new Exception('Setting members of the group is not supported yet');
162
+    }
163
+
164
+    /**
165
+     * @param string $path
166
+     * @param PropPatch $propPatch
167
+     * @return int
168
+     */
169
+    function updatePrincipal($path, PropPatch $propPatch) {
170
+        return 0;
171
+    }
172
+
173
+    /**
174
+     * @param string $prefixPath
175
+     * @param array $searchProperties
176
+     * @param string $test
177
+     * @return array
178
+     */
179
+    function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
180
+        $results = [];
181
+
182
+        if (\count($searchProperties) === 0) {
183
+            return [];
184
+        }
185
+        if ($prefixPath !== self::PRINCIPAL_PREFIX) {
186
+            return [];
187
+        }
188
+        // If sharing is disabled, return the empty array
189
+        $shareAPIEnabled = $this->shareManager->shareApiEnabled();
190
+        if (!$shareAPIEnabled) {
191
+            return [];
192
+        }
193
+
194
+        // If sharing is restricted to group members only,
195
+        // return only members that have groups in common
196
+        $restrictGroups = false;
197
+        if ($this->shareManager->shareWithGroupMembersOnly()) {
198
+            $user = $this->userSession->getUser();
199
+            if (!$user) {
200
+                return [];
201
+            }
202
+
203
+            $restrictGroups = $this->groupManager->getUserGroupIds($user);
204
+        }
205
+
206
+        foreach ($searchProperties as $prop => $value) {
207
+            switch ($prop) {
208
+                case '{DAV:}displayname':
209
+                    $groups = $this->groupManager->search($value);
210
+
211
+                    $results[] = array_reduce($groups, function(array $carry, IGroup $group) use ($restrictGroups) {
212
+                        $gid = $group->getGID();
213
+                        // is sharing restricted to groups only?
214
+                        if ($restrictGroups !== false) {
215
+                            if (!\in_array($gid, $restrictGroups, true)) {
216
+                                return $carry;
217
+                            }
218
+                        }
219
+
220
+                        $carry[] = self::PRINCIPAL_PREFIX . '/' . $gid;
221
+                        return $carry;
222
+                    }, []);
223
+                    break;
224
+
225
+                case '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set':
226
+                    // If you add support for more search properties that qualify as a user-address,
227
+                    // please also add them to the array below
228
+                    $results[] = $this->searchPrincipals(self::PRINCIPAL_PREFIX, [
229
+                    ], 'anyof');
230
+                    break;
231
+
232
+                default:
233
+                    $results[] = [];
234
+                    break;
235
+            }
236
+        }
237
+
238
+        // results is an array of arrays, so this is not the first search result
239
+        // but the results of the first searchProperty
240
+        if (count($results) === 1) {
241
+            return $results[0];
242
+        }
243
+
244
+        switch ($test) {
245
+            case 'anyof':
246
+                return array_values(array_unique(array_merge(...$results)));
247
+
248
+            case 'allof':
249
+            default:
250
+                return array_values(array_intersect(...$results));
251
+        }
252
+    }
253
+
254
+    /**
255
+     * @param string $uri
256
+     * @param string $principalPrefix
257
+     * @return string
258
+     */
259
+    function findByUri($uri, $principalPrefix) {
260
+        // If sharing is disabled, return the empty array
261
+        $shareAPIEnabled = $this->shareManager->shareApiEnabled();
262
+        if (!$shareAPIEnabled) {
263
+            return null;
264
+        }
265
+
266
+        // If sharing is restricted to group members only,
267
+        // return only members that have groups in common
268
+        $restrictGroups = false;
269
+        if ($this->shareManager->shareWithGroupMembersOnly()) {
270
+            $user = $this->userSession->getUser();
271
+            if (!$user) {
272
+                return null;
273
+            }
274
+
275
+            $restrictGroups = $this->groupManager->getUserGroupIds($user);
276
+        }
277
+
278
+        if (strpos($uri, 'principal:principals/groups/') === 0) {
279
+            $name = urlencode(substr($uri, 28));
280
+            if ($restrictGroups !== false && !\in_array($name, $restrictGroups, true)) {
281
+                return null;
282
+            }
283
+
284
+            return substr($uri, 10);
285
+        }
286
+
287
+        return null;
288
+    }
289
+
290
+    /**
291
+     * @param IGroup $group
292
+     * @return array
293
+     */
294
+    protected function groupToPrincipal($group) {
295
+        $groupId = $group->getGID();
296
+        // getDisplayName returns UID if none
297
+        $displayName = $group->getDisplayName();
298
+
299
+        return [
300
+            'uri' => 'principals/groups/' . urlencode($groupId),
301
+            '{DAV:}displayname' => $displayName,
302
+            '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'GROUP',
303
+        ];
304
+    }
305
+
306
+    /**
307
+     * @param IUser $user
308
+     * @return array
309
+     */
310
+    protected function userToPrincipal($user) {
311
+        $userId = $user->getUID();
312
+        // getDisplayName returns UID if none
313
+        $displayName = $user->getDisplayName();
314
+
315
+        $principal = [
316
+            'uri' => 'principals/users/' . $userId,
317
+            '{DAV:}displayname' => $displayName,
318
+            '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
319
+        ];
320
+
321
+        $email = $user->getEMailAddress();
322
+        if (!empty($email)) {
323
+            $principal['{http://sabredav.org/ns}email-address'] = $email;
324
+        }
325
+
326
+        return $principal;
327
+    }
328 328
 }
Please login to merge, or discard this patch.