1 | <?php |
||
2 | |||
3 | /** |
||
4 | * This receives requests for voting, locking, removing editing polls |
||
5 | * |
||
6 | * @package ElkArte Forum |
||
7 | * @copyright ElkArte Forum contributors |
||
8 | * @license BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file) |
||
9 | * |
||
10 | * This file contains code covered by: |
||
11 | * copyright: 2011 Simple Machines (http://www.simplemachines.org) |
||
12 | * |
||
13 | * @version 2.0 dev |
||
14 | * |
||
15 | */ |
||
16 | |||
17 | namespace ElkArte\Controller; |
||
18 | |||
19 | use ElkArte\AbstractController; |
||
20 | use ElkArte\Errors\ErrorContext; |
||
21 | use ElkArte\Exceptions\Exception; |
||
22 | use ElkArte\Helper\Util; |
||
23 | use ElkArte\Languages\Txt; |
||
24 | |||
25 | /** |
||
26 | * This receives requests for voting, locking, removing and editing polls. |
||
27 | * Note that that posting polls is done in Post.controller.php. |
||
28 | */ |
||
29 | class Poll extends AbstractController |
||
30 | { |
||
31 | /** |
||
32 | * Forward to the right action. |
||
33 | * |
||
34 | * @see AbstractController::action_index |
||
35 | */ |
||
36 | public function action_index() |
||
37 | { |
||
38 | // Figure out the right action to do. |
||
39 | } |
||
40 | |||
41 | /** |
||
42 | * Allow the user to vote. |
||
43 | * |
||
44 | * What it does: |
||
45 | * |
||
46 | * - It is called to register a vote in a poll. |
||
47 | * - Must be called with a topic and option specified. |
||
48 | * - Requires the poll_vote permission. |
||
49 | * - Upon successful completion of action will direct user back to topic. |
||
50 | * - Accessed via ?action=poll;sa=vote. |
||
51 | * |
||
52 | * @uses Post language file. |
||
53 | */ |
||
54 | public function action_vote() |
||
55 | { |
||
56 | global $topic, $modSettings; |
||
57 | |||
58 | require_once(SUBSDIR . '/Poll.subs.php'); |
||
59 | |||
60 | // Make sure you can vote. |
||
61 | isAllowedTo('poll_vote'); |
||
62 | |||
63 | Txt::load('Post'); |
||
64 | |||
65 | // Check if they have already voted, or voting is locked. |
||
66 | $row = checkVote($topic); |
||
67 | |||
68 | if (empty($row)) |
||
69 | { |
||
70 | throw new Exception('poll_error', false); |
||
71 | } |
||
72 | |||
73 | // If this is a guest can they vote? |
||
74 | if ($this->user->is_guest) |
||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||
75 | { |
||
76 | // Guest voting disabled? |
||
77 | if (!$row['guest_vote']) |
||
78 | { |
||
79 | throw new Exception('guest_vote_disabled'); |
||
80 | } |
||
81 | // Guest already voted? |
||
82 | if (!empty($_COOKIE['guest_poll_vote']) && preg_match('~^[0-9,;]+$~', $_COOKIE['guest_poll_vote']) && strpos($_COOKIE['guest_poll_vote'], ';' . $row['id_poll'] . ',') !== false) |
||
83 | { |
||
84 | // ;id,timestamp,[vote,vote...]; etc |
||
85 | $guestinfo = explode(';', $_COOKIE['guest_poll_vote']); |
||
86 | // Find the poll we're after. |
||
87 | foreach ($guestinfo as $i => $guestvoted) |
||
88 | { |
||
89 | $guestvoted = explode(',', $guestvoted); |
||
90 | if ($guestvoted[0] == $row['id_poll']) |
||
91 | { |
||
92 | break; |
||
93 | } |
||
94 | } |
||
95 | // Has the poll been reset since guest voted? |
||
96 | if (isset($guestvoted[1]) && $row['reset_poll'] > $guestvoted[1]) |
||
97 | { |
||
98 | // Remove the poll info from the cookie to allow guest to vote again |
||
99 | unset($guestinfo[$i]); |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
100 | if (!empty($guestinfo)) |
||
101 | { |
||
102 | $_COOKIE['guest_poll_vote'] = ';' . implode(';', $guestinfo); |
||
103 | } |
||
104 | else |
||
105 | { |
||
106 | unset($_COOKIE['guest_poll_vote']); |
||
107 | } |
||
108 | } |
||
109 | else |
||
110 | { |
||
111 | throw new Exception('poll_error', false); |
||
112 | } |
||
113 | |||
114 | unset($guestinfo, $guestvoted, $i); |
||
115 | } |
||
116 | } |
||
117 | |||
118 | // Is voting locked or has it expired? |
||
119 | if (!empty($row['voting_locked']) || (!empty($row['expire_time']) && time() > $row['expire_time'])) |
||
120 | { |
||
121 | throw new Exception('poll_error', false); |
||
122 | } |
||
123 | // If they have already voted and aren't allowed to change their vote - hence they are outta here! |
||
124 | if ($this->user->is_guest === false && $row['selected'] != -1 && empty($row['change_vote'])) |
||
125 | { |
||
126 | throw new Exception('poll_error', false); |
||
127 | } |
||
128 | |||
129 | // Otherwise if they can change their vote yet they haven't sent any options... remove their vote and redirect. |
||
130 | if (!empty($row['change_vote']) && $this->user->is_guest === false && empty($this->_req->post->options)) |
||
131 | { |
||
132 | checkSession('request'); |
||
133 | |||
134 | // Find out what they voted for before. |
||
135 | $pollOptions = determineVote($this->user->id, $row['id_poll']); |
||
136 | |||
137 | // Just skip it if they had voted for nothing before. |
||
138 | if (!empty($pollOptions)) |
||
139 | { |
||
140 | // Update the poll totals. |
||
141 | decreaseVoteCounter($row['id_poll'], $pollOptions); |
||
142 | |||
143 | // Delete off the log. |
||
144 | removeVote($this->user->id, $row['id_poll']); |
||
145 | } |
||
146 | // Redirect back to the topic so the user can vote again! |
||
147 | if (empty($this->_req->post->options)) |
||
148 | { |
||
149 | redirectexit('topic=' . $topic . '.' . $this->_req->post->start); |
||
150 | } |
||
151 | } |
||
152 | |||
153 | checkSession('request'); |
||
154 | |||
155 | // Make sure the option(s) are valid. |
||
156 | if (empty($this->_req->post->options)) |
||
157 | { |
||
158 | throw new Exception('didnt_select_vote', false); |
||
159 | } |
||
160 | |||
161 | // Too many options checked! |
||
162 | if (count($this->_req->post->options) > $row['max_votes']) |
||
163 | { |
||
164 | throw new Exception('poll_too_many_votes', false, array($row['max_votes'])); |
||
165 | } |
||
166 | |||
167 | $pollOptions = array(); |
||
168 | $inserts = array(); |
||
169 | foreach ($this->_req->post->options as $id) |
||
170 | { |
||
171 | $id = (int) $id; |
||
172 | |||
173 | $pollOptions[] = $id; |
||
174 | $inserts[] = array($row['id_poll'], $this->user->id, $id); |
||
175 | } |
||
176 | |||
177 | // Add their vote to the tally. |
||
178 | addVote($inserts); |
||
179 | increaseVoteCounter($row['id_poll'], $pollOptions); |
||
180 | |||
181 | // If it's a guest don't let them vote again. |
||
182 | if ($this->user->is_guest && $pollOptions !== []) |
||
183 | { |
||
184 | // Time is stored in case the poll is reset later, plus what they voted for. |
||
185 | $_COOKIE['guest_poll_vote'] = empty($_COOKIE['guest_poll_vote']) ? '' : $_COOKIE['guest_poll_vote']; |
||
186 | |||
187 | // ;id,timestamp,[vote,vote...]; etc |
||
188 | $_COOKIE['guest_poll_vote'] .= ';' . $row['id_poll'] . ',' . time() . ',' . (count($pollOptions) > 1 ? implode(',', $pollOptions) : $pollOptions[0]); |
||
189 | |||
190 | // Increase num guest voters count by 1 |
||
191 | increaseGuestVote($row['id_poll']); |
||
192 | |||
193 | // Set the guest cookie so we can track the voting |
||
194 | require_once(SUBSDIR . '/Auth.subs.php'); |
||
195 | $cookie_url = url_parts(!empty($modSettings['localCookies']), !empty($modSettings['globalCookies'])); |
||
196 | elk_setcookie('guest_poll_vote', $_COOKIE['guest_poll_vote'], time() + 2500000, $cookie_url[1], $cookie_url[0], false, false); |
||
197 | } |
||
198 | |||
199 | // Maybe let a social networking mod log this, or something? |
||
200 | call_integration_hook('integrate_poll_vote', array(&$row['id_poll'], &$pollOptions)); |
||
201 | |||
202 | // Return to the post... |
||
203 | redirectexit('topic=' . $topic . '.' . $this->_req->post->start); |
||
204 | } |
||
205 | |||
206 | /** |
||
207 | * Lock the voting for a poll. |
||
208 | * |
||
209 | * What it does: |
||
210 | * |
||
211 | * - Must be called with a topic specified in the URL. |
||
212 | * - An admin always has over riding permission to lock a poll. |
||
213 | * - If not an admin must have poll_lock_any permission, otherwise must |
||
214 | * be poll starter with poll_lock_own permission. |
||
215 | * - Upon successful completion of action will direct user back to topic. |
||
216 | * - Accessed via ?action=lockvoting. |
||
217 | */ |
||
218 | public function action_lockvoting() |
||
219 | { |
||
220 | global $topic; |
||
221 | |||
222 | require_once(SUBSDIR . '/Poll.subs.php'); |
||
223 | |||
224 | checkSession('get'); |
||
225 | |||
226 | // Get the poll starter, ID, and whether or not it is locked. |
||
227 | $poll = pollInfoForTopic($topic); |
||
228 | |||
229 | // If the user _can_ modify the poll.... |
||
230 | if (!allowedTo('poll_lock_any')) |
||
231 | { |
||
232 | isAllowedTo('poll_lock_' . ($this->user->id == $poll['id_member_started'] ? 'own' : 'any')); |
||
233 | } |
||
234 | |||
235 | // It's been locked by a non-moderator. |
||
236 | if ($poll['locked'] == '1') |
||
237 | { |
||
238 | $poll['locked'] = '0'; |
||
239 | } |
||
240 | // Locked by a moderator, and this is a moderator. |
||
241 | elseif ($poll['locked'] == '2' && allowedTo('moderate_board')) |
||
242 | { |
||
243 | $poll['locked'] = '0'; |
||
244 | } |
||
245 | // Sorry, a moderator locked it. |
||
246 | elseif ($poll['locked'] == '2' && !allowedTo('moderate_board')) |
||
247 | { |
||
248 | throw new Exception('locked_by_admin', 'user'); |
||
249 | } |
||
250 | // A moderator *is* locking it. |
||
251 | elseif ($poll['locked'] == '0' && allowedTo('moderate_board')) |
||
252 | { |
||
253 | $poll['locked'] = '2'; |
||
254 | } |
||
255 | // Well, it's gonna be locked one way or another otherwise... |
||
256 | else |
||
257 | { |
||
258 | $poll['locked'] = '1'; |
||
259 | } |
||
260 | |||
261 | // Lock! *Poof* - no one can vote. |
||
262 | lockPoll($poll['id_poll'], $poll['locked']); |
||
263 | |||
264 | redirectexit('topic=' . $topic . '.' . $this->_req->post->start); |
||
265 | } |
||
266 | |||
267 | /** |
||
268 | * Update the settings for a poll, or add a new one. |
||
269 | * |
||
270 | * What it does: |
||
271 | * |
||
272 | * - Must be called with a topic specified in the URL. |
||
273 | * - The user must have poll_edit_any/poll_add_any permission for the relevant action. Otherwise |
||
274 | * they must be poll starter with poll_edit_own permission for editing, or be topic starter |
||
275 | * with poll_add_any permission for adding. |
||
276 | * - In the case of an error, this function will redirect back to action_editpoll and |
||
277 | * display the relevant error message. |
||
278 | * - Upon successful completion of action will direct user back to topic. |
||
279 | * - Accessed via ?action=editpoll2. |
||
280 | */ |
||
281 | public function action_editpoll2() |
||
282 | { |
||
283 | global $topic, $board; |
||
284 | |||
285 | // Sneaking off, are we? |
||
286 | if (empty($this->_req->post)) |
||
287 | { |
||
288 | redirectexit('action=editpoll;topic=' . $topic . '.0'); |
||
289 | } |
||
290 | |||
291 | $poll_errors = ErrorContext::context('poll'); |
||
292 | |||
293 | if (checkSession('post', '', false) !== '') |
||
294 | { |
||
295 | $poll_errors->addError('session_timeout'); |
||
296 | } |
||
297 | |||
298 | // HACKERS (!!) can't edit :P. |
||
299 | if (empty($topic)) |
||
300 | { |
||
301 | throw new Exception('no_access', false); |
||
302 | } |
||
303 | |||
304 | // Is this a new poll, or editing an existing? |
||
305 | $isEdit = isset($this->_req->post->add) ? 0 : 1; |
||
306 | |||
307 | // Make sure we have our stuff. |
||
308 | require_once(SUBSDIR . '/Poll.subs.php'); |
||
309 | |||
310 | // Get the starter and the poll's ID - if it's an edit. |
||
311 | $bcinfo = getPollStarter($topic); |
||
312 | // Check their adding/editing is valid. |
||
313 | if (!$isEdit && !empty($bcinfo['id_poll'])) |
||
314 | { |
||
315 | throw new Exception('poll_already_exists'); |
||
316 | } |
||
317 | |||
318 | // Are we editing a poll which doesn't exist? |
||
319 | if ($isEdit && empty($bcinfo['id_poll'])) |
||
320 | { |
||
321 | throw new Exception('poll_not_found'); |
||
322 | } |
||
323 | |||
324 | // Check if they have the power to add or edit the poll. |
||
325 | if ($isEdit && !allowedTo('poll_edit_any')) |
||
326 | { |
||
327 | isAllowedTo('poll_edit_' . ($this->user->id == $bcinfo['id_member_started'] || ($bcinfo['poll_starter'] != 0 && $this->user->id == $bcinfo['poll_starter']) ? 'own' : 'any')); |
||
328 | } |
||
329 | elseif (!$isEdit && !allowedTo('poll_add_any')) |
||
330 | { |
||
331 | isAllowedTo('poll_add_' . ($this->user->id == $bcinfo['id_member_started'] ? 'own' : 'any')); |
||
332 | } |
||
333 | |||
334 | $optionCount = 0; |
||
335 | $idCount = 0; |
||
336 | |||
337 | // Ensure the user is leaving a valid amount of options - there must be at least two. |
||
338 | foreach ($this->_req->post->options as $k => $option) |
||
339 | { |
||
340 | if (trim($option) !== '') |
||
341 | { |
||
342 | $optionCount++; |
||
343 | $idCount = max($idCount, $k); |
||
344 | } |
||
345 | } |
||
346 | |||
347 | if ($optionCount < 2) |
||
348 | { |
||
349 | $poll_errors->addError('poll_few'); |
||
350 | } |
||
351 | elseif ($optionCount > 256 || $idCount > 255) |
||
352 | { |
||
353 | $poll_errors->addError('poll_many'); |
||
354 | } |
||
355 | |||
356 | // Also - ensure they are not removing the question. |
||
357 | if ($this->_req->getPost('question', 'trim') === '') |
||
358 | { |
||
359 | $poll_errors->addError('no_question'); |
||
360 | } |
||
361 | |||
362 | // Got any errors to report? |
||
363 | if ($poll_errors->hasErrors()) |
||
364 | { |
||
365 | $this->action_editpoll(); |
||
366 | } |
||
367 | |||
368 | // Prevent double submission of this form. |
||
369 | checkSubmitOnce('check'); |
||
370 | |||
371 | // Now we've done all our error checking, let's get the core poll information cleaned... question first. |
||
372 | $question = Util::htmlspecialchars($this->_req->getPost('question', 'trim')); |
||
373 | $question = Util::substr($question, 0, 255); |
||
374 | |||
375 | $poll_hide = $this->_req->getPost('poll_hide', 'intval', 0); |
||
376 | $poll_expire = $this->_req->getPost('poll_expire', 'intval', 0); |
||
377 | $poll_change_vote = isset($this->_req->post->poll_change_vote) ? 1 : 0; |
||
378 | $poll_guest_vote = isset($this->_req->post->poll_guest_vote) ? 1 : 0; |
||
379 | $poll_max_votes = 0; |
||
380 | |||
381 | // Make sure guests are actually allowed to vote generally. |
||
382 | if ($poll_guest_vote !== 0) |
||
383 | { |
||
384 | require_once(SUBSDIR . '/Members.subs.php'); |
||
385 | $allowedGroups = groupsAllowedTo('poll_vote', $board); |
||
386 | if (!in_array(-1, $allowedGroups['allowed'])) |
||
387 | { |
||
388 | $poll_guest_vote = 0; |
||
389 | } |
||
390 | } |
||
391 | |||
392 | // Ensure that the number options allowed makes sense, and the expiration date is valid. |
||
393 | if (!$isEdit || allowedTo('moderate_board')) |
||
394 | { |
||
395 | $poll_expire = $poll_expire > 9999 ? 9999 : ($poll_expire < 0 ? 0 : $poll_expire); |
||
396 | |||
397 | if (empty($poll_expire) && $poll_hide == 2) |
||
398 | { |
||
399 | $poll_hide = 1; |
||
400 | } |
||
401 | elseif (!$isEdit || $poll_expire != ceil($bcinfo['expire_time'] <= time() ? -1 : ($bcinfo['expire_time'] - time()) / (3600 * 24))) |
||
402 | { |
||
403 | $poll_expire = empty($poll_expire) ? 0 : time() + $_POST['poll_expire'] * 3600 * 24; |
||
404 | } |
||
405 | else |
||
406 | { |
||
407 | $poll_expire = $bcinfo['expire_time']; |
||
408 | } |
||
409 | |||
410 | if (empty($this->_req->post->poll_max_votes) || $this->_req->post->poll_max_votes <= 0) |
||
411 | { |
||
412 | $poll_max_votes = 1; |
||
413 | } |
||
414 | else |
||
415 | { |
||
416 | $poll_max_votes = $this->_req->getPost('poll_max_votes', 'intval', 0); |
||
417 | } |
||
418 | } |
||
419 | |||
420 | // If we're editing, let's commit the changes. |
||
421 | if ($isEdit !== 0) |
||
422 | { |
||
423 | modifyPoll($bcinfo['id_poll'], $question, |
||
424 | empty($poll_max_votes) ? 0 : $poll_max_votes, |
||
425 | $poll_hide, |
||
426 | empty($poll_expire) ? 0 : $poll_expire, |
||
427 | $poll_change_vote, $poll_guest_vote |
||
428 | ); |
||
429 | } |
||
430 | // Otherwise, let's get our poll going! |
||
431 | else |
||
432 | { |
||
433 | // Create the poll. |
||
434 | $bcinfo['id_poll'] = createPoll($question, $this->user->id, $this->user->username, |
||
435 | $poll_max_votes, $poll_hide, $poll_expire, |
||
436 | $poll_change_vote, $poll_guest_vote |
||
437 | ); |
||
438 | |||
439 | // Link the poll to the topic. |
||
440 | associatedPoll($topic, $bcinfo['id_poll']); |
||
441 | } |
||
442 | |||
443 | // Get all the choices. (no better way to remove all emptied and add previously non-existent ones.) |
||
444 | $choices = array_keys(pollOptions($bcinfo['id_poll'])); |
||
445 | |||
446 | $add_options = array(); |
||
447 | $update_options = array(); |
||
448 | $delete_options = array(); |
||
449 | foreach ($this->_req->post->options as $k => $option) |
||
450 | { |
||
451 | // Make sure the key is numeric for sanity's sake. |
||
452 | $k = (int) $k; |
||
453 | |||
454 | // They've cleared the box. Either they want it deleted, or it never existed. |
||
455 | if (trim($option) === '') |
||
456 | { |
||
457 | // They want it deleted. Bye. |
||
458 | if (in_array($k, $choices)) |
||
459 | { |
||
460 | $delete_options[] = $k; |
||
461 | } |
||
462 | |||
463 | // Skip the rest... |
||
464 | continue; |
||
465 | } |
||
466 | |||
467 | // Dress the option up for its big date with the database. |
||
468 | $option = Util::htmlspecialchars($option); |
||
469 | |||
470 | // If it's already there, update it. If it's not... add it. |
||
471 | if (in_array($k, $choices)) |
||
472 | { |
||
473 | $update_options[] = array($bcinfo['id_poll'], $k, $option); |
||
474 | } |
||
475 | else |
||
476 | { |
||
477 | $add_options[] = array($bcinfo['id_poll'], $k, $option, 0); |
||
478 | } |
||
479 | } |
||
480 | |||
481 | if (!empty($update_options)) |
||
482 | { |
||
483 | modifyPollOption($update_options); |
||
484 | } |
||
485 | |||
486 | if (!empty($add_options)) |
||
487 | { |
||
488 | insertPollOptions($add_options); |
||
489 | } |
||
490 | |||
491 | // I'm sorry, but... well, no one was choosing you. Poor options, I'll put you out of your misery. |
||
492 | if (!empty($delete_options)) |
||
493 | { |
||
494 | deletePollOptions($bcinfo['id_poll'], $delete_options); |
||
495 | } |
||
496 | |||
497 | // Shall I reset the vote count, sir? |
||
498 | if (isset($this->_req->post->resetVoteCount)) |
||
499 | { |
||
500 | resetVotes($bcinfo['id_poll']); |
||
501 | } |
||
502 | |||
503 | call_integration_hook('integrate_poll_add_edit', array($bcinfo['id_poll'], $isEdit)); |
||
504 | |||
505 | // Off we go. |
||
506 | redirectexit('topic=' . $topic . '.' . $this->_req->post->start); |
||
507 | } |
||
508 | |||
509 | /** |
||
510 | * Display screen for editing or adding a poll. |
||
511 | * |
||
512 | * What it does: |
||
513 | * |
||
514 | * - Must be called with a topic specified in the URL. |
||
515 | * - If the user is adding a poll to a topic, must contain the variable |
||
516 | * 'add' in the url. |
||
517 | * - User must have poll_edit_any/poll_add_any permission for the relevant action, |
||
518 | * otherwise must be poll starter with poll_edit_own permission for editing, or |
||
519 | * be topic starter with poll_add_any permission for adding. |
||
520 | * - Accessed via ?action=editpoll. |
||
521 | * |
||
522 | * @uses Post language file. |
||
523 | * @uses template_poll_edit() sub-template in Poll.template, |
||
524 | */ |
||
525 | public function action_editpoll() |
||
526 | { |
||
527 | global $txt, $context, $topic, $board; |
||
528 | |||
529 | // No topic, means you can't edit the poll |
||
530 | if (empty($topic)) |
||
531 | { |
||
532 | throw new Exception('no_access', false); |
||
533 | } |
||
534 | |||
535 | // We work hard with polls. |
||
536 | require_once(SUBSDIR . '/Poll.subs.php'); |
||
537 | |||
538 | Txt::load('Post'); |
||
539 | theme()->getTemplates()->load('Poll'); |
||
540 | loadJavascriptFile('post.js', array(), 'post_scripts'); |
||
541 | |||
542 | $context['sub_template'] = 'poll_edit'; |
||
543 | $context['start'] = $this->_req->getQuery('start', 'intval'); |
||
544 | $context['is_edit'] = isset($this->_req->post->add) ? 0 : 1; |
||
545 | |||
546 | $poll_errors = ErrorContext::context('poll'); |
||
547 | $pollinfo = pollInfoForTopic($topic); |
||
548 | |||
549 | // Assume it all exists, right? |
||
550 | if (empty($pollinfo)) |
||
551 | { |
||
552 | throw new Exception('no_board'); |
||
553 | } |
||
554 | |||
555 | // If we are adding a new poll - make sure that there isn't already a poll there. |
||
556 | if (!$context['is_edit'] && !empty($pollinfo['id_poll'])) |
||
557 | { |
||
558 | throw new Exception('poll_already_exists'); |
||
559 | } |
||
560 | |||
561 | // Otherwise, if we're editing it, it does exist I assume? |
||
562 | if ($context['is_edit'] && empty($pollinfo['id_poll'])) |
||
563 | { |
||
564 | throw new Exception('poll_not_found'); |
||
565 | } |
||
566 | |||
567 | // Can you do this? |
||
568 | if ($context['is_edit'] && !allowedTo('poll_edit_any')) |
||
569 | { |
||
570 | isAllowedTo('poll_edit_' . ($this->user->id == $pollinfo['id_member_started'] || ($pollinfo['poll_starter'] != 0 && $this->user->id == $pollinfo['poll_starter']) ? 'own' : 'any')); |
||
0 ignored issues
–
show
The property
id does not exist on ElkArte\Helper\ValuesContainer . Since you implemented __get , consider adding a @property annotation.
![]() |
|||
571 | } |
||
572 | elseif (!$context['is_edit'] && !allowedTo('poll_add_any')) |
||
573 | { |
||
574 | isAllowedTo('poll_add_' . ($this->user->id == $pollinfo['id_member_started'] ? 'own' : 'any')); |
||
575 | } |
||
576 | |||
577 | $context['can_moderate_poll'] = isset($this->_req->post->add) ? true : allowedTo('poll_edit_' . ($this->user->id == $pollinfo['id_member_started'] || ($pollinfo['poll_starter'] != 0 && $this->user->id == $pollinfo['poll_starter']) ? 'own' : 'any')); |
||
578 | |||
579 | // Do we enable guest voting? |
||
580 | require_once(SUBSDIR . '/Members.subs.php'); |
||
581 | $groupsAllowedVote = groupsAllowedTo('poll_vote', $board); |
||
582 | |||
583 | // Want to make sure before you actually submit? Must be a lot of options, or something. |
||
584 | if ($poll_errors->hasErrors()) |
||
585 | { |
||
586 | $question = Util::htmlspecialchars($this->_req->post->question); |
||
587 | |||
588 | // Basic theme info... |
||
589 | $context['poll'] = array( |
||
590 | 'id' => $pollinfo['id_poll'], |
||
591 | 'question' => $question, |
||
592 | 'hide_results' => empty($this->_req->post->poll_hide) ? 0 : $this->_req->post->poll_hide, |
||
593 | 'change_vote' => isset($this->_req->post->poll_change_vote), |
||
594 | 'guest_vote' => isset($this->_req->post->poll_guest_vote), |
||
595 | 'guest_vote_allowed' => in_array(-1, $groupsAllowedVote['allowed']), |
||
596 | 'max_votes' => empty($this->_req->post->poll_max_votes) ? '1' : max(1, $this->_req->post->poll_max_votes), |
||
597 | ); |
||
598 | |||
599 | // Start at number one with no last id to speak of. |
||
600 | $number = 1; |
||
601 | $last_id = 0; |
||
602 | |||
603 | // Get all the choices - if this is an edit. |
||
604 | if ($context['is_edit']) |
||
605 | { |
||
606 | $pollOptions = pollOptions($pollinfo['id_poll']); |
||
607 | $context['poll']['choices'] = array(); |
||
608 | |||
609 | foreach ($pollOptions as $option) |
||
610 | { |
||
611 | // Get the highest id so we can add more without reusing. |
||
612 | if ($option['id_choice'] >= $last_id) |
||
613 | { |
||
614 | $last_id = $option['id_choice'] + 1; |
||
615 | } |
||
616 | |||
617 | // They cleared this by either omitting it or emptying it. |
||
618 | if (!isset($this->_req->post->options[$option['id_choice']]) || $this->_req->post->options[$option['id_choice']] == '') |
||
619 | { |
||
620 | continue; |
||
621 | } |
||
622 | |||
623 | // Add the choice! |
||
624 | $context['poll']['choices'][$option['id_choice']] = array( |
||
625 | 'id' => $option['id_choice'], |
||
626 | 'number' => $number++, |
||
627 | 'votes' => $option['votes'], |
||
628 | 'label' => $option['label'], |
||
629 | 'is_last' => false |
||
630 | ); |
||
631 | } |
||
632 | } |
||
633 | |||
634 | // Work out how many options we have, so we get the 'is_last' field right... |
||
635 | $totalPostOptions = 0; |
||
636 | foreach ($this->_req->post->options as $id => $label) |
||
637 | { |
||
638 | if ($label !== '') |
||
639 | { |
||
640 | $totalPostOptions++; |
||
641 | } |
||
642 | } |
||
643 | |||
644 | $count = 1; |
||
645 | |||
646 | // If an option exists, update it. If it is new, add it - but don't reuse ids! |
||
647 | foreach ($this->_req->post->options as $id => $label) |
||
648 | { |
||
649 | $label = censor(Util::htmlspecialchars($label)); |
||
650 | |||
651 | if (isset($context['poll']['choices'][$id])) |
||
652 | { |
||
653 | $context['poll']['choices'][$id]['label'] = $label; |
||
654 | } |
||
655 | elseif ($label !== '') |
||
656 | { |
||
657 | $context['poll']['choices'][] = array( |
||
658 | 'id' => $last_id++, |
||
659 | 'number' => $number++, |
||
660 | 'label' => $label, |
||
661 | 'votes' => -1, |
||
662 | 'is_last' => $count++ === $totalPostOptions && $totalPostOptions > 1, |
||
663 | ); |
||
664 | } |
||
665 | } |
||
666 | |||
667 | // Make sure we have two choices for sure! |
||
668 | if ($totalPostOptions < 2) |
||
669 | { |
||
670 | // Need two? |
||
671 | if ($totalPostOptions === 0) |
||
672 | { |
||
673 | $context['poll']['choices'][] = array( |
||
674 | 'id' => $last_id++, |
||
675 | 'number' => $number++, |
||
676 | 'label' => '', |
||
677 | 'votes' => -1, |
||
678 | 'is_last' => false |
||
679 | ); |
||
680 | } |
||
681 | |||
682 | $poll_errors->addError('poll_few'); |
||
683 | } |
||
684 | |||
685 | // Always show one extra box... |
||
686 | $context['poll']['choices'][] = array( |
||
687 | 'id' => $last_id++, |
||
688 | 'number' => $number, |
||
689 | 'label' => '', |
||
690 | 'votes' => -1, |
||
691 | 'is_last' => true |
||
692 | ); |
||
693 | |||
694 | $context['last_choice_id'] = $last_id; |
||
695 | |||
696 | if ($context['can_moderate_poll']) |
||
697 | { |
||
698 | $context['poll']['expiration'] = (int) $this->_req->post->poll_expire; |
||
699 | } |
||
700 | |||
701 | // Check the question/option count for errors. |
||
702 | // @todo: why !$poll_errors->hasErrors()? |
||
703 | if (trim($this->_req->post->question) === '' && !$poll_errors->hasErrors()) |
||
704 | { |
||
705 | $poll_errors->addError('no_question'); |
||
706 | } |
||
707 | |||
708 | // No check is needed, since nothing is really posted. |
||
709 | checkSubmitOnce('free'); |
||
710 | |||
711 | // Take a check for any errors... assuming we haven't already done so! |
||
712 | $context['poll_error'] = array( |
||
713 | 'errors' => $poll_errors->prepareErrors(), |
||
714 | 'type' => $poll_errors->getErrorType() == 0 ? 'minor' : 'serious', |
||
715 | 'title' => $context['is_edit'] ? $txt['error_while_editing_poll'] : $txt['error_while_adding_poll'], |
||
716 | ); |
||
717 | } |
||
718 | else |
||
719 | { |
||
720 | // Basic theme info... |
||
721 | $context['poll'] = array( |
||
722 | 'id' => $pollinfo['id_poll'], |
||
723 | 'question' => $pollinfo['question'], |
||
724 | 'hide_results' => $pollinfo['hide_results'], |
||
725 | 'max_votes' => $pollinfo['max_votes'], |
||
726 | 'change_vote' => !empty($pollinfo['change_vote']), |
||
727 | 'guest_vote' => !empty($pollinfo['guest_vote']), |
||
728 | 'guest_vote_allowed' => in_array(-1, $groupsAllowedVote['allowed']), |
||
729 | ); |
||
730 | |||
731 | // Poll expiration time? |
||
732 | $context['poll']['expiration'] = empty($pollinfo['expire_time']) || !$context['can_moderate_poll'] ? '' : ceil($pollinfo['expire_time'] <= time() ? -1 : ($pollinfo['expire_time'] - time()) / (3600 * 24)); |
||
733 | |||
734 | // Get all the choices - if this is an edit. |
||
735 | if ($context['is_edit']) |
||
736 | { |
||
737 | $context['poll']['choices'] = getPollChoices($pollinfo['id_poll']); |
||
738 | |||
739 | $last_id = max(array_keys($context['poll']['choices'])) + 1; |
||
740 | |||
741 | // Add an extra choice... |
||
742 | $context['poll']['choices'][] = array( |
||
743 | 'id' => $last_id, |
||
744 | 'number' => $context['poll']['choices'][$last_id - 1]['number'] + 1, |
||
745 | 'votes' => -1, |
||
746 | 'label' => '', |
||
747 | 'is_last' => true |
||
748 | ); |
||
749 | $context['last_choice_id'] = $last_id; |
||
750 | } |
||
751 | // New poll? |
||
752 | else |
||
753 | { |
||
754 | // Setup the default poll options. |
||
755 | $context['poll'] = array( |
||
756 | 'id' => 0, |
||
757 | 'question' => '', |
||
758 | 'hide_results' => 0, |
||
759 | 'max_votes' => 1, |
||
760 | 'change_vote' => 0, |
||
761 | 'guest_vote' => 0, |
||
762 | 'guest_vote_allowed' => in_array(-1, $groupsAllowedVote['allowed']), |
||
763 | 'expiration' => '', |
||
764 | ); |
||
765 | |||
766 | // Make all five poll choices empty. |
||
767 | $context['poll']['choices'] = array( |
||
768 | array('id' => 0, 'number' => 1, 'votes' => -1, 'label' => '', 'is_last' => false), |
||
769 | array('id' => 1, 'number' => 2, 'votes' => -1, 'label' => '', 'is_last' => false), |
||
770 | array('id' => 2, 'number' => 3, 'votes' => -1, 'label' => '', 'is_last' => false), |
||
771 | array('id' => 3, 'number' => 4, 'votes' => -1, 'label' => '', 'is_last' => false), |
||
772 | array('id' => 4, 'number' => 5, 'votes' => -1, 'label' => '', 'is_last' => true) |
||
773 | ); |
||
774 | $context['last_choice_id'] = 4; |
||
775 | } |
||
776 | } |
||
777 | |||
778 | $context['page_title'] = $context['is_edit'] ? $txt['poll_edit'] : $txt['add_poll']; |
||
779 | $context['form_url'] = getUrl('action', ['action' => 'editpoll2'] + ($context['is_edit'] ? [] : ['add']) + ['topic' => $context['current_topic'] . '.' . $context['start']]); |
||
780 | |||
781 | // Build the link tree. |
||
782 | $pollinfo['subject'] = censor($pollinfo['subject']); |
||
783 | $context['breadcrumbs'][] = array( |
||
784 | 'url' => getUrl('topic', ['topic' => $topic, 'start' => '0', 'subject' => $pollinfo['subject']]), |
||
785 | 'name' => $pollinfo['subject'], |
||
786 | ); |
||
787 | $context['breadcrumbs'][] = [ |
||
788 | 'name' => $context['page_title'], |
||
789 | ]; |
||
790 | |||
791 | // Register this form in the session variables. |
||
792 | checkSubmitOnce('register'); |
||
793 | } |
||
794 | |||
795 | /** |
||
796 | * Remove a poll from a topic without removing the topic. |
||
797 | * |
||
798 | * What it does: |
||
799 | * |
||
800 | * - Must be called with a topic specified in the URL. |
||
801 | * - Requires poll_remove_any permission, unless it's the poll starter |
||
802 | * with poll_remove_own permission. |
||
803 | * - Upon successful completion of action will direct user back to topic. |
||
804 | * - Accessed via ?action=poll;sa=remove. |
||
805 | */ |
||
806 | public function action_remove() |
||
807 | { |
||
808 | global $topic; |
||
809 | |||
810 | // Make sure the topic is not empty. |
||
811 | if (empty($topic)) |
||
812 | { |
||
813 | throw new Exception('no_access', false); |
||
814 | } |
||
815 | |||
816 | // Verify the session. |
||
817 | checkSession('get'); |
||
818 | |||
819 | // We need to work with them polls. |
||
820 | require_once(SUBSDIR . '/Poll.subs.php'); |
||
821 | |||
822 | // Check permissions. |
||
823 | if (!allowedTo('poll_remove_any')) |
||
824 | { |
||
825 | $pollStarters = pollStarters($topic); |
||
826 | if (empty($pollStarters)) |
||
827 | { |
||
828 | throw new Exception('no_access', false); |
||
829 | } |
||
830 | |||
831 | [$topicStarter, $pollStarter] = $pollStarters; |
||
832 | if ($topicStarter == $this->user->id || ($pollStarter != 0 && $pollStarter == $this->user->id)) |
||
833 | { |
||
834 | isAllowedTo('poll_remove_own'); |
||
835 | } |
||
836 | } |
||
837 | |||
838 | // Retrieve the poll ID. |
||
839 | $pollID = associatedPoll($topic); |
||
840 | |||
841 | // Remove the poll! |
||
842 | removePoll($pollID); |
||
843 | |||
844 | // Finally set the topic poll ID back to 0! |
||
845 | associatedPoll($topic, 0); |
||
846 | |||
847 | // A mod might have logged this (social network?), so let them remove, it too |
||
848 | call_integration_hook('integrate_poll_remove', array($pollID)); |
||
849 | |||
850 | // Take the moderator back to the topic. |
||
851 | redirectexit('topic=' . $topic . '.' . $this->_req->post->start); |
||
852 | } |
||
853 | |||
854 | /** |
||
855 | * The only reason of this function is to build the poll UI and send it back in an XML form |
||
856 | */ |
||
857 | public function action_interface() |
||
858 | { |
||
859 | global $context, $board, $db_show_debug; |
||
860 | |||
861 | theme()->getLayers()->removeAll(); |
||
862 | theme()->getTemplates()->load('Poll'); |
||
863 | Txt::load('Post'); |
||
864 | |||
865 | $db_show_debug = false; |
||
866 | |||
867 | $context['sub_template'] = 'poll_edit'; |
||
868 | |||
869 | require_once(SUBSDIR . '/Members.subs.php'); |
||
870 | $allowedVoteGroups = groupsAllowedTo('poll_vote', $board); |
||
871 | |||
872 | // Set up the poll options. |
||
873 | $context['poll'] = array( |
||
874 | 'max_votes' => 1, |
||
875 | 'hide_results' => 0, |
||
876 | 'expiration' => '', |
||
877 | 'change_vote' => false, |
||
878 | 'guest_vote' => false, |
||
879 | 'guest_vote_allowed' => in_array(-1, $allowedVoteGroups['allowed']), |
||
880 | ); |
||
881 | |||
882 | $context['can_moderate_poll'] = true; |
||
883 | |||
884 | // Make all five poll choices empty. |
||
885 | $context['poll']['choices'] = array( |
||
886 | array('id' => 0, 'number' => 1, 'label' => '', 'is_last' => false), |
||
887 | array('id' => 1, 'number' => 2, 'label' => '', 'is_last' => false), |
||
888 | array('id' => 2, 'number' => 3, 'label' => '', 'is_last' => false), |
||
889 | array('id' => 3, 'number' => 4, 'label' => '', 'is_last' => false), |
||
890 | array('id' => 4, 'number' => 5, 'label' => '', 'is_last' => true) |
||
891 | ); |
||
892 | $context['last_choice_id'] = 4; |
||
893 | } |
||
894 | } |
||
895 |