Completed
Push — develop-0.9 ( 3c00b3...763dab )
by René
12s
created

PageController::userIsOwner()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
ccs 0
cts 6
cp 0
crap 6
1
<?php
2
/**
3
 * @copyright Copyright (c) 2017 Vinzenz Rosenkranz <[email protected]>
4
 *
5
 * @author Vinzenz Rosenkranz <[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
namespace OCA\Polls\Controller;
25
26
use OCA\Polls\Db\Comment;
27
use OCA\Polls\Db\CommentMapper;
28
use OCA\Polls\Db\Event;
29
use OCA\Polls\Db\EventMapper;
30
use OCA\Polls\Db\Notification;
31
use OCA\Polls\Db\NotificationMapper;
32
use OCA\Polls\Db\Options;
33
use OCA\Polls\Db\OptionsMapper;
34
use OCA\Polls\Db\Votes;
35
use OCA\Polls\Db\VotesMapper;
36
use OCP\AppFramework\Controller;
37
use OCP\AppFramework\Db\DoesNotExistException;
38
use OCP\AppFramework\Http\ContentSecurityPolicy;
39
use OCP\AppFramework\Http\JSONResponse;
40
use OCP\AppFramework\Http\RedirectResponse;
41
use OCP\AppFramework\Http\TemplateResponse;
42
use OCP\IAvatarManager;
43
use OCP\IGroupManager;
44
use OCP\IL10N;
45
use OCP\ILogger;
46
use OCP\IRequest;
47
use OCP\IURLGenerator;
48
use OCP\IUserManager;
49
use OCP\Mail\IMailer;
50
use OCP\Security\ISecureRandom;
51
use OCP\User; //To do: replace according to API
52
use OCP\Util;
53
54
class PageController extends Controller {
55
56
	private $userId;
57
	private $commentMapper;
58
	private $eventMapper;
59
	private $notificationMapper;
60
	private $optionsMapper;
61
	private $votesMapper;
62
	private $urlGenerator;
63
	private $userMgr;
64
	private $avatarManager;
65
	private $logger;
66
	private $trans;
67
	private $groupManager;
68
69
	/**
70
	 * PageController constructor.
71
	 * @param string $appName
72
	 * @param IRequest $request
73
	 * @param IUserManager $userMgr
74
	 * @param IGroupManager $groupManager
75
	 * @param IAvatarManager $avatarManager
76
	 * @param ILogger $logger
77
	 * @param IL10N $trans
78
	 * @param IURLGenerator $urlGenerator
79
	 * @param string $userId
80
	 * @param CommentMapper $commentMapper
81
	 * @param EventMapper $eventMapper
82
	 * @param NotificationMapper $notificationMapper
83
	 * @param OptionsMapper $optionsMapper
84
	 * @param VotesMapper $VotesMapper
85
	 */
86 1
	public function __construct(
87
		$appName,
88
		IRequest $request,
89
		IUserManager $userMgr,
90
		IGroupManager $groupManager,
91
		IAvatarManager $avatarManager,
92 1
		ILogger $logger,
93
		IL10N $trans,
94
		IURLGenerator $urlGenerator,
95
		$userId,
96
		CommentMapper $commentMapper,
97
		OptionsMapper $optionsMapper,
98
		EventMapper $eventMapper,
99
		NotificationMapper $notificationMapper,
100
		VotesMapper $VotesMapper
101
	) {
102 1
		parent::__construct($appName, $request);
103 1
		$this->userMgr = $userMgr;
104 1
		$this->groupManager = $groupManager;
105 1
		$this->avatarManager = $avatarManager;
106 1
		$this->logger = $logger;
107 1
		$this->trans = $trans;
108 1
		$this->urlGenerator = $urlGenerator;
109 1
		$this->userId = $userId;
110 1
		$this->commentMapper = $commentMapper;
111 1
		$this->eventMapper = $eventMapper;
112 1
		$this->notificationMapper = $notificationMapper;
113 1
		$this->optionsMapper = $optionsMapper;
114 1
		$this->votesMapper = $VotesMapper;
115 1
	}
