Passed
Push — master ( 346770...2398d1 )
by Roeland
10:40 queued 35s
created

Collection::canAccess()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
/**
4
 * @copyright Copyright (c) 2018 Joas Schilling <[email protected]>
5
 *
6
 * @license GNU AGPL version 3 or any later version
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as
10
 * published by the Free Software Foundation, either version 3 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 */
22
23
namespace OC\Collaboration\Resources;
24
25
26
use Doctrine\DBAL\Exception\ConstraintViolationException;
27
use OCP\Collaboration\Resources\IManager;
28
use OCP\Collaboration\Resources\ResourceException;
29
use OCP\Collaboration\Resources\ICollection;
30
use OCP\Collaboration\Resources\IResource;
31
use OCP\DB\QueryBuilder\IQueryBuilder;
32
use OCP\IDBConnection;
33
use OCP\IUser;
34
35
class Collection implements ICollection {
36
37
	/** @var IManager|Manager */
38
	protected $manager;
39
40
	/** @var IDBConnection */
41
	protected $connection;
42
43
	/** @var int */
44
	protected $id;
45
46
	/** @var string */
47
	protected $name;
48
49
	/** @var IUser|null */
50
	protected $userForAccess;
51
52
	/** @var bool|null */
53
	protected $access;
54
55
	/** @var IResource[] */
56
	protected $resources;
57
58
	public function __construct(
59
		IManager $manager,
60
		IDBConnection $connection,
61
		int $id,
62
		string $name,
63
		?IUser $userForAccess = null,
64
		?bool $access = null
65
	) {
66
		$this->manager = $manager;
67
		$this->connection = $connection;
68
		$this->id = $id;
69
		$this->name = $name;
70
		$this->userForAccess = $userForAccess;
71
		$this->access = $access;
72
		$this->resources = [];
73
	}
74
75
	/**
76
	 * @return int
77
	 * @since 16.0.0
78
	 */
79
	public function getId(): int {
80
		return $this->id;
81
	}
82
83
	/**
84
	 * @return string
85
	 * @since 16.0.0
86
	 */
87
	public function getName(): string {
88
		return $this->name;
89
	}
90
91
	/**
92
	 * @param string $name
93
	 * @since 16.0.0
94
	 */
95
	public function setName(string $name): void {
96
		$query = $this->connection->getQueryBuilder();
97
		$query->update(Manager::TABLE_COLLECTIONS)
98
			->set('name', $query->createNamedParameter($name))
99
			->where($query->expr()->eq('id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT)));
100
		$query->execute();
101
102
		$this->name = $name;
103
	}
104
105
	/**
106
	 * @return IResource[]
107
	 * @since 16.0.0
108
	 */
109
	public function getResources(): array {
110
		if (empty($this->resources)) {
111
			$this->resources = $this->manager->getResourcesByCollectionForUser($this, $this->userForAccess);
0 ignored issues
show
Bug introduced by
The method getResourcesByCollectionForUser() does not exist on OCP\Collaboration\Resources\IManager. Since it exists in all sub-types, consider adding an abstract or default implementation to OCP\Collaboration\Resources\IManager. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

111
			/** @scrutinizer ignore-call */ 
112
   $this->resources = $this->manager->getResourcesByCollectionForUser($this, $this->userForAccess);
Loading history...
112
		}
113
114
		return $this->resources;
115
	}
116
117
	/**
118
	 * Adds a resource to a collection
119
	 *
120
	 * @param IResource $resource
121
	 * @throws ResourceException when the resource is already part of the collection
122
	 * @since 16.0.0
123
	 */
124
	public function addResource(IResource $resource): void {
125
		array_map(function(IResource $r) use ($resource) {
126
			if ($this->isSameResource($r, $resource)) {
127
				throw new ResourceException('Already part of the collection');
128
			}
129
		}, $this->getResources());
130
131
		$this->resources[] = $resource;
132
133
		$query = $this->connection->getQueryBuilder();
134
		$query->insert(Manager::TABLE_RESOURCES)
135
			->values([
136
				'collection_id' => $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT),
137
				'resource_type' => $query->createNamedParameter($resource->getType()),
138
				'resource_id' => $query->createNamedParameter($resource->getId()),
139
			]);
140
141
		try {
142
			$query->execute();
143
		} catch (ConstraintViolationException $e) {
144
			throw new ResourceException('Already part of the collection');
145
		}
146
147
		$this->manager->invalidateAccessCacheForCollection($this);
0 ignored issues
show
Bug introduced by
The method invalidateAccessCacheForCollection() does not exist on OCP\Collaboration\Resources\IManager. Did you maybe mean invalidateAccessCacheForUser()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

147
		$this->manager->/** @scrutinizer ignore-call */ 
148
                  invalidateAccessCacheForCollection($this);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
148
	}
149
150
	/**
151
	 * Removes a resource from a collection
152
	 *
153
	 * @param IResource $resource
154
	 * @since 16.0.0
155
	 */
156
	public function removeResource(IResource $resource): void {
157
		$this->resources = array_filter($this->getResources(), function(IResource $r) use ($resource) {
158
			return !$this->isSameResource($r, $resource);
159
		});
160
161
		$query = $this->connection->getQueryBuilder();
162
		$query->delete(Manager::TABLE_RESOURCES)
163
			->where($query->expr()->eq('collection_id', $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT)))
164
			->andWhere($query->expr()->eq('resource_type', $query->createNamedParameter($resource->getType())))
165
			->andWhere($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId())));
166
		$query->execute();
167
168
		if (empty($this->resources)) {
169
			$this->removeCollection();
170
		} else {
171
			$this->manager->invalidateAccessCacheForCollection($this);
172
		}
173
174
	}
175
176
	/**
177
	 * Can a user/guest access the collection
178
	 *
179
	 * @param IUser|null $user
180
	 * @return bool
181
	 * @since 16.0.0
182
	 */
183
	public function canAccess(?IUser $user): bool {
184
		if ($user instanceof IUser) {
185
			return $this->canUserAccess($user);
186
		}
187
		return $this->canGuestAccess();
188
	}
189
190
	protected function canUserAccess(IUser $user): bool {
191
		if (\is_bool($this->access) && $this->userForAccess instanceof IUser && $user->getUID() === $this->userForAccess->getUID()) {
192
			return $this->access;
193
		}
194
195
		$access = $this->manager->canAccessCollection($this, $user);
196
		if ($this->userForAccess instanceof IUser && $user->getUID() === $this->userForAccess->getUID()) {
197
			$this->access = $access;
198
		}
199
		return $access;
200
	}
201
202
	protected function canGuestAccess(): bool {
203
		if (\is_bool($this->access) && !$this->userForAccess instanceof IUser) {
204
			return $this->access;
205
		}
206
207
		$access = $this->manager->canAccessCollection($this, null);
208
		if (!$this->userForAccess instanceof IUser) {
209
			$this->access = $access;
210
		}
211
		return $access;
212
	}
213
214
	protected function isSameResource(IResource $resource1, IResource $resource2): bool {
215
		return $resource1->getType() === $resource2->getType() &&
216
			$resource1->getId() === $resource2->getId();
217
	}
218
219
	protected function removeCollection(): void {
220
		$query = $this->connection->getQueryBuilder();
221
		$query->delete(Manager::TABLE_COLLECTIONS)
222
			->where($query->expr()->eq('id', $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT)));
223
		$query->execute();
224
225
		$this->manager->invalidateAccessCacheForCollection($this);
226
		$this->id = 0;
227
	}
228
}
229