Passed
Pull Request — master (#1254)
by René
04:14
created

Acl::getUserIsInvolved()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 5
c 1
b 1
f 0
dl 0
loc 6
ccs 0
cts 3
cp 0
rs 10
cc 4
nc 4
nop 0
crap 20
1
<?php
2
/**
3
 * @copyright Copyright (c) 2017 Vinzenz Rosenkranz <[email protected]>
4
 *
5
 * @author René Gieling <[email protected]>
6
 *
7
 * @license GNU AGPL version 3 or any later version
8
 *
9
 *  This program is free software: you can redistribute it and/or modify
10
 *  it under the terms of the GNU Affero General Public License as
11
 *  published by the Free Software Foundation, either version 3 of the
12
 *  License, or (at your option) any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU Affero General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU Affero General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 *
22
 */
23
24
25
namespace OCA\Polls\Model;
26
27
use JsonSerializable;
28
use OCP\AppFramework\Db\DoesNotExistException;
29
use OCA\Polls\Exceptions\NotAuthorizedException;
30
31
use OCP\IUserManager;
32
use OCP\IGroupManager;
33
use OCA\Polls\Db\Poll;
34
use OCA\Polls\Db\Share;
35
use OCA\Polls\Db\PollMapper;
36
use OCA\Polls\Db\VoteMapper;
37
use OCA\Polls\Db\ShareMapper;
38
39
/**
40
 * Class Acl
41
 *
42
 * @package OCA\Polls\Model\Acl
43
 */
44
class Acl implements JsonSerializable {
45
46
	/** @var IUserManager */
47
	private $userManager;
48
49
	/** @var IGroupManager */
50
	private $groupManager;
51
52
	/** @var PollMapper */
53
	private $pollMapper;
54
55
	/** @var VoteMapper */
56
	private $voteMapper;
57
58
	/** @var ShareMapper */
59
	private $shareMapper;
60
61
	/** @var Poll */
62
	private $poll;
63
64
	/** @var Share */
65
	private $share;
66
67
	/**
68
	 * Acl constructor.
69
	 * @param IUserManager $userManager
70
	 * @param IGroupManager $groupManager
71
	 * @param PollMapper $pollMapper
72
	 * @param VoteMapper $voteMapper
73
	 * @param ShareMapper $shareMapper
74
	 *
75
	 */
76
	public function __construct(
77
		IUserManager $userManager,
78
		IGroupManager $groupManager,
79
		PollMapper $pollMapper,
80
		VoteMapper $voteMapper,
81
		ShareMapper $shareMapper
82
	) {
83
		$this->userManager = $userManager;
84
		$this->groupManager = $groupManager;
85
		$this->pollMapper = $pollMapper;
86
		$this->voteMapper = $voteMapper;
87
		$this->shareMapper = $shareMapper;
88
		$this->poll = new Poll;
89
		$this->share = new Share;
90
	}
91
92
	/**
93
	 * set
94
	 * @return self
95
	 * @throws NotAuthorizedException
96
	 */
97
	public function set($pollId = 0, $token = ''): Acl {
98
		if ($token) {
99
			$pollId = $this->setToken($token);
100
		}
101
102
		try {
103
			$this->poll = $this->pollMapper->find($pollId);
104
		} catch (DoesNotExistException $e) {
105
			throw new NotAuthorizedException;
106
		}
107
108
		return $this;
109
	}
110
111
	/**
112
	 * getUserId
113
	 * @return string
114
	 */
115
	public function getUserId() {
116
		if ($this->getLoggedIn()) {
117
			return \OC::$server->getUserSession()->getUser()->getUID();
118
		} else {
119
			return $this->share->getUserId();
120
		}
121
	}
122
123
	/**
124
	 * getDisplayName
125
	 * @return string
126
	 */
127
	private function getDisplayName() {
128
		if ($this->getLoggedIn()) {
129
			return $this->userManager->get($this->getUserId())->getDisplayName();
130
		} else {
131
			return $this->share->getDisplayName();
132
		}
133
	}
134
135
	/**
136
	 * getPollId
137
	 * @return int
138
	 */
139
	public function getPollId(): int {
140
		return $this->poll->getId();
141
	}
142
143
	/**
144
	 * getAllowView
145
	 * @return bool
146
	 */
147
	public function getAllowView(): bool {
148
		return (
149
			   $this->getAllowEdit()
150
			|| !$this->poll->getDeleted() && (
151
				   $this->getUserIsInvolved()
152
				|| $this->getPublicShare()
153
				|| ($this->poll->getAccess() === Poll::ACCESS_PUBLIC)
154
			)
155
		);
156
	}
157
158
	/**
159
	 * getAllowVote
160
	 * @return bool
161
	 */
162
	public function getAllowVote(): bool {
163
		return ($this->getAllowView() || $this->getToken())
164
			&& !$this->poll->getExpired()
165
			&& !$this->poll->getDeleted()
166
			&& $this->getUserId();
167
	}
168
169
	/**
170
	 * getAllowSubscribe
171
	 * @return bool
172
	 */
173
	public function getAllowSubscribe(): bool {
174
		return ($this->hasEmail())
175
			&& !$this->poll->getDeleted()
176
			&& $this->getAllowView();
177
	}
178
179
	/**
180
	 * getAllowComment
181
	 * @return bool
182
	 */
183
	public function getAllowComment(): bool {
184
		return !$this->poll->getDeleted() && $this->getUserId();
185
	}
186
187
	/**
188
	 * getAllowEdit
189
	 * @return bool
190
	 */
191
	public function getAllowEdit(): bool {
192
		return ($this->getIsOwner() || $this->getIsAdmin());
193
	}
194
195
	/**
196
	 * getAllowSeeResults
197
	 * @return bool
198
	 */
199
	public function getAllowSeeResults(): bool {
200
		return $this->poll->getShowResults() === Poll::SHOW_RESULTS_ALWAYS
201
			|| ($this->poll->getShowResults() === 'expired' && $this->poll->getExpired())
202
			|| $this->getIsOwner();
203
	}
204
205
	/**
206
	 * getAllowSeeUsernames
207
	 * @return bool
208
	 */
209
	public function getAllowSeeUsernames(): bool {
210
		return !$this->poll->getAnonymous() || $this->getIsOwner();
211
	}
212
213
	/**
214
	 * getToken
215
	 * @return string
216
	 */
217
	public function getToken(): string {
218
		return strval($this->share->getToken());
219
	}
220
221
	/**
222
	 * @return array
223
	 */
224
	public function jsonSerialize(): array {
225
		return	[
226
			'allowComment'      => $this->getAllowComment(),
227
			'allowEdit'         => $this->getAllowEdit(),
228
			'allowSeeResults'   => $this->getAllowSeeResults(),
229
			'allowSeeUsernames' => $this->getAllowSeeUsernames(),
230
			'allowSubscribe'    => $this->getAllowSubscribe(),
231
			'allowView'         => $this->getAllowView(),
232
			'allowVote'         => $this->getAllowVote(),
233
			'displayName'       => $this->getDisplayName(),
234
			'isOwner'           => $this->getIsOwner(),
235
			'loggedIn'			=> $this->getLoggedIn(),
236
			'pollId'            => $this->getPollId(),
237
			'token'             => $this->getToken(),
238
			'userHasVoted'		=> $this->getUserHasVoted(),
239
			'userId'            => $this->getUserId(),
240
			'userIsInvolved'	=> $this->getUserIsInvolved(),
241
		];
242
	}
243
244
	/**
245
	 * setToken
246
	 * @param string $token
247
	 * @return int
248
	 * @throws NotAuthorizedException
249
	 */
250
	private function setToken($token) {
251
		try {
252
			$this->share = $this->shareMapper->findByToken($token);
253
			$this->validateShareAccess();
254
		} catch (DoesNotExistException $e) {
255
			if (!$this->getLoggedIn()) {
256
				// Token is invalid and user is not logged in. Reject
257
				throw new NotAuthorizedException;
258
			}
259
		}
260
		return $this->share->getPollId();
261
	}
262
263
	/**
264
	 * getLoggedIn - Is user logged in to nextcloud?
265
	 * @return string
266
	 */
267
	private function getLoggedIn() {
268
		return \OC::$server->getUserSession()->isLoggedIn();
269
	}
270
271
	/**
272
	 * getIsOwner - Is user owner of the poll?
273
	 * @return bool
274
	 */
275
	private function getIsOwner(): bool {
276
		return ($this->getLoggedIn() && $this->poll->getOwner() === $this->getUserId());
277
	}
278
279
	/**
280
	 * getIsAdmin - Has user administrative rights?
281
	 * Returns true, if user is in admin group and poll has allowed admins to manage the poll
282
	 * @return bool
283
	 */
284
	private function getIsAdmin(): bool {
285
		return ($this->getLoggedIn() && $this->groupManager->isAdmin($this->getUserId()) && $this->poll->getAdminAccess());
286
	}
287
288
	/**
289
	 * getUserIsInvolved - Is user involved?
290
	 * Returns true, if the current user is involved in the share via share or if he is a participant.
291
	 * @return bool
292
	 */
293
	private function getUserIsInvolved(): bool {
294
		return (
295
			   $this->getIsOwner()
296
			|| $this->getUserHasVoted()
297
			|| $this->getGroupShare()
298
			|| $this->getPersonalShare());
299
	}
300
301
	/**
302
	 * getUserHasVoted - Is user a participant?
303
	 * Returns true, if the current user is already a particitipant of the current poll.
304
	 * @return bool
305
	 */
306
	private function getUserHasVoted(): bool {
307
		return count(
308
			$this->voteMapper->findParticipantsVotes($this->getPollId(), $this->getUserId())
309
		) > 0;
310
	}
311
312
	/**
313
	 * getGroupShare - Is the poll shared via group share?
314
	 * Returns true, if the current poll contains a group share with a group,
315
	 * where the current user is member of. This only affects logged users.
316
	 * @return bool
317
	 */
318
	private function getGroupShare(): bool {
319
		if ($this->getLoggedIn()) {
320
			return count(
321
				array_filter($this->shareMapper->findByPoll($this->getPollId()), function ($item) {
322
					if ($item->getType() === Share::TYPE_GROUP && $this->groupManager->isInGroup($this->getUserId(), $item->getUserId())) {
323
						return true;
324
					}
325
				})
326
			);
327
		} else {
328
			return false;
329
		}
330
	}
331
332
	/**
333
	 * getPersonalShare - Is the poll shared via user share?
334
	 * Returns true, if the current poll contains a user share for the current user.
335
	 * This only affects logged users.
336
	 * @return bool
337
	 */
338
	private function getPersonalShare(): bool {
339
		if ($this->getLoggedIn()) {
340
			return count(
341
				array_filter($this->shareMapper->findByPoll($this->getPollId()), function ($item) {
342
					if (in_array($item->getType(), [
343
						Share::TYPE_USER,
344
						Share::TYPE_EXTERNAL,
345
						Share::TYPE_EMAIL,
346
						Share::TYPE_CONTACT
347
					])
348
						&& $item->getUserId() === $this->getUserId()
349
					) {
350
						return true;
351
					}
352
				})
353
			);
354
		} else {
355
			return false;
356
		}
357
	}
358
359
	/**
360
	 * getPublicShare
361
	 * @return bool
362
	 */
363
	private function getPublicShare(): bool {
364
		return count(
365
			array_filter($this->shareMapper->findByPoll($this->getPollId()), function ($item) {
366
				if ($item->getType() === Share::TYPE_PUBLIC && $item->getToken() === $this->getToken()) {
367
					return true;
368
				}
369
			})
370
		);
371
	}
372
373
	/**
374
	 * validateShareAccess
375
	 * @return bool
376
	 * @throws NotAuthorizedException
377
	 */
378
	private function validateShareAccess() {
379
		if ($this->getLoggedIn()) {
380
			if (!$this->getValidAuthenticatedShare()) {
381
				throw new NotAuthorizedException;
382
			};
383
		} else {
384
			if (!$this->getValidPublicShare()) {
385
				throw new NotAuthorizedException;
386
			};
387
		}
388
	}
389
390
	/**
391
	 * getValidPublicShare
392
	 * @return bool
393
	 */
394
	private function getValidPublicShare() {
395
		return in_array($this->share->getType(), [
396
			Share::TYPE_PUBLIC,
397
			Share::TYPE_EMAIL,
398
			Share::TYPE_CONTACT,
399
			Share::TYPE_EXTERNAL
400
		]);
401
	}
402
403
	/**
404
	 * getValidAuthenticatedShare
405
	 * @return bool
406
	 */
407
	private function getValidAuthenticatedShare() {
408
		return in_array($this->share->getType(), [
409
			Share::TYPE_PUBLIC,
410
			Share::TYPE_USER,
411
			Share::TYPE_GROUP
412
		]);
413
	}
414
415
	/**
416
	 * hasEmail
417
	 * @return bool
418
	 */
419
	private function hasEmail():bool {
420
		if ($this->share->getToken()) {
421
			return strlen($this->share->getEmailAddress()) > 0;
422
		} else {
423
			return $this->getLoggedIn();
424
		}
425
	}
426
}
427