116
117
	/**
118
	 * @NoAdminRequired
119
	 * @NoCSRFRequired
120
	 */
121 1
	public function index() {
122 1
		$polls = $this->eventMapper->findAllForUserWithInfo($this->userId);
123 1
		$comments = $this->commentMapper->findDistinctByUser($this->userId);
124 1
		$votes = $this->votesMapper->findDistinctByUser($this->userId);
125 1
		$response = new TemplateResponse('polls', 'main.tmpl', [
126 1
			'polls' => $polls,
127 1
			'comments' => $comments,
128 1
			'votes' => $votes,
129 1
			'userId' => $this->userId,
130 1
			'userMgr' => $this->userMgr,
131 1
			'urlGenerator' => $this->urlGenerator
132 1
		]);
133 1
		$csp = new ContentSecurityPolicy();
134 1
		$response->setContentSecurityPolicy($csp);
135 1
		return $response;
136
	}
137
138
	/**
139
	 * @param int $pollId
140
	 * @param string $from
141
	 */
142
	private function sendNotifications($pollId, $from) {
143
		$poll = $this->eventMapper->find($pollId);
144
		$notifications = $this->notificationMapper->findAllByPoll($pollId);
145
		foreach ($notifications as $notification) {
146
			if ($from === $notification->getUserId()) {
147
				continue;
148
			}
149
			$email = \OC::$server->getConfig()->getUserValue($notification->getUserId(), 'settings', 'email');
150
			if ($email === null || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
151
				continue;
152
			}
153
			$url = $this->urlGenerator->getAbsoluteURL(
154
				$this->urlGenerator->linkToRoute('polls.page.goto_poll',
155
					array('hash' => $poll->getHash()))
156
			);
157
158
			$recUser = $this->userMgr->get($notification->getUserId());
159
			$sendUser = $this->userMgr->get($from);
160
			$rec = '';
161
			if ($recUser !== null) {
162
				$rec = $recUser->getDisplayName();
163
			}
164
			$sender = $from;
165
			if ($sendUser !== null) {
166
				$sender = $sendUser->getDisplayName();
167
			}
168
			$msg = $this->trans->t('Hello %s,<br/><br/><strong>%s</strong> participated in the poll \'%s\'.<br/><br/>To go directly to the poll, you can use this <a href="%s">link</a>',
169
				array(
170
					$rec,
171
					$sender,
172
					$poll->getTitle(),
173
					$url
174
				));
175
176
			$msg .= '<br/><br/>';
177
178
			$toName = $this->userMgr->get($notification->getUserId())->getDisplayName();
179
			$subject = $this->trans->t('Polls App - New Activity');
180
			$fromAddress = Util::getDefaultEmailAddress('no-reply');
181
			$fromName = $this->trans->t('Polls App') . ' (' . $from . ')';
182
183
			try {
184
				/** @var IMailer $mailer */
185
				$mailer = \OC::$server->getMailer();
186
				/** @var \OC\Mail\Message $message */
187
				$message = $mailer->createMessage();
188
				$message->setSubject($subject);
189
				$message->setFrom(array($fromAddress => $fromName));
190
				$message->setTo(array($email => $toName));
191
				$message->setHtmlBody($msg);
192
				$mailer->send($message);
193
			} catch (\Exception $e) {
194
				$message = 'Error sending mail to: ' . $toName . ' (' . $email . ')';
195
				Util::writeLog('polls', $message, Util::ERROR);
196
			}
197
		}
198
	}
199
200
	/**
201
	 * @NoAdminRequired
202
	 * @NoCSRFRequired
203
	 * @PublicPage
204
	 * @param string $hash
205
	 * @return TemplateResponse
206
	 */
