Passed
Pull Request — master (#1219)
by René
04:57
created

OptionService::getHighestOrder()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 8
ccs 0
cts 0
cp 0
rs 10
cc 3
nc 3
nop 1
crap 12
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 DateTime;
27
use OCP\AppFramework\Db\DoesNotExistException;
28
use OCA\Polls\Exceptions\NotAuthorizedException;
29
use OCA\Polls\Exceptions\BadRequestException;
30
use OCA\Polls\Exceptions\DuplicateEntryException;
31
use OCA\Polls\Exceptions\NotFoundException;
32
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
33
34
use OCA\Polls\Db\OptionMapper;
35
use OCA\Polls\Db\Option;
36
use OCA\Polls\Db\PollMapper;
37
use OCA\Polls\Db\Poll;
38
use OCA\Polls\Model\Acl;
39
40
class OptionService {
41
42
	/** @var OptionMapper */
43
	private $optionMapper;
44
45
	/** @var Option */
46
	private $option;
47
48
	/** @var PollMapper */
49
	private $pollMapper;
50
51
	/** @var Poll */
52
	private $poll;
53
54
	/** @var LogService */
55
	private $logService;
56
57
	/** @var Acl */
58
	private $acl;
59
60
	/**
61
	 * OptionService constructor.
62
	 * @param OptionMapper $optionMapper
63
	 * @param Option $option
64
	 * @param PollMapper $pollMapper
65
	 * @param Poll $poll
66
	 * @param LogService $logService
67
	 * @param Acl $acl
68
	 */
69
70
	public function __construct(
71
		OptionMapper $optionMapper,
72
		Option $option,
73
		PollMapper $pollMapper,
74
		Poll $poll,
75
		LogService $logService,
76
		Acl $acl
77
	) {
78
		$this->optionMapper = $optionMapper;
79
		$this->option = $option;
80
		$this->pollMapper = $pollMapper;
81
		$this->poll = $poll;
82
		$this->logService = $logService;
83
		$this->acl = $acl;
84
	}
85
86
	/**
87
	 * Get all options of given poll
88
	 * @NoAdminRequired
89
	 * @param int $pollId
90
	 * @param string $token
91
	 * @return array Array of Option objects
92
	 * @throws NotAuthorizedException
93
	 */
94
	public function list($pollId = 0, $token = '') {
95
		$acl = $this->acl->set($pollId, $token);
96
97
		if (!$acl->getAllowView()) {
98
			throw new NotAuthorizedException;
99
		}
100
101
		try {
102
			return $this->optionMapper->findByPoll($acl->getPollId());
103
		} catch (DoesNotExistException $e) {
104
			return [];
105
		}
106
	}
107
108
	/**
109
	 * Get option
110
	 * @NoAdminRequired
111
	 * @param int $optionId
112
	 * @return Option
113
	 * @throws NotAuthorizedException
114
	 */
115
	public function get($optionId) {
116
		if (!$this->acl->set($this->optionMapper->find($optionId)->getPollId())->getAllowView()) {
117
			throw new NotAuthorizedException;
118
		}
119
120
		return $this->optionMapper->find($optionId);
121
	}
122
123
124
	/**
125
	 * Add a new option
126
	 * @NoAdminRequired
127
	 * @param int $pollId
128
	 * @param int $timestamp
129
	 * @param string $pollOptionText
130
	 * @return Option
131
	 * @throws NotAuthorizedException
132
	 */
133
	public function add($pollId, $timestamp = 0, $pollOptionText = '') {
134
		$this->poll = $this->pollMapper->find($pollId);
135
		if (!$this->acl->set($pollId)->getAllowEdit()) {
136
			throw new NotAuthorizedException;
137
		}
138
139
		$this->option = new Option();
140
		$this->option->setPollId($pollId);
141
		$this->setOption($timestamp, $pollOptionText, 0);
142
143
		try {
144
			return $this->optionMapper->insert($this->option);
145
		} catch (UniqueConstraintViolationException $e) {
146
			throw new DuplicateEntryException('This option already exists');
147
		}
148
	}
149
150
	/**
151
	 * Update option
152
	 * @NoAdminRequired
153
	 * @param int $optionId
154
	 * @param int $timestamp
155
	 * @param string $pollOptionText
156
	 * @param int $order
157
	 * @return Option
158
	 * @throws NotAuthorizedException
159
	 */
160
	public function update($optionId, $timestamp = 0, $pollOptionText = '', $order = 0) {
161
		$this->option = $this->optionMapper->find($optionId);
162
		$this->poll = $this->pollMapper->find($this->option->getPollId());
163
164
		if (!$this->acl->set($this->option->getPollId())->getAllowEdit()) {
165
			throw new NotAuthorizedException;
166
		}
167
168
		$this->setOption($timestamp, $pollOptionText, $order);
169
170
		return $this->optionMapper->update($this->option);
171
	}
172
173
	/**
174
	 * Delete option
175
	 * @NoAdminRequired
176
	 * @param int $optionId
177
	 * @return Option deleted Option
178
	 * @throws NotAuthorizedException
179
	 */
180
	public function delete($optionId) {
181
		$this->option = $this->optionMapper->find($optionId);
182
183
		if (!$this->acl->set($this->option->getPollId())->getAllowEdit()) {
184
			throw new NotAuthorizedException;
185
		}
186
187
		$this->optionMapper->delete($this->option);
188
189
		return $this->option;
190
	}
191
192
	/**
193
	 * Switch optoin confirmation
194
	 * @NoAdminRequired
195
	 * @param int $optionId
196
	 * @return Option confirmed Option
197
	 * @throws NotAuthorizedException
198
	 */
199
	public function confirm($optionId) {
200
		$this->option = $this->optionMapper->find($optionId);
201
202
		if (!$this->acl->set($this->option->getPollId())->getAllowEdit()) {
203
			throw new NotAuthorizedException;
204
		}
205
206
		if ($this->option->getConfirmed()) {
207
			$this->option->setConfirmed(0);
208
		} else {
209
			$this->option->setConfirmed(time());
210
		}
211
212
		return $this->optionMapper->update($this->option);
213
	}
214
215
	/**
216
	 * Make a sequence of date poll options
217
	 * @NoAdminRequired
218
	 * @param int $optionId
219
	 * @param int $step
220
	 * @param string $unit
221
	 * @param int $amount
222
	 * @return array Array of Option objects
223
	 * @throws NotAuthorizedException
224
	 */
225
	public function sequence($optionId, $step, $unit, $amount) {
226
		$baseDate = new DateTime;
227
		$origin = $this->optionMapper->find($optionId);
228
229
		if (!$this->acl->set($origin->getPollId())->getAllowEdit()) {
230
			throw new NotAuthorizedException;
231
		}
232
233
		if ($step === 0) {
234
			return $this->optionMapper->findByPoll($origin->getPollId());
235
		}
236
237
		$baseDate->setTimestamp($origin->getTimestamp());
238
239
		for ($i = 0; $i < $amount; $i++) {
240
			$this->option = new Option();
241
			$this->option->setPollId($origin->getPollId());
242
			$this->option->setConfirmed(0);
243
			$this->option->setTimestamp($baseDate->modify($step . ' ' . $unit)->getTimestamp());
244
			$this->option->setPollOptionText($baseDate->format('c'));
245
			$this->option->setOrder($baseDate->getTimestamp());
246
			try {
247
				$this->optionMapper->insert($this->option);
248
			} catch (UniqueConstraintViolationException $e) {
249
				\OC::$server->getLogger()->warning('skip adding ' . $baseDate->format('c') . 'for pollId' . $origin->getPollId() . '. Option alredy exists.');
250
			}
251
		}
252
		return $this->optionMapper->findByPoll($origin->getPollId());
253
	}
254
255
	/**
256
	 * Copy options from $fromPoll to $toPoll
257
	 * @NoAdminRequired
258
	 * @param int $fromPollId
259
	 * @param int $toPollId
260
	 * @return array Array of Option objects
261
	 * @throws NotAuthorizedException
262
	 */
263
	public function clone($fromPollId, $toPollId) {
264
		try {
265
			if (!$this->acl->set($fromPollId)->getAllowView()) {
266
				throw new NotAuthorizedException;
267
			}
268
		} catch (DoesNotExistException $e) {
269
			throw new NotFoundException('Poll ' . $fromPollId .' does not exist');
270
		}
271
272
		foreach ($this->optionMapper->findByPoll($fromPollId) as $origin) {
273
			$option = new Option();
274
			$option->setPollId($toPollId);
275
			$option->setConfirmed(0);
276
			$option->setPollOptionText($origin->getPollOptionText());
277
			$option->setTimestamp($origin->getTimestamp());
278
			$option->setOrder($origin->getOrder());
279
			$this->optionMapper->insert($option);
280
		}
281
282
		return $this->optionMapper->findByPoll($toPollId);
283
	}
284
285
	/**
286
	 * Reorder options with the order specified by $options
287
	 * @NoAdminRequired
288
	 * @param int $pollId
289
	 * @param array $options - Array of options
290
	 * @return array Array of Option objects
291
	 * @throws NotAuthorizedException
292
	 * @throws BadRequestException
293
	 * @throws NotFoundException
294
	 */
295
	public function reorder($pollId, $options) {
296
		try {
297
			$this->poll = $this->pollMapper->find($pollId);
298
		} catch (DoesNotExistException $e) {
299
			throw new NotFoundException('Poll ' . $pollId .' not found');
300
		}
301
302
303
		if (!$this->acl->set($pollId)->getAllowEdit()) {
304
			throw new NotAuthorizedException;
305
		}
306
307
		if ($this->poll->getType() === Poll::TYPE_DATE) {
308
			throw new BadRequestException("Not allowed in date polls");
309
		}
310
311
		$i = 0;
312
		foreach ($options as $option) {
313
			$this->option = $this->optionMapper->find($option['id']);
314
			if ($pollId === intval($this->option->getPollId())) {
315
				$this->option->setOrder(++$i);
316
				$this->optionMapper->update($this->option);
317
			}
318
		}
319
320
		return $this->optionMapper->findByPoll($pollId);
321
	}
322
323
	/**
324
	 * Change order for $optionId and reorder the options
325
	 * @NoAdminRequired
326
	 * @param int $optionId
327
	 * @param int $newOrder
328
	 * @return array Array of Option objects
329
	 * @throws NotAuthorizedException
330
	 * @throws BadRequestException
331
	 * @throws NotFoundException
332
	 */
333
	public function setOrder($optionId, $newOrder) {
334
		try {
335
			$this->option = $this->optionMapper->find($optionId);
336
		} catch (DoesNotExistException $e) {
337
			throw new NotFoundException('Option ' . $optionId .' not found');
338
		}
339
340
		$pollId = $this->option->getPollId();
341
		$this->poll = $this->pollMapper->find($pollId);
342
343
		if (!$this->acl->set($pollId)->getAllowEdit()) {
344
			throw new NotAuthorizedException;
345
		}
346
347
		if ($this->poll->getType() === Poll::TYPE_DATE) {
348
			throw new BadRequestException("Not allowed in date polls");
349
		}
350
351
		if ($newOrder < 1) {
352
			$newOrder = 1;
353
		} elseif ($newOrder > $this->getHighestOrder($pollId)) {
354
			$newOrder = $this->getHighestOrder($pollId);
355
		}
356
357
		$oldOrder = $this->option->getOrder();
358
359
		foreach ($this->optionMapper->findByPoll($pollId) as $option) {
360
			$currentOrder = $option->getOrder();
361
			if ($currentOrder > $oldOrder && $currentOrder <= $newOrder) {
362
				$option->setOrder($currentOrder - 1);
363
				$this->optionMapper->update($option);
364
			} elseif (
365
					   ($currentOrder < $oldOrder && $currentOrder >= $newOrder)
366
					|| ($currentOrder < $oldOrder && $currentOrder = $newOrder)
367
				) {
368
				$option->setOrder($currentOrder + 1);
369
				$this->optionMapper->update($option);
370
			} elseif ($currentOrder === $oldOrder) {
371
				$option->setOrder($newOrder);
372
				$this->optionMapper->update($option);
373
			} else {
374
				continue;
375
			}
376
		}
377
378
		return $this->optionMapper->findByPoll($this->option->getPollId());
379
	}
380
381
	/**
382
	 * Set option entities validated
383
	 * @NoAdminRequired
384
	 * @param int $timestamp
385
	 * @param string $pollOptionText
386
	 * @param int $order
387
	 * @throws BadRequestException
388
	 */
389
	private function setOption($timestamp = 0, $pollOptionText = '', $order = 0) {
390
		if ($this->poll->getType() === Poll::TYPE_DATE) {
391
			if ($timestamp) {
392
				$this->option->setTimestamp($timestamp);
393
				$this->option->setOrder($timestamp);
394
				$this->option->setPollOptionText(date('c', $timestamp));
395
			} else {
396
				throw new BadRequestException("Date poll must have a timestamp");
397
			}
398
		} elseif ($this->poll->getType() === Poll::TYPE_TEXT) {
399
			if ($pollOptionText) {
400
				$this->option->setPollOptionText($pollOptionText);
401
			} else {
402
				throw new BadRequestException("Text poll must have a pollOptionText");
403
			}
404
405
			if (!$order && !$this->option->getOrder()) {
406
				$order = $this->getHighestOrder($this->option->getPollId()) + 1;
407
				$this->option->setOrder($order);
408
			}
409
		}
410
	}
411
412
	/**
413
	 * Get the highest order number in $pollId
414
	 * @NoAdminRequired
415
	 * @param int $pollId
416
	 * @return int Highest order number
417
	 */
418
	private function getHighestOrder($pollId) {
419
		$order = 0;
420
		foreach ($this->optionMapper->findByPoll($pollId) as $option) {
421
			if ($option->getOrder() > $order) {
422
				$order = $option->getOrder();
423
			}
424
		}
425
		return $order;
426
	}
427
}
428