Passed
Pull Request — master (#1254)
by René
03:50
created

Acl::hasEmail()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 5
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
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
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
	/**
94
	 * setToken - load share via token and than call setShare
95
	 * @param string $token
96
	 * @return self
97
	 * @throws NotAuthorizedException
98
	 */
99
	public function setToken($token = ''): Acl {
100
		try {
101
			return $this->setShare($this->shareMapper->findByToken($token));
102
		} catch (DoesNotExistException $e) {
103
			throw new NotAuthorizedException('Error loading share ' . $token);
104
		}
105
	}
106
107
	/**
108
	 * setShare - sets and validates the share
109
	 * read access is
110
	 * @param Share $share
111
	 * @return Acl
112
	 */
113
	public function setShare(Share $share): Acl {
114
		$this->share = $share;
115
		$this->validateShareAccess();
116
117
		// load poll, if pollId does not match
118
		if ($this->share->getPollId() !== $this->poll->getId()) {
119
			$this->setPollId($share->getPollId());
120
		}
121
		return $this;
122
	}
123
124
	/**
125
	 * setPollId
126
	 * @param int $pollId
127
	 * @return Acl
128
	 * @throws NotAuthorizedException
129
	 */
130
	public function setPollId(int $pollId = 0): Acl {
131
		try {
132
			return $this->setPoll($this->pollMapper->find($pollId));
133
		} catch (DoesNotExistException $e) {
134
			throw new NotAuthorizedException('Error loading poll ' . $pollId);
135
		}
136
	}
137
138
	/**
139
	 * setPoll
140
	 * @param Poll $poll
141
	 * @return self
142
	 */
143
	public function setPoll(Poll $poll) {
144
		$this->poll = $poll;
145
		if (!$this->getAllowView()) {
146
			throw new NotAuthorizedException('Error loading poll ' . $poll->getId());
147
		}
148
		return $this;
149
	}
150
151
	/**
152
	 * getUserId
153
	 * @return string
154
	 */
155
	public function getUserId() {
156
		if ($this->getLoggedIn()) {
157
			return \OC::$server->getUserSession()->getUser()->getUID();
158
		} else {
159
			return $this->share->getUserId();
160
		}
161
	}
162
163
	/**
164
	 * getDisplayName
165
	 * @return string
166
	 */
167
	private function getDisplayName() {
168
		if ($this->getLoggedIn()) {
169
			return $this->userManager->get($this->getUserId())->getDisplayName();
170
		} else {
171
			return $this->share->getDisplayName();
172
		}
173
	}
174
175
	/**
176
	 * getPollId
177
	 * @return int
178
	 */
179
	public function getPollId(): int {
180
		return $this->poll->getId();
181
	}
182
183
	/**
184
	 * getAllowView
185
	 * @return bool
186
	 */
187
	public function getAllowView(): bool {
188
		return (
189
			   $this->getAllowEdit()
190
			|| !$this->poll->getDeleted() && (
191
				   $this->getValidPublicShare()
192
				|| $this->getUserIsInvolved()
193
				|| $this->getPublicShare()
194
			)
195
		);
196
	}
197
198
	/**
199
	 * getAllowVote
200
	 * @return bool
201
	 */
202
	public function getAllowVote(): bool {
203
		return ($this->getAllowView() || $this->getToken())
204
			&& !$this->poll->getExpired()
205
			&& !$this->poll->getDeleted()
206
			&& $this->getUserId();
207
	}
208
209
	/**
210
	 * requestVote
211
	 * @throws NotAuthorizedException
212
	 * @return void
213
	 */
214
	public function requestVote(): void {
215
		if (!$this->getAllowVote()) {
216
			throw new NotAuthorizedException;
217
		}
218
	}
219
220
221
	/**
222
	 * getAllowSubscribe
223
	 * @return bool
224
	 */
225
	public function getAllowSubscribe(): bool {
226
		return ($this->hasEmail())
227
			&& !$this->poll->getDeleted()
228
			&& $this->getAllowView();
229
	}
230
231
	/**
232
	 * getAllowComment
233
	 * @return bool
234
	 */
235
	public function getAllowComment(): bool {
236
		return !$this->poll->getDeleted() && $this->getUserId();
237
	}
238
239
	/**
240
	 * getAllowEdit
241
	 * @return bool
242
	 */
243
	public function getAllowEdit(): bool {
244
		return ($this->getIsOwner() || $this->getIsAdmin());
245
	}
246
247
	/**
248
	 * requestEdit
249
	 * @throws NotAuthorizedException
250
	 * @return void
251
	 */
252
	public function requestEdit(): void {
253
		if (!$this->getAllowEdit()) {
254
			throw new NotAuthorizedException;
255
		}
256
	}
257
258
	/**
259
	 * requestDelete
260
	 * @throws NotAuthorizedException
261
	 * @return void
262
	 */
263
	public function requestDelete(): void {
264
		if (!$this->getAllowEdit() || !$this->poll->getDeleted()) {
265
			throw new NotAuthorizedException;
266
		}
267
	}
268
269
	/**
270
	 * getAllowSeeResults
271
	 * @return bool
272
	 */
273
	public function getAllowSeeResults(): bool {
274
		return $this->poll->getShowResults() === Poll::SHOW_RESULTS_ALWAYS
275
			|| ($this->poll->getShowResults() === 'expired' && $this->poll->getExpired())
276
			|| $this->getIsOwner();
277
	}
278
279
	/**
280
	 * getAllowSeeUsernames
281
	 * @return bool
282
	 */
283
	public function getAllowSeeUsernames(): bool {
284
		return !$this->poll->getAnonymous() || $this->getIsOwner();
285
	}
286
287
	/**
288
	 * getToken
289
	 * @return string
290
	 */
291
	public function getToken(): string {
292
		return strval($this->share->getToken());
293
	}
294
295
	/**
296
	 * @return array
297
	 */
298
	public function jsonSerialize(): array {
299
		return	[
300
			'allowComment'      => $this->getAllowComment(),
301
			'allowEdit'         => $this->getAllowEdit(),
302
			'allowSeeResults'   => $this->getAllowSeeResults(),
303
			'allowSeeUsernames' => $this->getAllowSeeUsernames(),
304
			'allowSubscribe'    => $this->getAllowSubscribe(),
305
			'allowView'         => $this->getAllowView(),
306
			'allowVote'         => $this->getAllowVote(),
307
			'displayName'       => $this->getDisplayName(),
308
			'isOwner'           => $this->getIsOwner(),
309
			'loggedIn'			=> $this->getLoggedIn(),
310
			'pollId'            => $this->getPollId(),
311
			'token'             => $this->getToken(),
312
			'userHasVoted'		=> $this->getUserHasVoted(),
313
			'userId'            => $this->getUserId(),
314
			'userIsInvolved'	=> $this->getUserIsInvolved(),
315
		];
316
	}
317
318
	/**
319
	 * getLoggedIn - Is user logged in to nextcloud?
320
	 * @return bool
321
	 */
322
	private function getLoggedIn(): bool {
323
		return \OC::$server->getUserSession()->isLoggedIn();
324
	}
325
326
	/**
327
	 * getIsOwner - Is user owner of the poll?
328
	 * @return bool
329
	 */
330
	private function getIsOwner(): bool {
331
		return ($this->getLoggedIn() && $this->poll->getOwner() === $this->getUserId());
332
	}
333
334
	/**
335
	 * getIsAdmin - Has user administrative rights?
336
	 * Returns true, if user is in admin group and poll has allowed admins to manage the poll
337
	 * @return bool
338
	 */
339
	private function getIsAdmin(): bool {
340
		return ($this->getLoggedIn() && $this->groupManager->isAdmin($this->getUserId()) && $this->poll->getAdminAccess());
341
	}
342
343
	/**
344
	 * getUserIsInvolved - Is user involved?
345
	 * Returns true, if the current user is involved in the share via share or if he is a participant.
346
	 * @return bool
347
	 */
348
	private function getUserIsInvolved(): bool {
349
		return (
350
			   $this->getIsOwner()
351
			|| $this->getUserHasVoted()
352
			|| $this->getGroupShare()
353
			|| $this->getPersonalShare());
354
	}
355
356
	/**
357
	 * getUserHasVoted - Is user a participant?
358
	 * Returns true, if the current user is already a particitipant of the current poll.
359
	 * @return bool
360
	 */
361
	private function getUserHasVoted(): bool {
362
		return count(
363
			$this->voteMapper->findParticipantsVotes($this->getPollId(), $this->getUserId())
364
		) > 0;
365
	}
366
367
	/**
368
	 * getGroupShare - Is the poll shared via group share?
369
	 * Returns true, if the current poll contains a group share with a group,
370
	 * where the current user is member of. This only affects logged users.
371
	 * @return bool
372
	 */
373
	private function getGroupShare(): bool {
374
		if ($this->getLoggedIn()) {
375
			return count(
376
				array_filter($this->shareMapper->findByPoll($this->getPollId()), function ($item) {
377
					if ($item->getType() === Share::TYPE_GROUP && $this->groupManager->isInGroup($this->getUserId(), $item->getUserId())) {
378
						return true;
379
					}
380
				})
381
			);
382
		} else {
383
			return false;
384
		}
385
	}
386
387
	/**
388
	 * getPersonalShare - Is the poll shared via user share?
389
	 * Returns true, if the current poll contains a user share for the current user.
390
	 * This only affects logged users.
391
	 * @return bool
392
	 */
393
	private function getPersonalShare(): bool {
394
		if ($this->getLoggedIn()) {
395
			return count(
396
				array_filter($this->shareMapper->findByPoll($this->getPollId()), function ($item) {
397
					if (in_array($item->getType(), [
398
						Share::TYPE_USER,
399
						Share::TYPE_EXTERNAL,
400
						Share::TYPE_EMAIL,
401
						Share::TYPE_CONTACT
402
					])
403
						&& $item->getUserId() === $this->getUserId()
404
					) {
405
						return true;
406
					}
407
				})
408
			);
409
		} else {
410
			return false;
411
		}
412
	}
413
414
	/**
415
	 * getPublicShare
416
	 * @return bool
417
	 */
418
	private function getPublicShare(): bool {
419
		return count(
420
			array_filter($this->shareMapper->findByPoll($this->getPollId()), function ($item) {
421
				if ($item->getType() === Share::TYPE_PUBLIC && $item->getToken() === $this->getToken()) {
422
					return true;
423
				}
424
			})
425
		);
426
	}
427
428
	/**
429
	 * validateShareAccess
430
	 * @return void
431
	 * @throws NotAuthorizedException
432
	 */
433
	private function validateShareAccess(): void {
434
		if ($this->getLoggedIn()) {
435
			if (!$this->getValidAuthenticatedShare()) {
436
				throw new NotAuthorizedException('Share type "' . $this->share->getType() . '"only valid for external users');
437
			};
438
		} else {
439
			if (!$this->getValidPublicShare()) {
440
				throw new NotAuthorizedException('Share type "' . $this->share->getType() . '"only valid for internal users');
441
			};
442
		}
443
	}
444
445
	/**
446
	 * getValidPublicShare
447
	 * @return bool
448
	 */
449
	private function getValidPublicShare(): bool {
450
		return in_array($this->share->getType(), [
451
			Share::TYPE_PUBLIC,
452
			Share::TYPE_EMAIL,
453
			Share::TYPE_CONTACT,
454
			Share::TYPE_EXTERNAL
455
		]);
456
	}
457
458
	/**
459
	 * getValidAuthenticatedShare
460
	 * @return bool
461
	 */
462
	private function getValidAuthenticatedShare(): bool {
463
		return in_array($this->share->getType(), [
464
			Share::TYPE_PUBLIC,
465
			Share::TYPE_USER,
466
			Share::TYPE_GROUP
467
		]);
468
	}
469
470
	/**
471
	 * hasEmail
472
	 * @return bool
473
	 */
474
	private function hasEmail(): bool {
475
		if ($this->share->getToken()) {
476
			return strlen($this->share->getEmailAddress()) > 0;
477
		} else {
478
			return $this->getLoggedIn();
479
		}
480
	}
481
}
482