207
	public function gotoPoll($hash) {
208
		try {
209
			$poll = $this->eventMapper->findByHash($hash);
210
		} catch (DoesNotExistException $e) {
211
			return new TemplateResponse('polls', 'no.acc.tmpl', []);
212
		}
213
		$options = $this->optionsMapper->findByPoll($poll->getId());
214
		$votes = $this->votesMapper->findByPoll($poll->getId());
215
		$participants = $this->votesMapper->findParticipantsByPoll($poll->getId());
216
		$comments = $this->commentMapper->findByPoll($poll->getId());
217
218
		try {
219
			$notification = $this->notificationMapper->findByUserAndPoll($poll->getId(), $this->userId);
220
		} catch (DoesNotExistException $e) {
221
			$notification = null;
222
		}
223
		if ($this->hasUserAccess($poll)) {
224
			return new TemplateResponse('polls', 'goto.tmpl', [
225
				'poll' => $poll,
226
				'options' => $options,
227
				'comments' => $comments,
228
				'votes' => $votes,
229
				'participant' => $participants,
230
				'notification' => $notification,
231
				'userId' => $this->userId,
232
				'userMgr' => $this->userMgr,
233
				'urlGenerator' => $this->urlGenerator,
234
				'avatarManager' => $this->avatarManager
235
			]);
236
		} else {
237
			User::checkLoggedIn();
238
			return new TemplateResponse('polls', 'no.acc.tmpl', []);
239
		}
240
	}
241
242
	/**
243
	 * @NoAdminRequired
244
	 * @NoCSRFRequired
245
	 * @param int $pollId
246
	 * @return TemplateResponse|RedirectResponse
247
	 */
248
	public function deletePoll($pollId) {
249
		$pollToDelete = $this->eventMapper->find($pollId);
250
		if ($this->userId !== $pollToDelete->getOwner()) {
251
			return new TemplateResponse('polls', 'no.delete.tmpl');
252
		}
253
		$poll = new Event();
254
		$poll->setId($pollId);
255
		$this->eventMapper->delete($poll);
256
		$this->optionsMapper->deleteByPoll($pollId);
257
		$this->votesMapper->deleteByPoll($pollId);
258
		$this->commentMapper->deleteByPoll($pollId);
259
		$url = $this->urlGenerator->linkToRoute('polls.page.index');
260
		return new RedirectResponse($url);
261
	}
262
263
	/**
264
	 * @NoAdminRequired
265
	 * @NoCSRFRequired
266
	 * @param string $hash
267
	 * @return TemplateResponse
268
	 */
269
	public function editPoll($hash) {
270
		return new TemplateResponse('polls', 'create.tmpl', [
271
			'urlGenerator' => $this->urlGenerator,
272
 			'hash' => $hash
273
		]);
274
	}
275
276
	/**
277
	 * @NoAdminRequired
278
	 * @NoCSRFRequired
279
	 */
280
	public function createPoll() {
281
		return new TemplateResponse('polls', 'create.tmpl',
282
			['urlGenerator' => $this->urlGenerator]);
283
	}
284
285
	/**
286
	 * @NoAdminRequired
287
	 * @NoCSRFRequired
288
	 * @PublicPage
289
	 * @param int $pollId
290
	 * @param string $userId
291
	 * @param string $answers
292
	 * @param string $options
293
	 * @param bool $receiveNotifications
294
	 * @param bool $changed
295
	 * @return RedirectResponse
296
	 */
