Add poll 9

Add form and vote handler.
This commit is contained in:
Visman 2020-11-22 18:24:29 +07:00
parent c5e0be935f
commit def812bf8c
8 changed files with 212 additions and 11 deletions
app
Controllers
Models
lang
templates/layouts
public/style/ForkBB

View file

@ -384,6 +384,15 @@ class Routing
}
}
// опросы
if ($user->usePoll) {
$r->add(
$r::PST,
'/poll/{tid:[1-9]\d*}',
'Poll:vote',
'Poll'
);
}
// админ и модератор
if ($user->isAdmMod) {
$r->add(

View file

@ -378,6 +378,7 @@ abstract class Page extends Model
{
$list = [
302 => '302 Moved Temporarily',
400 => '400 Bad Request',
403 => '403 Forbidden',
404 => '404 Not Found',
405 => '405 Method Not Allowed',

55
app/Models/Pages/Poll.php Normal file
View file

@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace ForkBB\Models\Pages;
use ForkBB\Models\Page;
use ForkBB\Models\Topic\Model as Topic;
use ForkBB\Models\Poll\Model as PollModel;
use function \ForkBB\__;
class Poll extends Page
{
/**
* Голосование
*/
public function vote(array $args, string $method): Page
{
$tid = (int) $args['tid'];
$topic = $this->c->topics->load($tid);
if (
! $topic instanceof Topic
|| ! $topic->poll instanceof PollModel
) {
return $this->c->Message->message('Bad request');
}
$this->c->Lang->load('poll');
$v = $this->c->Validator->reset()
->addValidators([
])->addRules([
'token' => 'token:Poll',
'poll_vote.*.*' => 'required|integer',
'vote' => 'required|string',
])->addAliases([
])->addArguments([
'token' => $args,
])->addMessages([
'poll_vote.*.*' => 'The poll structure is broken',
]);
if (! $v->validation($_POST)) {
$message = $this->c->Message;
$message->fIswev = $v->getErrors();
return $message->message('', true, 400);
} elseif (null !== ($result = $topic->poll->vote($v->poll_vote))) {
return $this->c->Message->message($result, true, 400);
} else {
return $this->c->Redirect->url($topic->link)->message('You voted');
}
}
}

View file

@ -13,6 +13,8 @@ use function \ForkBB\__;
class Model extends DataModel
{
const JSON_OPTIONS = \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE | \JSON_THROW_ON_ERROR;
/**
* Возвращает родительскую тему
*/
@ -50,6 +52,30 @@ class Model extends DataModel
$this->tid = $topic->id;
}
/**
* Ссылка на обработчик опроса
*/
protected function getlink(): ?string
{
if ($this->tid > 0) {
return $this->c->Router->link('Poll', ['tid' => $this->tid]);
} else {
return null;
}
}
/**
* Значение токена для формы голосования
*/
protected function gettoken(): ?string
{
if ($this->tid > 0) {
return $this->c->Csrf->create('Poll', ['tid' => $this->tid]);
} else {
return null;
}
}
/**
* Статус голосования для текущего пользователя
*/
@ -200,6 +226,9 @@ class Model extends DataModel
return $result;
}
/**
* Возвращает статус опроса для текущего пользователя или null
*/
protected function getstatus(): ?string
{
if ($this->tid < 1) {
@ -219,4 +248,71 @@ class Model extends DataModel
return __('Poll status is undefined');
}
}
/**
* Голосование
* Возвращает текст ошибки или null
*/
public function vote(array $vote): ?string
{
if (! $this->canVote) {
return __('You cannot vote on this poll');
}
$data = [];
foreach (\array_keys($this->question) as $q) {
if ($this->type[$q] > 1) {
$count = \count($vote[$q]);
if (0 == $count) {
return __('No vote on question %s', $q);
} elseif ($count > $this->type[$q]) {
return __('Too many answers selected in question %s', $q);
}
foreach (\array_keys($vote[$q]) as $a) {
if (! isset($this->answer[$q][$a])) {
return __('The selected answer is not present in question %s', $q);
}
$data[] = [$q, $a];
}
} else {
if (! isset($vote[$q][0])) {
return __('No vote on question %s', $q);
} elseif (! isset($this->answer[$q][$vote[$q][0]])) {
return __('The selected answer is not present in question %s', $q);
}
$data[] = [$q, $vote[$q][0]];
}
$data[] = [$q, 0];
}
$vars = [
':tid' => $this->tid,
':uid' => $this->c->user->id,
':rez' => \json_encode($data, self::JSON_OPTIONS),
];
$query = 'INSERT INTO ::poll_voted (tid, uid, rez)
VALUES (?i:tid, ?i:uid, ?s:rez)';
$this->c->DB->exec($query, $vars);
$vars = [
':tid' => $this->tid,
];
$query = 'UPDATE ::poll
SET votes=votes+1
WHERE tid=?i:tid AND question_id=?i:qid AND field_id=?i:fid';
foreach ($data as list($vars[':qid'], $vars[':fid'])) {
$this->c->DB->exec($query, $vars);
}
$this->c->polls->reset($this->tid);
return null;
}
}

View file

@ -73,16 +73,31 @@ msgid "(%1$s [%2$s%%])"
msgstr "(%1$s [%2$s%%])"
msgid "Poll results are hidden from the guests"
msgstr "Poll results are hidden from the guests"
msgstr "Poll results are hidden from the guests."
msgid "This poll is closed"
msgstr "This poll is closed"
msgstr "This poll is closed."
msgid "Poll results are hidden up to %s voters"
msgstr "Poll results are hidden up to %s voters"
msgstr "Poll results are hidden up to %s voters."
msgid "You voted"
msgstr "You voted"
msgstr "You voted."
msgid "Poll status is undefined"
msgstr "Статус опроса неопределен"
msgstr "Poll status is undefined."
msgid "Vote"
msgstr "Vote"
msgid "You cannot vote on this poll"
msgstr "You cannot vote on this poll."
msgid "No vote on question %s"
msgstr "No vote on question number %s."
msgid "The selected answer is not present in question %s"
msgstr "The selected answer is not present in question number %s."
msgid "Too many answers selected in question %s"
msgstr "Too many answers selected in question number %s."

View file

@ -73,16 +73,31 @@ msgid "(%1$s [%2$s%%])"
msgstr "(%1$s [%2$s%%])"
msgid "Poll results are hidden from the guests"
msgstr "Результаты опроса скрыты от гостей"
msgstr "Результаты опроса скрыты от гостей."
msgid "This poll is closed"
msgstr "Опрос закрыт"
msgstr "Опрос закрыт."
msgid "Poll results are hidden up to %s voters"
msgstr "Результаты опроса скрыты до %s проголосовавших"
msgstr "Результаты опроса скрыты до %s проголосовавших."
msgid "You voted"
msgstr "Вы проголосовали"
msgstr "Вы проголосовали."
msgid "Poll status is undefined"
msgstr "Статус опроса неопределен"
msgstr "Статус опроса неопределен."
msgid "Vote"
msgstr "Голосовать"
msgid "You cannot vote on this poll"
msgstr "Вы не можете проголосовать в этом опросе."
msgid "No vote on question %s"
msgstr "Отсутствует голос по %s вопросу."
msgid "The selected answer is not present in question %s"
msgstr "Выбранный вариант ответа отсутствует в вопросе номер %s."
msgid "Too many answers selected in question %s"
msgstr "В вопросе номер %s выбрано много ответов."

View file

@ -1,6 +1,7 @@
<div class="f-post-poll">
@if ($poll->canVote)
<form>
<form class="f-form" method="post" action="{!! $poll->link !!}">
<input type="hidden" name="token" value="{{ $poll->token }}">
@endif
@foreach ($poll->question as $q => $question)
<fieldset id="id-question-{!! $q !!}" class="f-poll-q">
@ -37,6 +38,9 @@
</fieldset>
@endforeach
@if ($poll->canVote)
<p class="f-poll-btns">
<button class="f-btn" name="vote" value="{!! __('Vote') !!}" title="{!! __('Vote') !!}"><span>{!! __('Vote') !!}</span></button>
</p>
</form>
@else
@if (null !== $poll->status)

View file

@ -2014,6 +2014,12 @@ body,
padding-top: 0.625rem;
}
#fork .f-poll-btns {
text-align: center;
border-top: 0.0625rem solid #AA7939;
padding-top: 0.625rem;
}
/**********/
/* Репорт */
/**********/