소스 검색

Add poll 9

Add form and vote handler.
Visman 4 년 전
부모
커밋
def812bf8c
8개의 변경된 파일212개의 추가작업 그리고 11개의 파일을 삭제
  1. 9 0
      app/Controllers/Routing.php
  2. 1 0
      app/Models/Page.php
  3. 55 0
      app/Models/Pages/Poll.php
  4. 96 0
      app/Models/Poll/Model.php
  5. 20 5
      app/lang/en/poll.po
  6. 20 5
      app/lang/ru/poll.po
  7. 5 1
      app/templates/layouts/poll.forkbb.php
  8. 6 0
      public/style/ForkBB/style.css

+ 9 - 0
app/Controllers/Routing.php

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

+ 1 - 0
app/Models/Page.php

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

+ 55 - 0
app/Models/Pages/Poll.php

@@ -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');
+        }
+    }
+}

+ 96 - 0
app/Models/Poll/Model.php

@@ -13,6 +13,8 @@ use function \ForkBB\__;
 
 
 class Model extends DataModel
 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;
         $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;
         return $result;
     }
     }
 
 
+    /**
+     * Возвращает статус опроса для текущего пользователя или null
+     */
     protected function getstatus(): ?string
     protected function getstatus(): ?string
     {
     {
         if ($this->tid < 1) {
         if ($this->tid < 1) {
@@ -219,4 +248,71 @@ class Model extends DataModel
             return __('Poll status is undefined');
             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;
+    }
 }
 }

+ 20 - 5
app/lang/en/poll.po

@@ -73,16 +73,31 @@ msgid "(%1$s [%2$s%%])"
 msgstr "(%1$s [%2$s%%])"
 msgstr "(%1$s [%2$s%%])"
 
 
 msgid "Poll results are hidden from the guests"
 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"
 msgid "This poll is closed"
-msgstr "This poll is closed"
+msgstr "This poll is closed."
 
 
 msgid "Poll results are hidden up to %s voters"
 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"
 msgid "You voted"
-msgstr "You voted"
+msgstr "You voted."
 
 
 msgid "Poll status is undefined"
 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."

+ 20 - 5
app/lang/ru/poll.po

@@ -73,16 +73,31 @@ msgid "(%1$s [%2$s%%])"
 msgstr "(%1$s [%2$s%%])"
 msgstr "(%1$s [%2$s%%])"
 
 
 msgid "Poll results are hidden from the guests"
 msgid "Poll results are hidden from the guests"
-msgstr "Результаты опроса скрыты от гостей"
+msgstr "Результаты опроса скрыты от гостей."
 
 
 msgid "This poll is closed"
 msgid "This poll is closed"
-msgstr "Опрос закрыт"
+msgstr "Опрос закрыт."
 
 
 msgid "Poll results are hidden up to %s voters"
 msgid "Poll results are hidden up to %s voters"
-msgstr "Результаты опроса скрыты до %s проголосовавших"
+msgstr "Результаты опроса скрыты до %s проголосовавших."
 
 
 msgid "You voted"
 msgid "You voted"
-msgstr "Вы проголосовали"
+msgstr "Вы проголосовали."
 
 
 msgid "Poll status is undefined"
 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 выбрано много ответов."

+ 5 - 1
app/templates/layouts/poll.forkbb.php

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

+ 6 - 0
public/style/ForkBB/style.css

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