297
	public function insertVote($pollId, $userId, $answers, $options, $receiveNotifications, $changed) {
298
		if ($this->userId !== null) {
299
			if ($receiveNotifications) {
300
				try {
301
					//check if user already set notification for this poll
302
					$this->notificationMapper->findByUserAndPoll($pollId, $userId);
303
				} catch (DoesNotExistException $e) {
304
					//insert if not exist
305
					$not = new Notification();
306
					$not->setUserId($userId);
307
					$not->setPollId($pollId);
308
					$this->notificationMapper->insert($not);
309
				}
310
			} else {
311
				try {
312
					//delete if entry is in db
313
					$not = $this->notificationMapper->findByUserAndPoll($pollId, $userId);
314
					$this->notificationMapper->delete($not);
315
				} catch (DoesNotExistException $e) {
316
					//doesn't exist in db, nothing to do
317
				}
318
			}
319
		}
320
		$poll = $this->eventMapper->find($pollId);
321
		
322
		if ($changed) {
323
			$options = json_decode($options);
324
			$answers = json_decode($answers);
325
			$count_options = count($options);
326
			$this->votesMapper->deleteByPollAndUser($pollId, $userId);
327
			
328
			for ($i = 0; $i < $count_options; $i++) {
329
				$vote = new Votes();
330
				$vote->setPollId($pollId);
331
				$vote->setUserId($userId);
332
				$vote->setVoteOptionText(htmlspecialchars($options[$i]));
333
				$vote->setVoteAnswer($answers[$i]);
334
				$this->votesMapper->insert($vote);
335
336
			}
337
			$this->sendNotifications($pollId, $userId);
338
		}
339
		$hash = $poll->getHash();
340
		$url = $this->urlGenerator->linkToRoute('polls.page.goto_poll', ['hash' => $hash]);
341
		return new RedirectResponse($url);
342
	}
343
344
	/**
345
	 * @NoAdminRequired
346
	 * @NoCSRFRequired
347
	 * @PublicPage
348
	 * @param int $pollId
349
	 * @param string $userId
350
	 * @param string $commentBox
351
	 * @return JSONResponse
352
	 */
353
	public function insertComment($pollId, $userId, $commentBox) {
354
		$comment = new Comment();
355
		$comment->setPollId($pollId);
356
		$comment->setUserId($userId);
357
		$comment->setComment($commentBox);
358
		$comment->setDt(date('Y-m-d H:i:s'));
359
		$this->commentMapper->insert($comment);
360
		$this->sendNotifications($pollId, $userId);
361
		$timeStamp = time();
362
		$displayName = $userId;
363
		$user = $this->userMgr->get($userId);
364
		if ($user !== null) {
365
			$displayName = $user->getDisplayName();
366
		}
367
		return new JSONResponse(array(
368
			'userId' => $userId,
369
			'displayName' => $displayName,
370
			'timeStamp' => $timeStamp * 100, 
371
			'date' => date('Y-m-d H:i:s', $timeStamp),
372
			'relativeNow' => $this->trans->t('just now'),
373
			'comment' => $commentBox
374
		));
375
	}
376
377
	/**
378
	 * @NoAdminRequired
379
	 * @NoCSRFRequired
380
	 * @param string $searchTerm
381
	 * @param string $groups
382
	 * @param string $users
383
	 * @return array
384
	 */
385
	public function search($searchTerm, $groups, $users) {
386
		return array_merge($this->searchForGroups($searchTerm, $groups), $this->searchForUsers($searchTerm, $users));
387
	}
388
389
	/**
390
	 * @NoAdminRequired
391
	 * @NoCSRFRequired
392
	 * @param string $searchTerm
393
	 * @param string $groups
394
	 * @return array
395
	 */
396
	public function searchForGroups($searchTerm, $groups) {
397
		$selectedGroups = json_decode($groups);
398
		$groups = $this->groupManager->search($searchTerm);
399
		$gids = array();
400
		$sgids = array();
401
		foreach ($selectedGroups as $sg) {
402
			$sgids[] = str_replace('group_', '', $sg);
403
		}
404
		foreach ($groups as $g) {
405
			$gids[] = $g->getGID();
406
		}
407
		$diffGids = array_diff($gids, $sgids);
408
		$gids = array();
409
		foreach ($diffGids as $g) {
410
			$gids[] = ['gid' => $g, 'isGroup' => true];
411
		}
412
		return $gids;
413
	}
