Completed
Push — master ( 0471ec...901b23 )
by René
10:22 queued 06:22
created

ApiController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 9
dl 0
loc 19
rs 10
c 0
b 0
f 0
ccs 0
cts 19
cp 0
crap 2

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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
namespace OCA\Polls\Controller;
25
26
use OCP\AppFramework\Controller;
27
use OCP\AppFramework\Http;
28
use OCP\AppFramework\Http\DataResponse;
29
use OCP\AppFramework\Db\DoesNotExistException;
30
31
use OCP\IGroupManager;
32
use OCP\IRequest;
33
use OCP\IUser;
34
use OCP\IUserManager;
35
use OCP\Security\ISecureRandom;
36
37
use OCA\Polls\Db\Event;
38
use OCA\Polls\Db\EventMapper;
39
use OCA\Polls\Db\Option;
40
use OCA\Polls\Db\OptionMapper;
41
use OCA\Polls\Db\Vote;
42
use OCA\Polls\Db\VoteMapper;
43
use OCA\Polls\Db\Comment;
44
use OCA\Polls\Db\CommentMapper;
45
46
47
48
class ApiController extends Controller {
49
50
	private $eventMapper;
51
	private $optionMapper;
52
	private $voteMapper;
53
	private $commentMapper;
54
55
	/**
56
	 * PageController constructor.
57
	 * @param string $appName
58
	 * @param IGroupManager $groupManager
59
	 * @param IRequest $request
60
	 * @param IUserManager $userManager
61
	 * @param string $userId
62
	 * @param EventMapper $eventMapper
63
	 * @param OptionMapper $optionMapper
64
	 * @param VoteMapper $VoteMapper
65
	 * @param CommentMapper $CommentMapper
66
	 */
67
	public function __construct(
68
		$appName,
69
		IGroupManager $groupManager,
70
		IRequest $request,
71
		IUserManager $userManager,
72
		$userId,
73
		EventMapper $eventMapper,
74
		OptionMapper $optionMapper,
75
		VoteMapper $VoteMapper,
76
		CommentMapper $CommentMapper
77
	) {
78
		parent::__construct($appName, $request);
79
		$this->userId = $userId;
0 ignored issues
show
Bug Best Practice introduced by
The property userId does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
80
		$this->groupManager = $groupManager;
0 ignored issues
show
Bug Best Practice introduced by
The property groupManager does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
81
		$this->userManager = $userManager;
0 ignored issues
show
Bug Best Practice introduced by
The property userManager does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
82
		$this->eventMapper = $eventMapper;
83
		$this->optionMapper = $optionMapper;
84
		$this->voteMapper = $VoteMapper;
85
		$this->commentMapper = $CommentMapper;
86
	}
87
88
	/**
89
	 * Transforms a string with user and group names to an array
90
	 * of nextcloud users and groups
91
	 * @NoAdminRequired
92
	 * @NoCSRFRequired
93
	 * @param string $item
94
	 * @return Array
95
	 */
96
	private function convertAccessList($item) {
97
		$split = array();
98
		if (strpos($item, 'user_') === 0) {
99
			$user = $this->userManager->get(substr($item, 5));
100
			$split = [
101
				'id' => $user->getUID(),
102
				'user' => $user->getUID(),
103
				'type' => 'user',
104
				'desc' => 'user',
105
				'icon' => 'icon-user',
106
				'displayName' => $user->getDisplayName(),
107
				'avatarURL' => '',
108
				'lastLogin' => $user->getLastLogin(),
109
				'cloudId' => $user->getCloudId()
110
			];
111
		} elseif (strpos($item, 'group_') === 0) {
112
			$group = substr($item, 6);
113
			$group = $this->groupManager->get($group);
114
			$split = [
115
				'id' => $group->getGID(),
116
				'user' => $group->getGID(),
117
				'type' => 'group',
118
				'desc' => 'group',
119
				'icon' => 'icon-group',
120
				'displayName' => $group->getDisplayName(),
121
				'avatarURL' => '',
122
			];
123
		}
124
125
		return($split);
126
	}
127
128
	/**
129
	 * Check if current user is in the access list
130
	 * @param Array $accessList
131
	 * @return Boolean
132
	 */
133
	private function checkUserAccess($accessList) {
134
		foreach ($accessList as $accessItem ) {
135
			if ($accessItem['type'] === 'user' && $accessItem['id'] === \OC::$server->getUserSession()->getUser()->getUID()) {
136
				return true;
137
			}
138
		}
139
140
		return false;
141
	}
142
143
	/**
144
	 * Check If current user is member of a group in the access list
145
	 * @param Array $accessList
146
	 * @return Boolean
147
	 */
148
	private function checkGroupAccess($accessList) {
149
		foreach ($accessList as $accessItem ) {
150
			if ($accessItem['type'] === 'group' && $this->groupManager->isInGroup(\OC::$server->getUserSession()->getUser()->getUID(),$accessItem['id'])) {
151
				return true;
152
			}
153
		}
154
155
		return false;
156
	}
157
158
	/**
159
	 * Read all options of a poll based on the poll id
160
	 * @NoAdminRequired
161
	 * @NoCSRFRequired
162
	 * @param Integer $pollId
163
	 * @return Array
164
	 */
165
	public function getOptions($pollId) {
166
		$optionList = array();
167
		$options = $this->optionMapper->findByPoll($pollId);
168
		foreach ($options as $optionElement) {
169
			$optionList[] = [
170
				'id' => $optionElement->getId(),
171
				'text' => htmlspecialchars_decode($optionElement->getPollOptionText()),
172
				'timestamp' => $optionElement->getTimestamp()
173
			];
174
		}
175
176
		return $optionList;
177
	}
178
179
	/**
180
	 * Read all votes of a poll based on the poll id
181
	 * @NoAdminRequired
182
	 * @NoCSRFRequired
183
	 * @param Integer $pollId
184
	 * @return Array
185
	 */
186
	public function getVotes($pollId) {
187
		$votesList = array();
188
		$votes = $this->voteMapper->findByPoll($pollId);
189
		foreach ($votes as $voteElement) {
190
			$votesList[] = [
191
				'id' => $voteElement->getId(),
192
				'userId' => $voteElement->getUserId(),
193
				'voteOptionId' => $voteElement->getVoteOptionId(),
194
				'voteOptionText' => htmlspecialchars_decode($voteElement->getVoteOptionText()),
195
				'voteAnswer' => $voteElement->getVoteAnswer()
196
			];
197
		}
198
199
		return $votesList;
200
	}
201
202
	/**
203
	 * Read all comments of a poll based on the poll id
204
	 * @NoAdminRequired
205
	 * @NoCSRFRequired
206
	 * @param Integer $pollId
207
	 * @return Array
208
	 */
209
	public function getComments($pollId) {
210
		$commentsList = array();
211
		$comments = $this->commentMapper->findByPoll($pollId);
212
		foreach ($comments as $commentElement) {
213
			$commentsList[] = [
214
				'id' => $commentElement->getId(),
215
				'userId' => $commentElement->getUserId(),
216
				'date' => $commentElement->getDt() . ' UTC',
217
				'comment' => $commentElement->getComment()
218
			];
219
		}
220
221
		return $commentsList;
222
	}
223
224
	/**
225
	 * Read an entire poll based on poll id
226
	 * @NoAdminRequired
227
	 * @NoCSRFRequired
228
	 * @param Integer $pollId
229
	 * @return Array
230
	 */
231
	public function getEvent($pollId) {
232
233
		$data = array();
234
235
		try {
236
			$event = $this->eventMapper->find($pollId);
237
238
			if ($event->getType() == 0) {
239
				$pollType = 'datePoll';
240
			} else {
241
				$pollType = 'textPoll';
242
			}
243
244
			$accessType = $event->getAccess();
245
			if (!strpos('|public|hidden|registered', $accessType)) {
246
				$accessType = 'select';
247
			}
248
249
			if ($event->getExpire() === null) {
0 ignored issues
show
introduced by
The condition $event->getExpire() === null is always false.
Loading history...
250
				$expired = false;
251
				$expiration = false;
252
			} else {
253
				$expired = time() > strtotime($event->getExpire());
254
				$expiration = true;
255
			}
256
257
			$data = [
258
				'id' => $event->getId(),
259
				'hash' => $event->getHash(),
260
				'type' => $pollType,
261
				'title' => $event->getTitle(),
262
				'description' => $event->getDescription(),
263
				'owner' => $event->getOwner(),
264
				'created' => $event->getCreated(),
265
				'access' => $accessType,
266
				'expiration' => $expiration,
267
				'expired' => $expired,
268
				'expirationDate' => $event->getExpire(),
269
				'isAnonymous' => $event->getIsAnonymous(),
270
				'fullAnonymous' => $event->getFullAnonymous(),
271
				'allowMaybe' => $event->getAllowMaybe()
272
			];
273
274
		} catch (DoesNotExistException $e) {
275
			// return silently
276
		} finally {
277
			return $data;
278
		}
279
280
	}
281
282
	/**
283
	 * Read all shares (users and groups with access) of a poll based on the poll id
284
	 * @NoAdminRequired
285
	 * @NoCSRFRequired
286
	 * @param Integer $pollId
287
	 * @return Array
288
	 */
289
	public function getShares($pollId) {
290
291
		$accessList = array();
292
293
		try {
294
			$poll = $this->eventMapper->find($pollId);
295
			if (!strpos('|public|hidden|registered', $poll->getAccess())) {
296
				$accessList = explode(';', $poll->getAccess());
297
				$accessList = array_filter($accessList);
298
				$accessList = array_map(array($this, 'convertAccessList'), $accessList);
299
			}
300
		} catch (DoesNotExistException $e) {
301
			// return silently
302
		} finally {
303
			return $accessList;
304
		}
305
306
	}
307
308
	/**
309
	 * Set the access right of the current user for the poll
310
	 * @param Integer $pollId
311
	 * @return String
312
	 */
313
	private function grantAccessAs($pollId) {
314
		if (!\OC::$server->getUserSession()->getUser() instanceof IUser) {
315
			$currentUser = '';
316
		} else {
317
			$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
318
		}
319
320
		$event = $this->getEvent($pollId);
321
		$accessList = $this->getShares($pollId);
322
		$grantAccessAs = 'none';
323
324
		if ($event['owner'] === $currentUser) {
325
			$grantAccessAs = 'owner';
326
		} elseif ($event['access'] === 'public') {
327
			$grantAccessAs = 'public';
328
		} elseif ($event['access'] === 'registered' && \OC::$server->getUserSession()->getUser() instanceof IUser) {
329
			$grantAccessAs = 'registered';
330
		} elseif ($this->checkUserAccess($accessList)) {
331
			$grantAccessAs = 'userInvitation';
332
		} elseif ($this->checkGroupAccess($accessList)) {
333
			$grantAccessAs = 'groupInvitation';
334
		} elseif ($this->groupManager->isAdmin($currentUser)) {
335
			$grantAccessAs = 'admin';
336
		}
337
338
		return $grantAccessAs;
339
	}
340
341
342
	/**
343
	 * Read an entire poll based on the poll id or hash
344
	 * @NoAdminRequired
345
	 * @NoCSRFRequired
346
	 * @param String $pollIdOrHash poll id or hash
347
	 * @return Array
348
	 */
349
	public function getPoll($pollIdOrHash) {
350
351
		if (!\OC::$server->getUserSession()->getUser() instanceof IUser) {
352
			$currentUser = '';
353
		} else {
354
			$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
355
		}
356
357
		$data = array();
358
359
		try {
360
361
			if (is_numeric($pollIdOrHash)) {
362
				$pollId = $this->eventMapper->find(intval($pollIdOrHash))->id;
363
				$result = 'foundById';
364
			} else {
365
				$pollId = $this->eventMapper->findByHash($pollIdOrHash)->id;
366
				$result = 'foundByHash';
367
			}
368
369
			$event = $this->getEvent($pollId);
370
371
			if ($event['owner'] !== $currentUser && !$this->groupManager->isAdmin($currentUser)) {
372
				$mode = 'create';
373
			} else {
374
				$mode = 'edit';
375
			}
376
377
			$data['poll'] = [
378
				'result' => $result,
379
				'grantedAs' => $this->grantAccessAs($event['id']),
380
				'mode' => $mode,
381
				'event' => $event,
382
				'comments' => $this->getComments($event['id']),
383
				'votes' => $this->getVotes($event['id']),
384
				'shares' => $this->getShares($event['id']),
385
				'options' => [
386
					'pollDates' => [],
387
					'pollTexts' => $this->getOptions($event['id'])
388
				]
389
			];
390
		} catch (DoesNotExistException $e) {
391
				$data['poll'] = ['result' => 'notFound'];
392
		} finally {
393
			return $data;
394
		}
395
	}
396
397
  	/**
398
	 * Get a list of NC users and groups
399
	 * @NoAdminRequired
400
	 * @NoCSRFRequired
401
	 * @return DataResponse
402
	 */
403
	public function getSiteUsersAndGroups($query = '', $getGroups = true, $getUsers = true, $skipGroups = array(), $skipUsers = array()) {
404
		$list = array();
405
		$data = array();
406
		if ($getGroups) {
407
			$groups = $this->groupManager->search($query);
408
			foreach ($groups as $group) {
409
				if (!in_array($group->getGID(), $skipGroups)) {
410
					$list['g_' . $group->getGID()] = [
411
						'id' => $group->getGID(),
412
						'user' => $group->getGID(),
413
						'type' => 'group',
414
						'desc' => 'group',
415
						'icon' => 'icon-group',
416
						'displayName' => $group->getGID(),
417
						'avatarURL' => ''
418
					];
419
				}
420
			}
421
		}
422
423
		if ($getUsers) {
424
			$users = $this->userManager->searchDisplayName($query);
425
			foreach ($users as $user) {
426
				if (!in_array($user->getUID(), $skipUsers)) {
427
					$list['u_' . $user->getUID()] = [
428
						'id' => $user->getUID(),
429
						'user' => $user->getUID(),
430
						'type' => 'user',
431
						'desc' => 'user',
432
						'icon' => 'icon-user',
433
						'displayName' => $user->getDisplayName(),
434
						'avatarURL' => '',
435
						'lastLogin' => $user->getLastLogin(),
436
						'cloudId' => $user->getCloudId()
437
					];
438
				}
439
			}
440
		}
441
442
		$data['siteusers'] = $list;
443
		return new DataResponse($data, Http::STATUS_OK);
444
	}
445
446
	/**
447
	 * Get all polls
448
	 * @NoAdminRequired
449
	 * @NoCSRFRequired
450
	 * @PublicPage
451
	 * @return DataResponse
452
	 */
453
454
	public function getPolls() {
455
		if (!\OC::$server->getUserSession()->getUser() instanceof IUser) {
456
			return new DataResponse(null, Http::STATUS_UNAUTHORIZED);
457
		}
458
459
		try {
460
			$events = $this->eventMapper->findAll();
461
		} catch (DoesNotExistException $e) {
462
			return new DataResponse($e, Http::STATUS_NOT_FOUND);
463
		}
464
465
		$eventsList = array();
466
467
		foreach ($events as $eventElement) {
468
			$eventsList[$eventElement->id] = $this->getEvent($eventElement->id);
469
		}
470
471
		return new DataResponse($eventsList, Http::STATUS_OK);
472
	}
473
474
	/**
475
	 * Write poll (create/update)
476
	 * @NoAdminRequired
477
	 * @NoCSRFRequired
478
	 * @param Array $event
479
	 * @param Array $options
480
	 * @param Array  $shares
481
	 * @param String $mode
482
	 * @return DataResponse
483
	 */
484
	public function writePoll($event, $options, $shares, $mode) {
485
		if (!\OC::$server->getUserSession()->getUser() instanceof IUser) {
486
			return new DataResponse(null, Http::STATUS_UNAUTHORIZED);
487
		} else {
488
			$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
489
			$AdminAccess = $this->groupManager->isAdmin($currentUser);
490
		}
491
492
		$newEvent = new Event();
493
494
		// Set the configuration options entered by the user
495
		$newEvent->setTitle($event['title']);
496
		$newEvent->setDescription($event['description']);
497
498
		$newEvent->setType($event['type']);
499
		$newEvent->setIsAnonymous($event['isAnonymous']);
500
		$newEvent->setFullAnonymous($event['fullAnonymous']);
501
		$newEvent->setAllowMaybe($event['allowMaybe']);
502
503
		if ($event['access'] === 'select') {
504
			$shareAccess = '';
505
			foreach ($shares as $shareElement) {
506
				if ($shareElement['type'] === 'user') {
507
					$shareAccess = $shareAccess . 'user_' . $shareElement['id'] . ';';
508
				} elseif ($shareElement['type'] === 'group') {
509
					$shareAccess = $shareAccess . 'group_' . $shareElement['id'] . ';';
510
				}
511
			}
512
			$newEvent->setAccess(rtrim($shareAccess, ';'));
513
		} else {
514
			$newEvent->setAccess($event['access']);
515
		}
516
517
		if ($event['expiration']) {
518
			$newEvent->setExpire($event['expirationDate']);
519
		} else {
520
			$newEvent->setExpire(null);
521
		}
522
523
		if ($event['type'] === 'datePoll') {
524
			$newEvent->setType(0);
525
		} elseif ($event['type'] === 'textPoll') {
526
			$newEvent->setType(1);
527
		}
528
529
		if ($mode === 'edit') {
530
			// Edit existing poll
531
			$oldPoll = $this->eventMapper->findByHash($event['hash']);
532
533
			// Check if current user is allowed to edit existing poll
534
			if ($oldPoll->getOwner() !== $currentUser && !$AdminAccess) {
535
				// If current user is not owner of existing poll deny access
536
				return new DataResponse(null, Http::STATUS_UNAUTHORIZED);
537
			}
538
539
			// else take owner, hash and id of existing poll
540
			$newEvent->setOwner($oldPoll->getOwner());
541
			$newEvent->setHash($oldPoll->getHash());
542
			$newEvent->setId($oldPoll->getId());
543
			$this->eventMapper->update($newEvent);
544
			$this->optionMapper->deleteByPoll($newEvent->getId());
545
546
		} elseif ($mode === 'create') {
547
			// Create new poll
548
			// Define current user as owner, set new creation date and create a new hash
549
			$newEvent->setOwner($currentUser);
550
			$newEvent->setCreated(date('Y-m-d H:i:s'));
551
			$newEvent->setHash(\OC::$server->getSecureRandom()->generate(
552
				16,
553
				ISecureRandom::CHAR_DIGITS .
554
				ISecureRandom::CHAR_LOWER .
555
				ISecureRandom::CHAR_UPPER
556
			));
557
			$newEvent = $this->eventMapper->insert($newEvent);
558
		}
559
560
		// Update options
561
		if ($event['type'] === 'datePoll') {
562
			foreach ($options['pollDates'] as $optionElement) {
563
				$newOption = new Option();
564
565
				$newOption->setPollId($newEvent->getId());
566
				$newOption->setPollOptionText(date('Y-m-d H:i:s', $optionElement['timestamp']));
567
				$newOption->setTimestamp($optionElement['timestamp']);
568
569
				$this->optionMapper->insert($newOption);
570
			}
571
		} elseif ($event['type'] === "textPoll") {
572
			foreach ($options['pollTexts'] as $optionElement) {
573
				$newOption = new Option();
574
575
				$newOption->setPollId($newEvent->getId());
576
				$newOption->setpollOptionText(trim(htmlspecialchars($optionElement['text'])));
577
578
				$this->optionMapper->insert($newOption);
579
			}
580
		}
581
582
		return new DataResponse(array(
583
			'id' => $newEvent->getId(),
584
			'hash' => $newEvent->getHash()
585
		), Http::STATUS_OK);
586
587
	}
588
}
589