Passed
Pull Request — master (#1320)
by René
07:41 queued 03:42
created

Acl::requestYesVotes()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 3
ccs 0
cts 1
cp 0
rs 10
cc 2
nc 2
nop 0
crap 6
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
use OCA\Polls\Exceptions\VoteLimitExceededException;
31
32
use OCP\IUserManager;
33
use OCP\IGroupManager;
34
use OCA\Polls\Db\Poll;
35
use OCA\Polls\Db\Share;
36
use OCA\Polls\Db\PollMapper;
37
use OCA\Polls\Db\VoteMapper;
38
use OCA\Polls\Db\ShareMapper;
39
40
/**
41
 * Class Acl
42
 *
43
 * @package OCA\Polls\Model\Acl
44
 */
45
class Acl implements JsonSerializable {
46
47
	/** @var IUserManager */
48
	private $userManager;
49
50
	/** @var IGroupManager */
51
	private $groupManager;
52
53
	/** @var PollMapper */
54
	private $pollMapper;
55
56
	/** @var VoteMapper */
57
	private $voteMapper;
58
59
	/** @var ShareMapper */
60
	private $shareMapper;
61
62
	/** @var Poll */
63
	private $poll;
64
65
	/** @var Share */
66
	private $share;
67
68
	public function __construct(
69
		IUserManager $userManager,
70
		IGroupManager $groupManager,
71
		PollMapper $pollMapper,
72
		VoteMapper $voteMapper,
73
		ShareMapper $shareMapper
74
	) {
75
		$this->userManager = $userManager;
76
		$this->groupManager = $groupManager;
77
		$this->pollMapper = $pollMapper;
78
		$this->voteMapper = $voteMapper;
79
		$this->shareMapper = $shareMapper;
80
		$this->poll = new Poll;
81
		$this->share = new Share;
82
	}
83
84
85
	/**
86
	 * load share via token and than call setShare
87
	 */
88
	public function setToken(string $token = ''): Acl {
89
		try {
90
			return $this->setShare($this->shareMapper->findByToken($token));
91
		} catch (DoesNotExistException $e) {
92
			throw new NotAuthorizedException('Error loading share ' . $token);
93
		}
94
	}
95
96
	/**
97
	 * setShare - sets and validates the share
98
	 * read access is
99
	 */
100
	public function setShare(Share $share): Acl {
101
		$this->share = $share;
102
		$this->validateShareAccess();
103
		$this->setPollId($share->getPollId());
104
		$this->requestView();
105
		return $this;
106
	}
107
108
	public function setPollId(int $pollId = 0): Acl {
109
		try {
110
			return $this->setPoll($this->pollMapper->find($pollId));
111
		} catch (DoesNotExistException $e) {
112
			throw new NotAuthorizedException('Error loading poll ' . $pollId);
113
		}
114
	}
115
116
	public function setPoll(Poll $poll): Acl {
117
		$this->poll = $poll;
118
		return $this;
119
	}
120
121
	public function getUserId() {
122
		if ($this->getLoggedIn()) {
123
			return \OC::$server->getUserSession()->getUser()->getUID();
124
		} else {
125
			return $this->share->getUserId();
126
		}
127
	}
128
129
	private function getDisplayName(): string {
130
		if ($this->getLoggedIn()) {
131
			return $this->userManager->get($this->getUserId())->getDisplayName();
132
		} else {
133
			return $this->share->getDisplayName();
134
		}
135
	}
136
137
	public function getPollId(): int {
138
		return $this->poll->getId();
139
	}
140
141
	public function getAllowYesVote(): bool {
142
		\OC::$server->getLogger()->alert('vote limit is (' . $this->poll->getVoteLimit() . ') and counted votes are ' . $this->getYesVotes());
143
		return !($this->poll->getVoteLimit() && $this->getYesVotes() >= $this->poll->getVoteLimit());
144
	}
145
146
	private function getYesVotes(): int {
147
		return $this->voteMapper->countYesVotes($this->getUserId(), $this->getPollId());
148
	}
149
150
	public function getAllowView(): bool {
151
		return (
152
			   $this->getAllowEdit()
153
			|| !$this->poll->getDeleted() && (
154
				   $this->getValidPublicShare()
155
				|| $this->getUserIsInvolved()
156
				|| $this->getPublicShare()
157
			)
158
		);
159
	}
160
161
	public function getAllowVote(): bool {
162
		return ($this->getAllowView() || $this->getToken())
163
			&& !$this->poll->getExpired()
164
			&& !$this->poll->getDeleted()
165
			&& $this->getUserId();
166
	}
167
168
	public function getAllowSubscribe(): bool {
169
		return ($this->hasEmail())
170
			&& !$this->poll->getDeleted()
171
			&& $this->getAllowView();
172
	}
173
174
	public function getAllowComment(): bool {
175
		return !$this->poll->getDeleted() && $this->getUserId();
176
	}
177
178
	public function getAllowEdit(): bool {
179
		return ($this->getIsOwner() || $this->hasAdminAccess());
180
	}
181
182
	public function requestView(): void {
183
		if (!$this->getAllowView()) {
184
			throw new NotAuthorizedException;
185
		}
186
	}
187
188
	public function requestVote(): void {
189
		if (!$this->getAllowVote()) {
190
			throw new NotAuthorizedException;
191
		}
192
	}
193
194
	public function requestComment(): void {
195
		if (!$this->getAllowComment()) {
196
			throw new NotAuthorizedException;
197
		}
198
	}
199
200
	public function requestEdit(): void {
201
		if (!$this->getAllowEdit()) {
202
			throw new NotAuthorizedException;
203
		}
204
	}
205
206
	public function requestYesVotes(): void {
207
		if (!$this->getAllowYesVote()) {
208
			throw new VoteLimitExceededException;
209
		}
210
	}
211
212
	public function requestDelete(): void {
213
		if (!$this->getAllowEdit() && !$this->getIsAdmin()) {
214
			throw new NotAuthorizedException;
215
		}
216
	}
217
218
	public function requestTakeOver(): void {
219
		if (!$this->getIsAdmin()) {
220
			throw new NotAuthorizedException;
221
		}
222
	}
223
224
	public function validateUserId(string $userId): void {
225
		if ($this->getUserId() !== $userId) {
226
			throw new NotAuthorizedException;
227
		}
228
	}
229
230
	public function getAllowSeeResults(): bool {
231
		return $this->poll->getShowResults() === Poll::SHOW_RESULTS_ALWAYS
232
			|| ($this->poll->getShowResults() === 'expired' && $this->poll->getExpired())
233
			|| $this->getIsOwner();
234
	}
235
236
	public function getAllowSeeUsernames(): bool {
237
		return !$this->poll->getAnonymous() || $this->getIsOwner();
238
	}
239
240
	public function getToken(): string {
241
		return strval($this->share->getToken());
242
	}
243
244
	public function jsonSerialize(): array {
245
		return	[
246
			'allowComment'      => $this->getAllowComment(),
247
			'allowEdit'         => $this->getAllowEdit(),
248
			'allowSeeResults'   => $this->getAllowSeeResults(),
249
			'allowSeeUsernames' => $this->getAllowSeeUsernames(),
250
			'allowSubscribe'    => $this->getAllowSubscribe(),
251
			'allowView'         => $this->getAllowView(),
252
			'allowVote'         => $this->getAllowVote(),
253
			'displayName'       => $this->getDisplayName(),
254
			'isOwner'           => $this->getIsOwner(),
255
			'loggedIn'			=> $this->getLoggedIn(),
256
			'pollId'            => $this->getPollId(),
257
			'token'             => $this->getToken(),
258
			'userHasVoted'		=> $this->getUserHasVoted(),
259
			'userId'            => $this->getUserId(),
260
			'userIsInvolved'	=> $this->getUserIsInvolved(),
261
		];
262
	}
263
264
	/**
265
	 * getLoggedIn - Is user logged in to nextcloud?
266
	 */
267
	private function getLoggedIn(): bool {
268
		return \OC::$server->getUserSession()->isLoggedIn();
269
	}
270
271
	/**
272
	 * getIsOwner - Is user owner of the poll?
273
	 */
274
	private function getIsOwner(): bool {
275
		return ($this->getLoggedIn() && $this->poll->getOwner() === $this->getUserId());
276
	}
277
278
	/**
279
	 * getIsAdmin - Is the user admin
280
	 * Returns true, if user is in admin group
281
	 */
282
	private function getIsAdmin(): bool {
283
		return ($this->getLoggedIn() && $this->groupManager->isAdmin($this->getUserId()));
284
	}
285
286
	/**
287
	 * hasAdminAccess - Has user administrative rights?
288
	 * Returns true, if user is in admin group and poll has allowed admins to manage the poll
289
	 */
290
	private function hasAdminAccess(): bool {
291
		return ($this->getIsAdmin() && $this->poll->getAdminAccess());
292
	}
293
294
	/**
295
	 * getUserIsInvolved - Is user involved?
296
	 * Returns true, if the current user is involved in the share via share or if he is a participant.
297
	 */
298
	private function getUserIsInvolved(): bool {
299
		return (
300
			   $this->getIsOwner()
301
			|| $this->getUserHasVoted()
302
			|| $this->getGroupShare()
303
			|| $this->getPersonalShare());
304
	}
305
306
	/**
307
	 * getUserHasVoted - Is user a participant?
308
	 * Returns true, if the current user is already a particitipant of the current poll.
309
	 */
310
	private function getUserHasVoted(): bool {
311
		return count(
312
			$this->voteMapper->findParticipantsVotes($this->getPollId(), $this->getUserId())
313
		) > 0;
314
	}
315
316
	/**
317
	 * getGroupShare - Is the poll shared via group share?
318
	 * Returns true, if the current poll contains a group share with a group,
319
	 * where the current user is member of. This only affects logged users.
320
	 */
321
	private function getGroupShare(): int {
322
		if (!$this->getLoggedIn()) {
323
			return 0;
324
		}
325
		return count(
326
			array_filter($this->shareMapper->findByPoll($this->getPollId()), function ($item) {
327
				if ($item->getType() === Share::TYPE_GROUP && $this->groupManager->isInGroup($this->getUserId(), $item->getUserId())) {
328
					return true;
329
				}
330
			})
331
		);
332
	}
333
334
	/**
335
	 * getPersonalShare - Is the poll shared via user share?
336
	 * Returns >0, if the current poll contains a user share for the current user.
337
	 * This only affects logged users.
338
	 */
339
	private function getPersonalShare(): int {
340
		if (!$this->getLoggedIn()) {
341
			return 0;
342
		}
343
		return count(
344
			array_filter($this->shareMapper->findByPoll($this->getPollId()), function ($item) {
345
				if (in_array($item->getType(), [
346
					Share::TYPE_USER,
347
					Share::TYPE_EXTERNAL,
348
					Share::TYPE_EMAIL,
349
					Share::TYPE_CONTACT
350
				])
351
					&& $item->getUserId() === $this->getUserId()
352
				) {
353
					return true;
354
				}
355
			})
356
		);
357
	}
358
359
	/**
360
	 * getPublicShare
361
	 */
362
	private function getPublicShare(): int {
363
		return count(
364
			array_filter($this->shareMapper->findByPoll($this->getPollId()), function ($item) {
365
				if ($item->getType() === Share::TYPE_PUBLIC && $item->getToken() === $this->getToken()) {
366
					return true;
367
				}
368
			})
369
		);
370
	}
371
372
	/**
373
	 * validateShareAccess
374
	 */
375
	private function validateShareAccess(): void {
376
		if ($this->getLoggedIn()) {
377
			if (!$this->getValidAuthenticatedShare()) {
378
				throw new NotAuthorizedException('Share type "' . $this->share->getType() . '"only valid for external users');
379
			};
380
		} else {
381
			if (!$this->getValidPublicShare()) {
382
				throw new NotAuthorizedException('Share type "' . $this->share->getType() . '"only valid for internal users');
383
			};
384
		}
385
	}
386
387
	/**
388
	 * getValidPublicShare
389
	 */
390
	private function getValidPublicShare(): bool {
391
		return in_array($this->share->getType(), [
392
			Share::TYPE_PUBLIC,
393
			Share::TYPE_EMAIL,
394
			Share::TYPE_CONTACT,
395
			Share::TYPE_EXTERNAL
396
		]);
397
	}
398
399
	/**
400
	 * getValidAuthenticatedShare
401
	 */
402
	private function getValidAuthenticatedShare(): bool {
403
		return in_array($this->share->getType(), [
404
			Share::TYPE_PUBLIC,
405
			Share::TYPE_USER,
406
			Share::TYPE_GROUP
407
		]);
408
	}
409
410
	/**
411
	 * hasEmail
412
	 */
413
	private function hasEmail(): bool {
414
		if ($this->share->getToken()) {
415
			return strlen($this->share->getEmailAddress()) > 0;
416
		} else {
417
			return $this->getLoggedIn();
418
		}
419
	}
420
}
421