Passed
Pull Request — master (#487)
by René
04:26
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
use OCA\Polls\Db\Notification;
46
use OCA\Polls\Db\NotificationMapper;
47
48
49
50
class ApiController extends Controller {
51
52
	private $groupManager;
53
	private $userManager;
54
	private $eventMapper;
55
	private $optionMapper;
56
	private $voteMapper;
57
	private $commentMapper;
58
59
	/**
60
	 * PageController constructor.
61
	 * @param string $appName
62
	 * @param IGroupManager $groupManager
63
	 * @param IRequest $request
64
	 * @param IUserManager $userManager
65
	 * @param string $userId
66
	 * @param EventMapper $eventMapper
67
	 * @param OptionMapper $optionMapper
68
	 * @param VoteMapper $VoteMapper
69
	 * @param CommentMapper $CommentMapper
70
	 */
71
	public function __construct(
72
		$appName,
73
		IGroupManager $groupManager,
74
		IRequest $request,
75
		IUserManager $userManager,
76
		$userId,
77
		EventMapper $eventMapper,
78
		OptionMapper $optionMapper,
79
		VoteMapper $voteMapper,
80
		CommentMapper $commentMapper
81
	) {
82
		parent::__construct($appName, $request);
83
		$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...
84
		$this->groupManager = $groupManager;
85
		$this->userManager = $userManager;
86
		$this->eventMapper = $eventMapper;
87
		$this->optionMapper = $optionMapper;
88
		$this->voteMapper = $voteMapper;
89
		$this->commentMapper = $commentMapper;
90
	}
91
92
	/**
93
	 * Transforms a string with user and group names to an array
94
	 * of nextcloud users and groups
95
	 * @param string $item
96
	 * @return Array
97
	 */
98
	private function convertAccessList($item) {
99
		$split = array();
100
		if (strpos($item, 'user_') === 0) {
101
			$user = $this->userManager->get(substr($item, 5));
102
			$split = [
103
				'id' => $user->getUID(),
104
				'user' => $user->getUID(),
105
				'type' => 'user',
106
				'desc' => 'user',
107
				'icon' => 'icon-user',
108
				'displayName' => $user->getDisplayName(),
109
				'avatarURL' => '',
110
				'lastLogin' => $user->getLastLogin(),
111
				'cloudId' => $user->getCloudId()
112
			];
113
		} elseif (strpos($item, 'group_') === 0) {
114
			$group = substr($item, 6);
115
			$group = $this->groupManager->get($group);
116
			$split = [
117
				'id' => $group->getGID(),
118
				'user' => $group->getGID(),
119
				'type' => 'group',
120
				'desc' => 'group',
121
				'icon' => 'icon-group',
122
				'displayName' => $group->getDisplayName(),
123
				'avatarURL' => '',
124
			];
125
		}
126
127
		return($split);
128
	}
129
130
	/**
131
	 * Check if current user is in the access list
132
	 * @param Array $accessList
133
	 * @return Boolean
134
	 */
135
	private function checkUserAccess($accessList) {
136
		foreach ($accessList as $accessItem ) {
137
			if ($accessItem['type'] === 'user' && $accessItem['id'] === \OC::$server->getUserSession()->getUser()->getUID()) {
138
				return true;
139
			}
140
		}
141
142
		return false;
143
	}
144
145
	/**
146
	 * Check If current user is member of a group in the access list
147
	 * @param Array $accessList
148
	 * @return Boolean
149
	 */
150
	private function checkGroupAccess($accessList) {
151
		foreach ($accessList as $accessItem ) {
152
			if ($accessItem['type'] === 'group' && $this->groupManager->isInGroup(\OC::$server->getUserSession()->getUser()->getUID(),$accessItem['id'])) {
153
				return true;
154
			}
155
		}
156
157
		return false;
158
	}
159
160
	/**
161
	 * Set the access right of the current user for the poll
162
	 * @param Array $event
163
	 * @param Array $shares
164
	 * @return String
165
	 */
166
	private function grantAccessAs($event, $shares) {
167
		if (!\OC::$server->getUserSession()->getUser() instanceof IUser) {
168
			$currentUser = '';
169
		} else {
170
			$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
171
		}
172
173
		$grantAccessAs = 'none';
174
175
		if ($event['owner'] === $currentUser) {
176
			$grantAccessAs = 'owner';
177
		} elseif ($event['access'] === 'public') {
178
			$grantAccessAs = 'public';
179
		} elseif ($event['access'] === 'registered' && \OC::$server->getUserSession()->getUser() instanceof IUser) {
180
			$grantAccessAs = 'registered';
181
		} elseif ($this->checkUserAccess($shares)) {
182
			$grantAccessAs = 'userInvitation';
183
		} elseif ($this->checkGroupAccess($shares)) {
184
			$grantAccessAs = 'groupInvitation';
185
		} elseif ($this->groupManager->isAdmin($currentUser)) {
186
			$grantAccessAs = 'admin';
187
		}
188
189
		return $grantAccessAs;
190
	}
191
192
	/**
193
	 * Read all options of a poll based on the poll id
194
	 * @NoAdminRequired
195
	 * @NoCSRFRequired
196
	 * @param Integer $pollId
197
	 * @return Array
198
	 */
199
	public function getOptions($pollId) {
200
		$optionList = array();
201
		$options = $this->optionMapper->findByPoll($pollId);
202
		foreach ($options as $optionElement) {
203
			$optionList[] = [
204
				'id' => $optionElement->getId(),
205
				'text' => htmlspecialchars_decode($optionElement->getPollOptionText()),
206
				'timestamp' => $optionElement->getTimestamp()
207
			];
208
		}
209
210
		return $optionList;
211
	}
212
213
	/**
214
	 * Read all votes of a poll based on the poll id
215
	 * @NoAdminRequired
216
	 * @NoCSRFRequired
217
	 * @param Integer $pollId
218
	 * @return Array
219
	 */
220
	public function getVotes($pollId) {
221
		$votesList = array();
222
		$votes = $this->voteMapper->findByPoll($pollId);
223
		foreach ($votes as $voteElement) {
224
			$votesList[] = [
225
				'id' => $voteElement->getId(),
226
				'userId' => $voteElement->getUserId(),
227
				'voteOptionId' => $voteElement->getVoteOptionId(),
228
				'voteOptionText' => htmlspecialchars_decode($voteElement->getVoteOptionText()),
229
				'voteAnswer' => $voteElement->getVoteAnswer()
230
			];
231
		}
232
233
		return $votesList;
234
	}
235
236
	/**
237
	 * Read all comments of a poll based on the poll id
238
	 * @NoAdminRequired
239
	 * @NoCSRFRequired
240
	 * @param Integer $pollId
241
	 * @return Array
242
	 */
243
	public function getComments($pollId) {
244
		$commentsList = array();
245
		$comments = $this->commentMapper->findByPoll($pollId);
246
		foreach ($comments as $commentElement) {
247
			$commentsList[] = [
248
				'id' => $commentElement->getId(),
249
				'userId' => $commentElement->getUserId(),
250
				'date' => $commentElement->getDt() . ' UTC',
251
				'comment' => $commentElement->getComment()
252
			];
253
		}
254
255
		return $commentsList;
256
	}
257
258
	/**
259
	 * Read an entire poll based on poll id
260
	 * @NoAdminRequired
261
	 * @NoCSRFRequired
262
	 * @param Integer $pollId
263
	 * @return Array
264
	 */
265
	public function getEvent($pollId) {
266
267
		$data = array();
268
269
		try {
270
			$event = $this->eventMapper->find($pollId);
271
272
			if ($event->getType() == 0) {
273
				$pollType = 'datePoll';
274
			} else {
275
				$pollType = 'textPoll';
276
			}
277
278
			$accessType = $event->getAccess();
279
			if (!strpos('|public|hidden|registered', $accessType)) {
280
				$accessType = 'select';
281
			}
282
283
			if ($event->getExpire() === null) {
0 ignored issues
show
introduced by
The condition $event->getExpire() === null is always false.
Loading history...
284
				$expired = false;
285
				$expiration = false;
286
			} else {
287
				$expired = time() > strtotime($event->getExpire());
288
				$expiration = true;
289
			}
290
291
			$data = [
292
				'id' => $event->getId(),
293
				'hash' => $event->getHash(),
294
				'type' => $pollType,
295
				'title' => $event->getTitle(),
296
				'description' => $event->getDescription(),
297
				'owner' => $event->getOwner(),
298
				'ownerDisplayName' => $this->userManager->get($event->getOwner())->getDisplayName(),
299
				'created' => $event->getCreated(),
300
				'access' => $accessType,
301
				'expiration' => $expiration,
302
				'expired' => $expired,
303
				'expirationDate' => $event->getExpire(),
304
				'isAnonymous' => $event->getIsAnonymous(),
305
				'fullAnonymous' => $event->getFullAnonymous(),
306
				'allowMaybe' => $event->getAllowMaybe()
307
			];
308
309
		} catch (DoesNotExistException $e) {
310
			// return silently
311
		} finally {
312
			return $data;
313
		}
314
315
	}
316
317
	/**
318
	 * Read all shares (users and groups with access) of a poll based on the poll id
319
	 * @NoAdminRequired
320
	 * @NoCSRFRequired
321
	 * @param Integer $pollId
322
	 * @return Array
323
	 */
324
	public function getShares($pollId) {
325
326
		$accessList = array();
327
328
		try {
329
			$poll = $this->eventMapper->find($pollId);
330
			if (!strpos('|public|hidden|registered', $poll->getAccess())) {
331
				$accessList = explode(';', $poll->getAccess());
332
				$accessList = array_filter($accessList);
333
				$accessList = array_map(array($this, 'convertAccessList'), $accessList);
334
			}
335
		} catch (DoesNotExistException $e) {
336
			// return silently
337
		} finally {
338
			return $accessList;
339
		}
340
341
	}
342
343
	/**
344
	 * Read an entire poll based on the poll id or hash
345
	 * @NoAdminRequired
346
	 * @NoCSRFRequired
347
	 * @param String $pollIdOrHash poll id or hash
348
	 * @return Array
349
	 */
350
	public function getPoll($pollIdOrHash) {
351
352
		if (!\OC::$server->getUserSession()->getUser() instanceof IUser) {
353
			$currentUser = '';
354
		} else {
355
			$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
356
		}
357
358
		$data = array();
359
360
		try {
361
362
			if (is_numeric($pollIdOrHash)) {
363
				$pollId = $this->eventMapper->find(intval($pollIdOrHash))->id;
364
				$result = 'foundById';
365
			} else {
366
				$pollId = $this->eventMapper->findByHash($pollIdOrHash)->id;
367
				$result = 'foundByHash';
368
			}
369
370
			$event = $this->getEvent($pollId);
371
			$shares = $this->getShares($event['id']);
372
373
			if ($event['owner'] !== $currentUser && !$this->groupManager->isAdmin($currentUser)) {
374
				$mode = 'create';
375
			} else {
376
				$mode = 'edit';
377
			}
378
379
			$data = [
380
				'id' => $event['id'],
381
				'result' => $result,
382
				'grantedAs' => $this->grantAccessAs($event, $shares),
383
				'mode' => $mode,
384
				'event' => $event,
385
				'comments' => $this->getComments($event['id']),
386
				'votes' => $this->getVotes($event['id']),
387
				'shares' => $shares,
388
				'options' => [
389
					'pollDates' => [],
390
					'pollTexts' => $this->getOptions($event['id'])
391
				]
392
			];
393
		} catch (DoesNotExistException $e) {
394
				$data['poll'] = ['result' => 'notFound'];
395
		} finally {
396
			return $data;
397
		}
398
	}
399
400
	/**
401
	 * Get all polls
402
	 * @NoAdminRequired
403
	 * @NoCSRFRequired
404
	 * @return DataResponse
405
	 */
406
407
	public function getPolls() {
408
		if (!\OC::$server->getUserSession()->getUser() instanceof IUser) {
409
			return new DataResponse(null, Http::STATUS_UNAUTHORIZED);
410
		}
411
412
		try {
413
			$events = $this->eventMapper->findAll();
414
		} catch (DoesNotExistException $e) {
415
			return new DataResponse($e, Http::STATUS_NOT_FOUND);
416
		}
417
418
		$eventsList = array();
419
420
		foreach ($events as $eventElement) {
421
			$eventsList[] = $this->getPoll($eventElement->id);
422
		}
423
424
		return new DataResponse($eventsList, Http::STATUS_OK);
425
	}
426
427
	/**
428
	 * @NoAdminRequired
429
	 * @param int $pollId
430
	 * @return DataResponse
431
	 */
432
	public function removePoll($id) {
433
		$pollToDelete = $this->eventMapper->find($id);
434
		if ($this->userId !== $pollToDelete->getOwner() && !$this->groupManager->isAdmin($this->userId)) {
435
			return new DataResponse(null, Http::STATUS_UNAUTHORIZED);
436
		}
437
		$this->commentMapper->deleteByPoll($id);
438
		$this->voteMapper->deleteByPoll($id);
439
		$this->optionMapper->deleteByPoll($id);
440
		// $this->notificationMapper->deleteByPoll($id);
441
		$this->eventMapper->delete($pollToDelete);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\AppFramework\Db\Mapper::delete() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

441
		/** @scrutinizer ignore-deprecated */ $this->eventMapper->delete($pollToDelete);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
442
		// $url = $this->urlGenerator->linkToRoute('polls.page.index');
443
		return new DataResponse(array(
444
			'id' => $id,
445
			'action' => 'deleted'
446
		), Http::STATUS_OK);
447
	}
448
449
450
	/**
451
	 * Write poll (create/update)
452
	 * @NoAdminRequired
453
	 * @param Array $event
454
	 * @param Array $options
455
	 * @param Array  $shares
456
	 * @param String $mode
457
	 * @return DataResponse
458
	 */
459
	public function writePoll($event, $options, $shares, $mode) {
460
		if (!\OC::$server->getUserSession()->getUser() instanceof IUser) {
461
			return new DataResponse(null, Http::STATUS_UNAUTHORIZED);
462
		} else {
463
			$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
464
			$AdminAccess = $this->groupManager->isAdmin($currentUser);
465
		}
466
467
		$newEvent = new Event();
468
469
		// Set the configuration options entered by the user
470
		$newEvent->setTitle($event['title']);
471
		$newEvent->setDescription($event['description']);
472
473
		$newEvent->setType($event['type']);
474
		$newEvent->setIsAnonymous($event['isAnonymous']);
475
		$newEvent->setFullAnonymous($event['fullAnonymous']);
476
		$newEvent->setAllowMaybe($event['allowMaybe']);
477
478
		if ($event['access'] === 'select') {
479
			$shareAccess = '';
480
			foreach ($shares as $shareElement) {
481
				if ($shareElement['type'] === 'user') {
482
					$shareAccess = $shareAccess . 'user_' . $shareElement['id'] . ';';
483
				} elseif ($shareElement['type'] === 'group') {
484
					$shareAccess = $shareAccess . 'group_' . $shareElement['id'] . ';';
485
				}
486
			}
487
			$newEvent->setAccess(rtrim($shareAccess, ';'));
488
		} else {
489
			$newEvent->setAccess($event['access']);
490
		}
491
492
		if ($event['expiration']) {
493
			$newEvent->setExpire($event['expirationDate']);
494
		} else {
495
			$newEvent->setExpire(null);
496
		}
497
498
		if ($event['type'] === 'datePoll') {
499
			$newEvent->setType(0);
500
		} elseif ($event['type'] === 'textPoll') {
501
			$newEvent->setType(1);
502
		}
503
504
		if ($mode === 'edit') {
505
			// Edit existing poll
506
			$oldPoll = $this->eventMapper->findByHash($event['hash']);
507
508
			// Check if current user is allowed to edit existing poll
509
			if ($oldPoll->getOwner() !== $currentUser && !$AdminAccess) {
510
				// If current user is not owner of existing poll deny access
511
				return new DataResponse(null, Http::STATUS_UNAUTHORIZED);
512
			}
513
514
			// else take owner, hash and id of existing poll
515
			$newEvent->setOwner($oldPoll->getOwner());
516
			$newEvent->setHash($oldPoll->getHash());
517
			$newEvent->setId($oldPoll->getId());
518
			$this->eventMapper->update($newEvent);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\AppFramework\Db\Mapper::update() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

518
			/** @scrutinizer ignore-deprecated */ $this->eventMapper->update($newEvent);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
519
			$this->optionMapper->deleteByPoll($newEvent->getId());
520
521
		} elseif ($mode === 'create') {
522
			// Create new poll
523
			// Define current user as owner, set new creation date and create a new hash
524
			$newEvent->setOwner($currentUser);
525
			$newEvent->setCreated(date('Y-m-d H:i:s'));
526
			$newEvent->setHash(\OC::$server->getSecureRandom()->generate(
527
				16,
528
				ISecureRandom::CHAR_DIGITS .
529
				ISecureRandom::CHAR_LOWER .
530
				ISecureRandom::CHAR_UPPER
531
			));
532
			$newEvent = $this->eventMapper->insert($newEvent);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\AppFramework\Db\Mapper::insert() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

532
			$newEvent = /** @scrutinizer ignore-deprecated */ $this->eventMapper->insert($newEvent);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
533
		}
534
535
		// Update options
536
		if ($event['type'] === 'datePoll') {
537
			foreach ($options['pollDates'] as $optionElement) {
538
				$newOption = new Option();
539
540
				$newOption->setPollId($newEvent->getId());
541
				$newOption->setPollOptionText(date('Y-m-d H:i:s', $optionElement['timestamp']));
542
				$newOption->setTimestamp($optionElement['timestamp']);
543
544
				$this->optionMapper->insert($newOption);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\AppFramework\Db\Mapper::insert() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

544
				/** @scrutinizer ignore-deprecated */ $this->optionMapper->insert($newOption);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
545
			}
546
		} elseif ($event['type'] === "textPoll") {
547
			foreach ($options['pollTexts'] as $optionElement) {
548
				$newOption = new Option();
549
550
				$newOption->setPollId($newEvent->getId());
551
				$newOption->setpollOptionText(trim(htmlspecialchars($optionElement['text'])));
552
553
				$this->optionMapper->insert($newOption);
0 ignored issues
show
Deprecated Code introduced by
The function OCP\AppFramework\Db\Mapper::insert() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

553
				/** @scrutinizer ignore-deprecated */ $this->optionMapper->insert($newOption);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
554
			}
555
		}
556
557
		return new DataResponse(array(
558
			'id' => $newEvent->getId(),
559
			'hash' => $newEvent->getHash()
560
		), Http::STATUS_OK);
561
562
	}
563
}
564