414
415
	/**
416
	 * @NoAdminRequired
417
	 * @NoCSRFRequired
418
	 * @param string $searchTerm
419
	 * @param string $users
420
	 * @return array
421
	 */
422
	public function searchForUsers($searchTerm, $users) {
423
		$selectedUsers = json_decode($users);
424
		Util::writeLog('polls', print_r($selectedUsers, true), Util::ERROR);
425
		$userNames = $this->userMgr->searchDisplayName($searchTerm);
426
		$users = array();
427
		$sUsers = array();
428
		foreach ($selectedUsers as $su) {
429
			$sUsers[] = str_replace('user_', '', $su);
430
		}
431
		foreach ($userNames as $u) {
432
			$allreadyAdded = false;
433
			foreach ($sUsers as &$su) {
434
				if ($su === $u->getUID()) {
435
					unset($su);
436
					$allreadyAdded = true;
437
					break;
438
				}
439
			}
440
			if (!$allreadyAdded) {
441
				$users[] = array('uid' => $u->getUID(), 'displayName' => $u->getDisplayName(), 'isGroup' => false);
442
			} else {
443
				continue;
444
			}
445
		}
446
		return $users;
447
	}
448
449
	/**
450
	 * @NoAdminRequired
451
	 * @NoCSRFRequired
452
	 * @param string $username
453
	 * @return string
454
	 */
455
	public function getDisplayName($username) {
456
		return $this->userMgr->get($username)->getDisplayName();
457
	}
458
459
	/**
460
	 * @return \OCP\IGroup[]
461
	 */
462
	private function getGroups() {
463
		if (class_exists('\OC_Group')) {
464
			// Nextcloud <= 11, ownCloud
465
			return \OC_Group::getUserGroups($this->userId);
0 ignored issues
show
Bug introduced by
The type OC_Group was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
466
		}
467
		// Nextcloud >= 12
468
		$groups = $this->groupManager->getUserGroups(\OC::$server->getUserSession()->getUser());
469
		return array_map(function($group) {
470
			return $group->getGID();
471
		}, $groups);
472
	}
473
474
	/**
475
	 * Check if user has access to this poll
476
	 *
477
	 * @param Event $poll
478
	 * @return bool
479
	 */
480
	private function hasUserAccess($poll) {
481
		$access = $poll->getAccess();
482
		$owner = $poll->getOwner();
483
		if ($access === 'public' || $access === 'hidden') {
484
			return true;
485
		}
486
		if ($this->userId === null) {
487
			return false;
488
		}
489
		if ($access === 'registered') {
490
			return true;
491
		}
492
		if ($owner === $this->userId) {
493
			return true;
494
		}
495
		Util::writeLog('polls', $this->userId, Util::ERROR);
496
		$userGroups = $this->getGroups();
497
		$arr = explode(';', $access);
498
		foreach ($arr as $item) {
499
			if (strpos($item, 'group_') === 0) {
500
				$grp = substr($item, 6);
501
				foreach ($userGroups as $userGroup) {
502
					if ($userGroup === $grp) {
503
						return true;
504
					}
505
				}
506
			} else {
507
				if (strpos($item, 'user_') === 0) {
508
					$usr = substr($item, 5);
509
					if ($usr === $this->userId) {
510
						return true;
511
					}
512
				}
513
			}
514
		}
515
		return false;
516
	}
517
	/**
518
	 * Check if user is owner of this poll
519
	 *
520
	 * @param Event $poll
521
	 * @return bool
522
	 */
523
524
	private function userIsOwner($poll) {
0 ignored issues
show
Unused Code introduced by
The method userIsOwner() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
525
		$owner = $poll->getOwner();
526
527
		if ($owner === $this->userId) {
528
			return true;
529
		}
530
		Util::writeLog('polls', $this->userId, Util::ERROR);
531
		return false;
532
	}
533
}
534