VoteService::checkLimits()   B
last analyzed

Complexity

Conditions 8
Paths 27

Size

Total Lines 35
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 0
Metric Value
eloc 17
dl 0
loc 35
ccs 0
cts 25
cp 0
rs 8.4444
c 0
b 0
f 0
cc 8
nc 27
nop 2
crap 72
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\Service;
25
26
use OCP\AppFramework\Db\DoesNotExistException;
27
use OCA\Polls\Exceptions\NotAuthorizedException;
28
use OCA\Polls\Exceptions\VoteLimitExceededException;
29
30
use OCA\Polls\Db\Log;
31
use OCA\Polls\Db\OptionMapper;
32
use OCA\Polls\Db\VoteMapper;
33
use OCA\Polls\Db\PollMapper;
34
use OCA\Polls\Db\Vote;
35
use OCA\Polls\Db\Watch;
36
use OCA\Polls\Model\Acl;
37
38
class VoteService {
39
40
	/** @var Acl */
41
	private $acl;
42
43
	/** @var AnonymizeService */
44
	private $anonymizer;
45
46
	/** @var LogService */
47
	private $logService;
48
49
	/** @var OptionMapper */
50
	private $optionMapper;
51
52
	/** @var PollMapper */
53
	private $pollMapper;
54
55
	/** @var Vote */
56
	private $vote;
57
58
	/** @var VoteMapper */
59
	private $voteMapper;
60
61
	/** @var WatchService */
62
	private $watchService;
63
64
65
	public function __construct(
66
		Acl $acl,
67
		AnonymizeService $anonymizer,
68
		LogService $logService,
69
		OptionMapper $optionMapper,
70
		PollMapper $pollMapper,
71
		Vote $vote,
72
		VoteMapper $voteMapper,
73
		WatchService $watchService
74
	) {
75
		$this->acl = $acl;
76
		$this->anonymizer = $anonymizer;
77
		$this->logService = $logService;
78
		$this->optionMapper = $optionMapper;
79
		$this->pollMapper = $pollMapper;
80
		$this->vote = $vote;
81
		$this->voteMapper = $voteMapper;
82
		$this->watchService = $watchService;
83
	}
84
85
	/**
86
	 * Read all votes of a poll based on the poll id and return list as array
87
	 */
88
	public function list(int $pollId = 0, string $token = ''): array {
89
		if ($token) {
90
			$this->acl->setToken($token);
91
		} else {
92
			$this->acl->setPollId($pollId)->request(Acl::PERMISSION_VIEW);
93
		}
94
95
		try {
96
			if (!$this->acl->isAllowed(Acl::PERMISSION_SEE_RESULTS)) {
97
				return $this->voteMapper->findByPollAndUser($this->acl->getpollId(), $this->acl->getUserId());
98
			} elseif (!$this->acl->isAllowed(Acl::PERMISSION_SEE_USERNAMES)) {
99
				$this->anonymizer->set($this->acl->getpollId(), $this->acl->getUserId());
100
				return $this->anonymizer->getVotes();
101
			} else {
102
				return $this->voteMapper->findByPoll($this->acl->getpollId());
103
			}
104
		} catch (DoesNotExistException $e) {
105
			return [];
106
		}
107
	}
108
109
	private function checkLimits(int $optionId, string $userId):void {
110
		$option = $this->optionMapper->find($optionId);
111
		$poll = $this->pollMapper->find($option->getPollId());
112
113
		// check, if the optionlimit is reached or exceeded, if one is set
114
		if ($poll->getOptionLimit() > 0) {
115
			if ($poll->getOptionLimit() <= count($this->voteMapper->getYesVotesByOption($option->getPollId(), $option->getPollOptionText()))) {
116
				throw new VoteLimitExceededException;
117
			}
118
		}
119
120
		// check if the votelimit for the user is reached or exceeded, if one is set
121
		if ($poll->getVoteLimit() > 0) {
122
			$pollOptionTexts = [];
123
			$votecount = 0;
124
125
			$options = $this->optionMapper->findByPoll($option->getPollId());
126
			$votes = $this->voteMapper->getYesVotesByParticipant($option->getPollId(), $userId);
127
128
			// Only count votes, which match to an actual existing option.
129
			// Explanation: If an option is deleted, the corresponding votes are not deleted.
130
131
			// create an array of pollOptionTexts
132
			foreach ($options as $element) {
133
				$pollOptionTexts[] = $element->getPollOptionText();
134
			}
135
136
			// only count relevant votes for the limit
137
			foreach ($votes as $vote) {
138
				if (in_array($vote->getVoteOptionText(), $pollOptionTexts)) {
139
					$votecount++;
140
				}
141
			}
142
			if ($poll->getVoteLimit() <= $votecount) {
143
				throw new VoteLimitExceededException;
144
			}
145
		}
146
	}
147
148
	/**
149
	 * Set vote
150
	 */
151
	public function set(int $optionId, string $setTo, string $token = ''): Vote {
152
		$option = $this->optionMapper->find($optionId);
153
154
		if ($token) {
155
			$this->acl->setToken($token)->request(Acl::PERMISSION_VOTE);
156
			if (intval($option->getPollId()) !== $this->acl->getPollId()) {
157
				throw new NotAuthorizedException;
158
			}
159
		} else {
160
			$this->acl->setPollId($option->getPollId())->request(Acl::PERMISSION_VOTE);
161
		}
162
163
		if ($setTo === 'yes') {
164
			$this->checkLimits($optionId, $this->acl->getUserId());
165
		}
166
167
		try {
168
			$this->vote = $this->voteMapper->findSingleVote($this->acl->getPollId(), $option->getPollOptionText(), $this->acl->getUserId());
169
			$this->vote->setVoteAnswer($setTo);
170
			$this->voteMapper->update($this->vote);
171
		} catch (DoesNotExistException $e) {
172
			// Vote does not exist, insert as new Vote
173
			$this->vote = new Vote();
174
175
			$this->vote->setPollId($this->acl->getPollId());
176
			$this->vote->setUserId($this->acl->getUserId());
177
			$this->vote->setVoteOptionText($option->getPollOptionText());
178
			$this->vote->setVoteOptionId($option->getId());
179
			$this->vote->setVoteAnswer($setTo);
180
			$this->voteMapper->insert($this->vote);
181
		}
182
		$this->logService->setLog($this->vote->getPollId(), Log::MSG_ID_SETVOTE, $this->vote->getUserId());
183
		$this->watchService->writeUpdate($this->vote->getPollId(), Watch::OBJECT_VOTES);
184
		return $this->vote;
185
	}
186
187
	/**
188
	 * Remove user from poll
189
	 */
190
	public function delete(int $pollId, string $userId): string {
191
		$this->acl->setPollId($pollId)->request(Acl::PERMISSION_EDIT);
192
		$this->voteMapper->deleteByPollAndUser($pollId, $userId);
193
		$this->watchService->writeUpdate($pollId, Watch::OBJECT_VOTES);
194
		return $userId;
195
	}
196
}
197