Passed
Push — master ( d94b56...b04bda )
by Roeland
09:57
created
lib/private/Collaboration/Resources/Manager.php 1 patch
Indentation   +485 added lines, -485 removed lines patch added patch discarded remove patch
@@ -38,489 +38,489 @@
 block discarded – undo
38 38
 
39 39
 class Manager implements IManager {
40 40
 
41
-	public const TABLE_COLLECTIONS = 'collres_collections';
42
-	public const TABLE_RESOURCES = 'collres_resources';
43
-	public const TABLE_ACCESS_CACHE = 'collres_accesscache';
44
-
45
-	/** @var IDBConnection */
46
-	protected $connection;
47
-	/** @var ILogger */
48
-	protected $logger;
49
-
50
-	/** @var string[] */
51
-	protected $providers = [];
52
-
53
-	/** @var IProvider[] */
54
-	protected $providerInstances = [];
55
-
56
-	public function __construct(IDBConnection $connection, ILogger $logger) {
57
-		$this->connection = $connection;
58
-		$this->logger = $logger;
59
-	}
60
-
61
-	/**
62
-	 * @param int $id
63
-	 * @return ICollection
64
-	 * @throws CollectionException when the collection could not be found
65
-	 * @since 16.0.0
66
-	 */
67
-	public function getCollection(int $id): ICollection {
68
-		$query = $this->connection->getQueryBuilder();
69
-		$query->select('*')
70
-			->from(self::TABLE_COLLECTIONS)
71
-			->where($query->expr()->eq('id', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
72
-		$result = $query->execute();
73
-		$row = $result->fetch();
74
-		$result->closeCursor();
75
-
76
-		if (!$row) {
77
-			throw new CollectionException('Collection not found');
78
-		}
79
-
80
-		return new Collection($this, $this->connection, (int) $row['id'], (string) $row['name']);
81
-	}
82
-
83
-	/**
84
-	 * @param int $id
85
-	 * @param IUser|null $user
86
-	 * @return ICollection
87
-	 * @throws CollectionException when the collection could not be found
88
-	 * @since 16.0.0
89
-	 */
90
-	public function getCollectionForUser(int $id, ?IUser $user): ICollection {
91
-		$query = $this->connection->getQueryBuilder();
92
-		$userId = $user instanceof IUser ? $user->getUID() : '';
93
-
94
-		$query->select('*')
95
-			->from(self::TABLE_COLLECTIONS, 'c')
96
-			->leftJoin(
97
-				'c', self::TABLE_ACCESS_CACHE, 'a',
98
-				$query->expr()->andX(
99
-					$query->expr()->eq('c.id', 'a.collection_id'),
100
-					$query->expr()->eq('a.user_id', $query->createNamedParameter($userId, IQueryBuilder::PARAM_STR))
101
-				)
102
-			)
103
-			->where($query->expr()->eq('c.id', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
104
-		$result = $query->execute();
105
-		$row = $result->fetch();
106
-		$result->closeCursor();
107
-
108
-		if (!$row) {
109
-			throw new CollectionException('Collection not found');
110
-		}
111
-
112
-		$access = $row['access'] === null ? null : (bool) $row['access'];
113
-		if ($user instanceof IUser) {
114
-			return new Collection($this, $this->connection, (int) $row['id'], (string) $row['name'], $user, $access);
115
-		}
116
-
117
-		return new Collection($this, $this->connection, (int) $row['id'], (string) $row['name'], $user, $access);
118
-	}
119
-
120
-	/**
121
-	 * @param IUser $user
122
-	 * @param string $filter
123
-	 * @param int $limit
124
-	 * @param int $start
125
-	 * @return ICollection[]
126
-	 * @since 16.0.0
127
-	 */
128
-	public function searchCollections(IUser $user, string $filter, int $limit = 50, int $start = 0): array {
129
-		$query = $this->connection->getQueryBuilder();
130
-		$userId = $user instanceof IUser ? $user->getUID() : '';
131
-
132
-		$query->select('c.*', 'a.access')
133
-			->from(self::TABLE_COLLECTIONS, 'c')
134
-			->leftJoin(
135
-				'c', self::TABLE_ACCESS_CACHE, 'a',
136
-				$query->expr()->andX(
137
-					$query->expr()->eq('c.id', 'a.collection_id'),
138
-					$query->expr()->eq('a.user_id', $query->createNamedParameter($userId, IQueryBuilder::PARAM_STR))
139
-				)
140
-			)
141
-			->where($query->expr()->iLike('c.name', $query->createNamedParameter($filter, IQueryBuilder::PARAM_STR)))
142
-			->andWhere($query->expr()->eq('a.access', $query->createNamedParameter(1, IQueryBuilder::PARAM_INT)))
143
-			->orderBy('c.id')
144
-			->setMaxResults($limit)
145
-			->setFirstResult($start);
146
-		$result = $query->execute();
147
-		$collections = [];
148
-
149
-		$foundResults = 0;
150
-		while ($row = $result->fetch()) {
151
-			$foundResults++;
152
-			$access = $row['access'] === null ? null : (bool) $row['access'];
153
-			$collection = new Collection($this, $this->connection, (int)$row['id'], (string)$row['name'], $user, $access);
154
-			if ($collection->canAccess($user)) {
155
-				$collections[] = $collection;
156
-			}
157
-		}
158
-		$result->closeCursor();
159
-
160
-		if (empty($collections) && $foundResults === $limit) {
161
-			$this->searchCollections($user, $filter, $limit, $start + $limit);
162
-		}
163
-
164
-		return $collections;
165
-	}
166
-
167
-	/**
168
-	 * @param string $name
169
-	 * @return ICollection
170
-	 * @since 16.0.0
171
-	 */
172
-	public function newCollection(string $name): ICollection {
173
-		$query = $this->connection->getQueryBuilder();
174
-		$query->insert(self::TABLE_COLLECTIONS)
175
-			->values([
176
-				'name' => $query->createNamedParameter($name),
177
-			]);
178
-		$query->execute();
179
-
180
-		return new Collection($this, $this->connection, $query->getLastInsertId(), $name);
181
-	}
182
-
183
-	/**
184
-	 * @param string $type
185
-	 * @param string $id
186
-	 * @return IResource
187
-	 * @since 16.0.0
188
-	 */
189
-	public function createResource(string $type, string $id): IResource {
190
-		return new Resource($this, $this->connection, $type, $id);
191
-	}
192
-
193
-	/**
194
-	 * @param string $type
195
-	 * @param string $id
196
-	 * @param IUser|null $user
197
-	 * @return IResource
198
-	 * @throws ResourceException
199
-	 * @since 16.0.0
200
-	 */
201
-	public function getResourceForUser(string $type, string $id, ?IUser $user): IResource {
202
-		$query = $this->connection->getQueryBuilder();
203
-		$userId = $user instanceof IUser ? $user->getUID() : '';
204
-
205
-		$query->select('r.*', 'a.access')
206
-			->from(self::TABLE_RESOURCES, 'r')
207
-			->leftJoin(
208
-				'r', self::TABLE_ACCESS_CACHE, 'a',
209
-				$query->expr()->andX(
210
-					$query->expr()->eq('r.resource_id', 'a.resource_id'),
211
-					$query->expr()->eq('r.resource_type', 'a.resource_type'),
212
-					$query->expr()->eq('a.user_id', $query->createNamedParameter($userId, IQueryBuilder::PARAM_STR))
213
-				)
214
-			)
215
-			->where($query->expr()->eq('r.resource_type', $query->createNamedParameter($type, IQueryBuilder::PARAM_STR)))
216
-			->andWhere($query->expr()->eq('r.resource_id', $query->createNamedParameter($id, IQueryBuilder::PARAM_STR)));
217
-		$result = $query->execute();
218
-		$row = $result->fetch();
219
-		$result->closeCursor();
220
-
221
-		if (!$row) {
222
-			throw new ResourceException('Resource not found');
223
-		}
224
-
225
-		$access = $row['access'] === null ? null : (bool) $row['access'];
226
-		if ($user instanceof IUser) {
227
-			return new Resource($this, $this->connection, $type, $id, $user, $access);
228
-		}
229
-
230
-		return new Resource($this, $this->connection, $type, $id, null, $access);
231
-	}
232
-
233
-	/**
234
-	 * @param ICollection $collection
235
-	 * @param IUser|null $user
236
-	 * @return IResource[]
237
-	 * @since 16.0.0
238
-	 */
239
-	public function getResourcesByCollectionForUser(ICollection $collection, ?IUser $user): array {
240
-		$query = $this->connection->getQueryBuilder();
241
-		$userId = $user instanceof IUser ? $user->getUID() : '';
242
-
243
-		$query->select('r.*', 'a.access')
244
-			->from(self::TABLE_RESOURCES, 'r')
245
-			->leftJoin(
246
-				'r', self::TABLE_ACCESS_CACHE, 'a',
247
-				$query->expr()->andX(
248
-					$query->expr()->eq('r.resource_id', 'a.resource_id'),
249
-					$query->expr()->eq('r.resource_type', 'a.resource_type'),
250
-					$query->expr()->eq('a.user_id', $query->createNamedParameter($userId, IQueryBuilder::PARAM_STR))
251
-				)
252
-			)
253
-			->where($query->expr()->eq('r.collection_id', $query->createNamedParameter($collection->getId(), IQueryBuilder::PARAM_INT)));
254
-
255
-		$resources = [];
256
-		$result = $query->execute();
257
-		while ($row = $result->fetch()) {
258
-			$access = $row['access'] === null ? null : (bool) $row['access'];
259
-			$resources[] = new Resource($this, $this->connection, $row['resource_type'], $row['resource_id'], $user, $access);
260
-		}
261
-		$result->closeCursor();
262
-
263
-		return $resources;
264
-	}
265
-
266
-	/**
267
-	 * @return IProvider[]
268
-	 * @since 16.0.0
269
-	 */
270
-	public function getProviders(): array {
271
-		if (!empty($this->providers)) {
272
-			foreach ($this->providers as $provider) {
273
-				try {
274
-					$this->providerInstances[] = \OC::$server->query($provider);
275
-				} catch (QueryException $e) {
276
-					$this->logger->logException($e, [
277
-						'message' => 'Error when instantiating resource provider'
278
-					]);
279
-				}
280
-			}
281
-			$this->providers = [];
282
-		}
283
-
284
-		return $this->providerInstances;
285
-	}
286
-
287
-	/**
288
-	 * Get the rich object data of a resource
289
-	 *
290
-	 * @param IResource $resource
291
-	 * @return array
292
-	 * @since 16.0.0
293
-	 */
294
-	public function getResourceRichObject(IResource $resource): array {
295
-		foreach ($this->getProviders() as $provider) {
296
-			if ($provider->getType() === $resource->getType()) {
297
-				try {
298
-					return $provider->getResourceRichObject($resource);
299
-				} catch (ResourceException $e) {
300
-				}
301
-			}
302
-		}
303
-
304
-		return [];
305
-	}
306
-
307
-	/**
308
-	 * Can a user/guest access the collection
309
-	 *
310
-	 * @param IResource $resource
311
-	 * @param IUser|null $user
312
-	 * @return bool
313
-	 * @since 16.0.0
314
-	 */
315
-	public function canAccessResource(IResource $resource, ?IUser $user): bool {
316
-		$access = $this->checkAccessCacheForUserByResource($resource, $user);
317
-		if (\is_bool($access)) {
318
-			return $access;
319
-		}
320
-
321
-		$access = false;
322
-		foreach ($this->getProviders() as $provider) {
323
-			if ($provider->getType() === $resource->getType()) {
324
-				try {
325
-					if ($provider->canAccessResource($resource, $user)) {
326
-						$access = true;
327
-						break;
328
-					}
329
-				} catch (ResourceException $e) {
330
-				}
331
-			}
332
-		}
333
-
334
-		$this->cacheAccessForResource($resource, $user, $access);
335
-		return $access;
336
-	}
337
-
338
-	/**
339
-	 * Can a user/guest access the collection
340
-	 *
341
-	 * @param ICollection $collection
342
-	 * @param IUser|null $user
343
-	 * @return bool
344
-	 * @since 16.0.0
345
-	 */
346
-	public function canAccessCollection(ICollection $collection, ?IUser $user): bool {
347
-		$access = $this->checkAccessCacheForUserByCollection($collection, $user);
348
-		if (\is_bool($access)) {
349
-			return $access;
350
-		}
351
-
352
-		$access = false;
353
-		foreach ($collection->getResources() as $resource) {
354
-			if ($resource->canAccess($user)) {
355
-				$access = true;
356
-				break;
357
-			}
358
-		}
359
-
360
-		$this->cacheAccessForCollection($collection, $user, $access);
361
-		return $access;
362
-	}
363
-
364
-	protected function checkAccessCacheForUserByResource(IResource $resource, ?IUser $user): ?bool {
365
-		$query = $this->connection->getQueryBuilder();
366
-		$userId = $user instanceof IUser ? $user->getUID() : '';
367
-
368
-		$query->select('access')
369
-			->from(self::TABLE_ACCESS_CACHE)
370
-			->where($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId(), IQueryBuilder::PARAM_STR)))
371
-			->andWhere($query->expr()->eq('resource_type', $query->createNamedParameter($resource->getType(), IQueryBuilder::PARAM_STR)))
372
-			->andWhere($query->expr()->eq('user_id', $query->createNamedParameter($userId, IQueryBuilder::PARAM_STR)))
373
-			->setMaxResults(1);
374
-
375
-		$hasAccess = null;
376
-		$result = $query->execute();
377
-		if ($row = $result->fetch()) {
378
-			$hasAccess = (bool) $row['access'];
379
-		}
380
-		$result->closeCursor();
381
-
382
-		return $hasAccess;
383
-	}
384
-
385
-	protected function checkAccessCacheForUserByCollection(ICollection $collection, ?IUser $user): ?bool {
386
-		$query = $this->connection->getQueryBuilder();
387
-		$userId = $user instanceof IUser ? $user->getUID() : '';
388
-
389
-		$query->select('access')
390
-			->from(self::TABLE_ACCESS_CACHE)
391
-			->where($query->expr()->eq('collection_id', $query->createNamedParameter($collection->getId(), IQueryBuilder::PARAM_INT)))
392
-			->andWhere($query->expr()->eq('user_id', $query->createNamedParameter($userId, IQueryBuilder::PARAM_STR)))
393
-			->setMaxResults(1);
394
-
395
-		$hasAccess = null;
396
-		$result = $query->execute();
397
-		if ($row = $result->fetch()) {
398
-			$hasAccess = (bool) $row['access'];
399
-		}
400
-		$result->closeCursor();
401
-
402
-		return $hasAccess;
403
-	}
404
-
405
-	public function cacheAccessForResource(IResource $resource, ?IUser $user, bool $access): void {
406
-		$query = $this->connection->getQueryBuilder();
407
-		$userId = $user instanceof IUser ? $user->getUID() : '';
408
-
409
-		$query->insert(self::TABLE_ACCESS_CACHE)
410
-			->values([
411
-				'user_id' => $query->createNamedParameter($userId),
412
-				'resource_id' => $query->createNamedParameter($resource->getId()),
413
-				'resource_type' => $query->createNamedParameter($resource->getType()),
414
-				'access' => $query->createNamedParameter($access, IQueryBuilder::PARAM_BOOL),
415
-			]);
416
-		try {
417
-			$query->execute();
418
-		} catch (UniqueConstraintViolationException $e) {
419
-		}
420
-	}
421
-
422
-	public function cacheAccessForCollection(ICollection $collection, ?IUser $user, bool $access): void {
423
-		$query = $this->connection->getQueryBuilder();
424
-		$userId = $user instanceof IUser ? $user->getUID() : '';
425
-
426
-		$query->insert(self::TABLE_ACCESS_CACHE)
427
-			->values([
428
-				'user_id' => $query->createNamedParameter($userId),
429
-				'collection_id' => $query->createNamedParameter($collection->getId()),
430
-				'access' => $query->createNamedParameter($access),
431
-			]);
432
-		try {
433
-			$query->execute();
434
-		} catch (UniqueConstraintViolationException $e) {
435
-		}
436
-	}
437
-
438
-	public function invalidateAccessCacheForUser(?IUser $user): void {
439
-		$query = $this->connection->getQueryBuilder();
440
-		$userId = $user instanceof IUser ? $user->getUID() : '';
441
-
442
-		$query->delete(self::TABLE_ACCESS_CACHE)
443
-			->where($query->expr()->eq('user_id', $query->createNamedParameter($userId)));
444
-		$query->execute();
445
-	}
446
-
447
-	public function invalidateAccessCacheForResource(IResource $resource): void {
448
-		$query = $this->connection->getQueryBuilder();
449
-
450
-		$query->delete(self::TABLE_ACCESS_CACHE)
451
-			->where($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId())))
452
-			->andWhere($query->expr()->eq('resource_type', $query->createNamedParameter($resource->getType(), IQueryBuilder::PARAM_STR)));
453
-		$query->execute();
454
-
455
-		foreach ($resource->getCollections() as $collection) {
456
-			$this->invalidateAccessCacheForCollection($collection);
457
-		}
458
-	}
459
-
460
-	public function invalidateAccessCacheForCollection(ICollection $collection): void {
461
-		$query = $this->connection->getQueryBuilder();
462
-
463
-		$query->delete(self::TABLE_ACCESS_CACHE)
464
-			->where($query->expr()->eq('collection_id', $query->createNamedParameter($collection->getId())));
465
-		$query->execute();
466
-	}
467
-
468
-	public function invalidateAccessCacheForProvider(IProvider $provider): void {
469
-		$query = $this->connection->getQueryBuilder();
470
-
471
-		$query->delete(self::TABLE_ACCESS_CACHE)
472
-			->where($query->expr()->eq('resource_type', $query->createNamedParameter($provider->getType(), IQueryBuilder::PARAM_STR)));
473
-		$query->execute();
474
-	}
475
-
476
-	public function invalidateAccessCacheForResourceByUser(IResource $resource, ?IUser $user): void {
477
-		$query = $this->connection->getQueryBuilder();
478
-		$userId = $user instanceof IUser ? $user->getUID() : '';
479
-
480
-		$query->delete(self::TABLE_ACCESS_CACHE)
481
-			->where($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId())))
482
-			->andWhere($query->expr()->eq('user_id', $query->createNamedParameter($userId)));
483
-		$query->execute();
484
-
485
-		foreach ($resource->getCollections() as $collection) {
486
-			$this->invalidateAccessCacheForCollectionByUser($collection, $user);
487
-		}
488
-	}
489
-
490
-	protected function invalidateAccessCacheForCollectionByUser(ICollection $collection, ?IUser $user): void {
491
-		$query = $this->connection->getQueryBuilder();
492
-		$userId = $user instanceof IUser ? $user->getUID() : '';
493
-
494
-		$query->delete(self::TABLE_ACCESS_CACHE)
495
-			->where($query->expr()->eq('collection_id', $query->createNamedParameter($collection->getId())))
496
-			->andWhere($query->expr()->eq('user_id', $query->createNamedParameter($userId)));
497
-		$query->execute();
498
-	}
499
-
500
-	public function invalidateAccessCacheForProviderByUser(IProvider $provider, ?IUser $user): void {
501
-		$query = $this->connection->getQueryBuilder();
502
-		$userId = $user instanceof IUser ? $user->getUID() : '';
503
-
504
-		$query->delete(self::TABLE_ACCESS_CACHE)
505
-			->where($query->expr()->eq('resource_type', $query->createNamedParameter($provider->getType(), IQueryBuilder::PARAM_STR)))
506
-			->andWhere($query->expr()->eq('user_id', $query->createNamedParameter($userId)));
507
-		$query->execute();
508
-	}
509
-
510
-	/**
511
-	 * @param string $provider
512
-	 */
513
-	public function registerResourceProvider(string $provider): void {
514
-		$this->providers[] = $provider;
515
-	}
516
-
517
-	/**
518
-	 * Get the resource type of the provider
519
-	 *
520
-	 * @return string
521
-	 * @since 16.0.0
522
-	 */
523
-	public function getType(): string {
524
-		return '';
525
-	}
41
+    public const TABLE_COLLECTIONS = 'collres_collections';
42
+    public const TABLE_RESOURCES = 'collres_resources';
43
+    public const TABLE_ACCESS_CACHE = 'collres_accesscache';
44
+
45
+    /** @var IDBConnection */
46
+    protected $connection;
47
+    /** @var ILogger */
48
+    protected $logger;
49
+
50
+    /** @var string[] */
51
+    protected $providers = [];
52
+
53
+    /** @var IProvider[] */
54
+    protected $providerInstances = [];
55
+
56
+    public function __construct(IDBConnection $connection, ILogger $logger) {
57
+        $this->connection = $connection;
58
+        $this->logger = $logger;
59
+    }
60
+
61
+    /**
62
+     * @param int $id
63
+     * @return ICollection
64
+     * @throws CollectionException when the collection could not be found
65
+     * @since 16.0.0
66
+     */
67
+    public function getCollection(int $id): ICollection {
68
+        $query = $this->connection->getQueryBuilder();
69
+        $query->select('*')
70
+            ->from(self::TABLE_COLLECTIONS)
71
+            ->where($query->expr()->eq('id', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
72
+        $result = $query->execute();
73
+        $row = $result->fetch();
74
+        $result->closeCursor();
75
+
76
+        if (!$row) {
77
+            throw new CollectionException('Collection not found');
78
+        }
79
+
80
+        return new Collection($this, $this->connection, (int) $row['id'], (string) $row['name']);
81
+    }
82
+
83
+    /**
84
+     * @param int $id
85
+     * @param IUser|null $user
86
+     * @return ICollection
87
+     * @throws CollectionException when the collection could not be found
88
+     * @since 16.0.0
89
+     */
90
+    public function getCollectionForUser(int $id, ?IUser $user): ICollection {
91
+        $query = $this->connection->getQueryBuilder();
92
+        $userId = $user instanceof IUser ? $user->getUID() : '';
93
+
94
+        $query->select('*')
95
+            ->from(self::TABLE_COLLECTIONS, 'c')
96
+            ->leftJoin(
97
+                'c', self::TABLE_ACCESS_CACHE, 'a',
98
+                $query->expr()->andX(
99
+                    $query->expr()->eq('c.id', 'a.collection_id'),
100
+                    $query->expr()->eq('a.user_id', $query->createNamedParameter($userId, IQueryBuilder::PARAM_STR))
101
+                )
102
+            )
103
+            ->where($query->expr()->eq('c.id', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
104
+        $result = $query->execute();
105
+        $row = $result->fetch();
106
+        $result->closeCursor();
107
+
108
+        if (!$row) {
109
+            throw new CollectionException('Collection not found');
110
+        }
111
+
112
+        $access = $row['access'] === null ? null : (bool) $row['access'];
113
+        if ($user instanceof IUser) {
114
+            return new Collection($this, $this->connection, (int) $row['id'], (string) $row['name'], $user, $access);
115
+        }
116
+
117
+        return new Collection($this, $this->connection, (int) $row['id'], (string) $row['name'], $user, $access);
118
+    }
119
+
120
+    /**
121
+     * @param IUser $user
122
+     * @param string $filter
123
+     * @param int $limit
124
+     * @param int $start
125
+     * @return ICollection[]
126
+     * @since 16.0.0
127
+     */
128
+    public function searchCollections(IUser $user, string $filter, int $limit = 50, int $start = 0): array {
129
+        $query = $this->connection->getQueryBuilder();
130
+        $userId = $user instanceof IUser ? $user->getUID() : '';
131
+
132
+        $query->select('c.*', 'a.access')
133
+            ->from(self::TABLE_COLLECTIONS, 'c')
134
+            ->leftJoin(
135
+                'c', self::TABLE_ACCESS_CACHE, 'a',
136
+                $query->expr()->andX(
137
+                    $query->expr()->eq('c.id', 'a.collection_id'),
138
+                    $query->expr()->eq('a.user_id', $query->createNamedParameter($userId, IQueryBuilder::PARAM_STR))
139
+                )
140
+            )
141
+            ->where($query->expr()->iLike('c.name', $query->createNamedParameter($filter, IQueryBuilder::PARAM_STR)))
142
+            ->andWhere($query->expr()->eq('a.access', $query->createNamedParameter(1, IQueryBuilder::PARAM_INT)))
143
+            ->orderBy('c.id')
144
+            ->setMaxResults($limit)
145
+            ->setFirstResult($start);
146
+        $result = $query->execute();
147
+        $collections = [];
148
+
149
+        $foundResults = 0;
150
+        while ($row = $result->fetch()) {
151
+            $foundResults++;
152
+            $access = $row['access'] === null ? null : (bool) $row['access'];
153
+            $collection = new Collection($this, $this->connection, (int)$row['id'], (string)$row['name'], $user, $access);
154
+            if ($collection->canAccess($user)) {
155
+                $collections[] = $collection;
156
+            }
157
+        }
158
+        $result->closeCursor();
159
+
160
+        if (empty($collections) && $foundResults === $limit) {
161
+            $this->searchCollections($user, $filter, $limit, $start + $limit);
162
+        }
163
+
164
+        return $collections;
165
+    }
166
+
167
+    /**
168
+     * @param string $name
169
+     * @return ICollection
170
+     * @since 16.0.0
171
+     */
172
+    public function newCollection(string $name): ICollection {
173
+        $query = $this->connection->getQueryBuilder();
174
+        $query->insert(self::TABLE_COLLECTIONS)
175
+            ->values([
176
+                'name' => $query->createNamedParameter($name),
177
+            ]);
178
+        $query->execute();
179
+
180
+        return new Collection($this, $this->connection, $query->getLastInsertId(), $name);
181
+    }
182
+
183
+    /**
184
+     * @param string $type
185
+     * @param string $id
186
+     * @return IResource
187
+     * @since 16.0.0
188
+     */
189
+    public function createResource(string $type, string $id): IResource {
190
+        return new Resource($this, $this->connection, $type, $id);
191
+    }
192
+
193
+    /**
194
+     * @param string $type
195
+     * @param string $id
196
+     * @param IUser|null $user
197
+     * @return IResource
198
+     * @throws ResourceException
199
+     * @since 16.0.0
200
+     */
201
+    public function getResourceForUser(string $type, string $id, ?IUser $user): IResource {
202
+        $query = $this->connection->getQueryBuilder();
203
+        $userId = $user instanceof IUser ? $user->getUID() : '';
204
+
205
+        $query->select('r.*', 'a.access')
206
+            ->from(self::TABLE_RESOURCES, 'r')
207
+            ->leftJoin(
208
+                'r', self::TABLE_ACCESS_CACHE, 'a',
209
+                $query->expr()->andX(
210
+                    $query->expr()->eq('r.resource_id', 'a.resource_id'),
211
+                    $query->expr()->eq('r.resource_type', 'a.resource_type'),
212
+                    $query->expr()->eq('a.user_id', $query->createNamedParameter($userId, IQueryBuilder::PARAM_STR))
213
+                )
214
+            )
215
+            ->where($query->expr()->eq('r.resource_type', $query->createNamedParameter($type, IQueryBuilder::PARAM_STR)))
216
+            ->andWhere($query->expr()->eq('r.resource_id', $query->createNamedParameter($id, IQueryBuilder::PARAM_STR)));
217
+        $result = $query->execute();
218
+        $row = $result->fetch();
219
+        $result->closeCursor();
220
+
221
+        if (!$row) {
222
+            throw new ResourceException('Resource not found');
223
+        }
224
+
225
+        $access = $row['access'] === null ? null : (bool) $row['access'];
226
+        if ($user instanceof IUser) {
227
+            return new Resource($this, $this->connection, $type, $id, $user, $access);
228
+        }
229
+
230
+        return new Resource($this, $this->connection, $type, $id, null, $access);
231
+    }
232
+
233
+    /**
234
+     * @param ICollection $collection
235
+     * @param IUser|null $user
236
+     * @return IResource[]
237
+     * @since 16.0.0
238
+     */
239
+    public function getResourcesByCollectionForUser(ICollection $collection, ?IUser $user): array {
240
+        $query = $this->connection->getQueryBuilder();
241
+        $userId = $user instanceof IUser ? $user->getUID() : '';
242
+
243
+        $query->select('r.*', 'a.access')
244
+            ->from(self::TABLE_RESOURCES, 'r')
245
+            ->leftJoin(
246
+                'r', self::TABLE_ACCESS_CACHE, 'a',
247
+                $query->expr()->andX(
248
+                    $query->expr()->eq('r.resource_id', 'a.resource_id'),
249
+                    $query->expr()->eq('r.resource_type', 'a.resource_type'),
250
+                    $query->expr()->eq('a.user_id', $query->createNamedParameter($userId, IQueryBuilder::PARAM_STR))
251
+                )
252
+            )
253
+            ->where($query->expr()->eq('r.collection_id', $query->createNamedParameter($collection->getId(), IQueryBuilder::PARAM_INT)));
254
+
255
+        $resources = [];
256
+        $result = $query->execute();
257
+        while ($row = $result->fetch()) {
258
+            $access = $row['access'] === null ? null : (bool) $row['access'];
259
+            $resources[] = new Resource($this, $this->connection, $row['resource_type'], $row['resource_id'], $user, $access);
260
+        }
261
+        $result->closeCursor();
262
+
263
+        return $resources;
264
+    }
265
+
266
+    /**
267
+     * @return IProvider[]
268
+     * @since 16.0.0
269
+     */
270
+    public function getProviders(): array {
271
+        if (!empty($this->providers)) {
272
+            foreach ($this->providers as $provider) {
273
+                try {
274
+                    $this->providerInstances[] = \OC::$server->query($provider);
275
+                } catch (QueryException $e) {
276
+                    $this->logger->logException($e, [
277
+                        'message' => 'Error when instantiating resource provider'
278
+                    ]);
279
+                }
280
+            }
281
+            $this->providers = [];
282
+        }
283
+
284
+        return $this->providerInstances;
285
+    }
286
+
287
+    /**
288
+     * Get the rich object data of a resource
289
+     *
290
+     * @param IResource $resource
291
+     * @return array
292
+     * @since 16.0.0
293
+     */
294
+    public function getResourceRichObject(IResource $resource): array {
295
+        foreach ($this->getProviders() as $provider) {
296
+            if ($provider->getType() === $resource->getType()) {
297
+                try {
298
+                    return $provider->getResourceRichObject($resource);
299
+                } catch (ResourceException $e) {
300
+                }
301
+            }
302
+        }
303
+
304
+        return [];
305
+    }
306
+
307
+    /**
308
+     * Can a user/guest access the collection
309
+     *
310
+     * @param IResource $resource
311
+     * @param IUser|null $user
312
+     * @return bool
313
+     * @since 16.0.0
314
+     */
315
+    public function canAccessResource(IResource $resource, ?IUser $user): bool {
316
+        $access = $this->checkAccessCacheForUserByResource($resource, $user);
317
+        if (\is_bool($access)) {
318
+            return $access;
319
+        }
320
+
321
+        $access = false;
322
+        foreach ($this->getProviders() as $provider) {
323
+            if ($provider->getType() === $resource->getType()) {
324
+                try {
325
+                    if ($provider->canAccessResource($resource, $user)) {
326
+                        $access = true;
327
+                        break;
328
+                    }
329
+                } catch (ResourceException $e) {
330
+                }
331
+            }
332
+        }
333
+
334
+        $this->cacheAccessForResource($resource, $user, $access);
335
+        return $access;
336
+    }
337
+
338
+    /**
339
+     * Can a user/guest access the collection
340
+     *
341
+     * @param ICollection $collection
342
+     * @param IUser|null $user
343
+     * @return bool
344
+     * @since 16.0.0
345
+     */
346
+    public function canAccessCollection(ICollection $collection, ?IUser $user): bool {
347
+        $access = $this->checkAccessCacheForUserByCollection($collection, $user);
348
+        if (\is_bool($access)) {
349
+            return $access;
350
+        }
351
+
352
+        $access = false;
353
+        foreach ($collection->getResources() as $resource) {
354
+            if ($resource->canAccess($user)) {
355
+                $access = true;
356
+                break;
357
+            }
358
+        }
359
+
360
+        $this->cacheAccessForCollection($collection, $user, $access);
361
+        return $access;
362
+    }
363
+
364
+    protected function checkAccessCacheForUserByResource(IResource $resource, ?IUser $user): ?bool {
365
+        $query = $this->connection->getQueryBuilder();
366
+        $userId = $user instanceof IUser ? $user->getUID() : '';
367
+
368
+        $query->select('access')
369
+            ->from(self::TABLE_ACCESS_CACHE)
370
+            ->where($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId(), IQueryBuilder::PARAM_STR)))
371
+            ->andWhere($query->expr()->eq('resource_type', $query->createNamedParameter($resource->getType(), IQueryBuilder::PARAM_STR)))
372
+            ->andWhere($query->expr()->eq('user_id', $query->createNamedParameter($userId, IQueryBuilder::PARAM_STR)))
373
+            ->setMaxResults(1);
374
+
375
+        $hasAccess = null;
376
+        $result = $query->execute();
377
+        if ($row = $result->fetch()) {
378
+            $hasAccess = (bool) $row['access'];
379
+        }
380
+        $result->closeCursor();
381
+
382
+        return $hasAccess;
383
+    }
384
+
385
+    protected function checkAccessCacheForUserByCollection(ICollection $collection, ?IUser $user): ?bool {
386
+        $query = $this->connection->getQueryBuilder();
387
+        $userId = $user instanceof IUser ? $user->getUID() : '';
388
+
389
+        $query->select('access')
390
+            ->from(self::TABLE_ACCESS_CACHE)
391
+            ->where($query->expr()->eq('collection_id', $query->createNamedParameter($collection->getId(), IQueryBuilder::PARAM_INT)))
392
+            ->andWhere($query->expr()->eq('user_id', $query->createNamedParameter($userId, IQueryBuilder::PARAM_STR)))
393
+            ->setMaxResults(1);
394
+
395
+        $hasAccess = null;
396
+        $result = $query->execute();
397
+        if ($row = $result->fetch()) {
398
+            $hasAccess = (bool) $row['access'];
399
+        }
400
+        $result->closeCursor();
401
+
402
+        return $hasAccess;
403
+    }
404
+
405
+    public function cacheAccessForResource(IResource $resource, ?IUser $user, bool $access): void {
406
+        $query = $this->connection->getQueryBuilder();
407
+        $userId = $user instanceof IUser ? $user->getUID() : '';
408
+
409
+        $query->insert(self::TABLE_ACCESS_CACHE)
410
+            ->values([
411
+                'user_id' => $query->createNamedParameter($userId),
412
+                'resource_id' => $query->createNamedParameter($resource->getId()),
413
+                'resource_type' => $query->createNamedParameter($resource->getType()),
414
+                'access' => $query->createNamedParameter($access, IQueryBuilder::PARAM_BOOL),
415
+            ]);
416
+        try {
417
+            $query->execute();
418
+        } catch (UniqueConstraintViolationException $e) {
419
+        }
420
+    }
421
+
422
+    public function cacheAccessForCollection(ICollection $collection, ?IUser $user, bool $access): void {
423
+        $query = $this->connection->getQueryBuilder();
424
+        $userId = $user instanceof IUser ? $user->getUID() : '';
425
+
426
+        $query->insert(self::TABLE_ACCESS_CACHE)
427
+            ->values([
428
+                'user_id' => $query->createNamedParameter($userId),
429
+                'collection_id' => $query->createNamedParameter($collection->getId()),
430
+                'access' => $query->createNamedParameter($access),
431
+            ]);
432
+        try {
433
+            $query->execute();
434
+        } catch (UniqueConstraintViolationException $e) {
435
+        }
436
+    }
437
+
438
+    public function invalidateAccessCacheForUser(?IUser $user): void {
439
+        $query = $this->connection->getQueryBuilder();
440
+        $userId = $user instanceof IUser ? $user->getUID() : '';
441
+
442
+        $query->delete(self::TABLE_ACCESS_CACHE)
443
+            ->where($query->expr()->eq('user_id', $query->createNamedParameter($userId)));
444
+        $query->execute();
445
+    }
446
+
447
+    public function invalidateAccessCacheForResource(IResource $resource): void {
448
+        $query = $this->connection->getQueryBuilder();
449
+
450
+        $query->delete(self::TABLE_ACCESS_CACHE)
451
+            ->where($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId())))
452
+            ->andWhere($query->expr()->eq('resource_type', $query->createNamedParameter($resource->getType(), IQueryBuilder::PARAM_STR)));
453
+        $query->execute();
454
+
455
+        foreach ($resource->getCollections() as $collection) {
456
+            $this->invalidateAccessCacheForCollection($collection);
457
+        }
458
+    }
459
+
460
+    public function invalidateAccessCacheForCollection(ICollection $collection): void {
461
+        $query = $this->connection->getQueryBuilder();
462
+
463
+        $query->delete(self::TABLE_ACCESS_CACHE)
464
+            ->where($query->expr()->eq('collection_id', $query->createNamedParameter($collection->getId())));
465
+        $query->execute();
466
+    }
467
+
468
+    public function invalidateAccessCacheForProvider(IProvider $provider): void {
469
+        $query = $this->connection->getQueryBuilder();
470
+
471
+        $query->delete(self::TABLE_ACCESS_CACHE)
472
+            ->where($query->expr()->eq('resource_type', $query->createNamedParameter($provider->getType(), IQueryBuilder::PARAM_STR)));
473
+        $query->execute();
474
+    }
475
+
476
+    public function invalidateAccessCacheForResourceByUser(IResource $resource, ?IUser $user): void {
477
+        $query = $this->connection->getQueryBuilder();
478
+        $userId = $user instanceof IUser ? $user->getUID() : '';
479
+
480
+        $query->delete(self::TABLE_ACCESS_CACHE)
481
+            ->where($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId())))
482
+            ->andWhere($query->expr()->eq('user_id', $query->createNamedParameter($userId)));
483
+        $query->execute();
484
+
485
+        foreach ($resource->getCollections() as $collection) {
486
+            $this->invalidateAccessCacheForCollectionByUser($collection, $user);
487
+        }
488
+    }
489
+
490
+    protected function invalidateAccessCacheForCollectionByUser(ICollection $collection, ?IUser $user): void {
491
+        $query = $this->connection->getQueryBuilder();
492
+        $userId = $user instanceof IUser ? $user->getUID() : '';
493
+
494
+        $query->delete(self::TABLE_ACCESS_CACHE)
495
+            ->where($query->expr()->eq('collection_id', $query->createNamedParameter($collection->getId())))
496
+            ->andWhere($query->expr()->eq('user_id', $query->createNamedParameter($userId)));
497
+        $query->execute();
498
+    }
499
+
500
+    public function invalidateAccessCacheForProviderByUser(IProvider $provider, ?IUser $user): void {
501
+        $query = $this->connection->getQueryBuilder();
502
+        $userId = $user instanceof IUser ? $user->getUID() : '';
503
+
504
+        $query->delete(self::TABLE_ACCESS_CACHE)
505
+            ->where($query->expr()->eq('resource_type', $query->createNamedParameter($provider->getType(), IQueryBuilder::PARAM_STR)))
506
+            ->andWhere($query->expr()->eq('user_id', $query->createNamedParameter($userId)));
507
+        $query->execute();
508
+    }
509
+
510
+    /**
511
+     * @param string $provider
512
+     */
513
+    public function registerResourceProvider(string $provider): void {
514
+        $this->providers[] = $provider;
515
+    }
516
+
517
+    /**
518
+     * Get the resource type of the provider
519
+     *
520
+     * @return string
521
+     * @since 16.0.0
522
+     */
523
+    public function getType(): string {
524
+        return '';
525
+    }
526 526
 }
Please login to merge, or discard this patch.