mirror of
https://github.com/Karaka-Management/oms-QA.git
synced 2026-01-11 15:48:42 +00:00
add voting/accepting
This commit is contained in:
parent
0e1dd3e830
commit
9b0dc90e2a
|
|
@ -122,6 +122,13 @@
|
|||
"foreignTable": "account",
|
||||
"foreignKey": "account_id"
|
||||
},
|
||||
"qa_question_vote_created_for": {
|
||||
"name": "qa_question_vote_created_for",
|
||||
"type": "INT",
|
||||
"null": false,
|
||||
"foreignTable": "account",
|
||||
"foreignKey": "account_id"
|
||||
},
|
||||
"qa_question_vote_score": {
|
||||
"name": "qa_question_vote_score",
|
||||
"type": "TINYINT",
|
||||
|
|
@ -263,6 +270,13 @@
|
|||
"foreignTable": "account",
|
||||
"foreignKey": "account_id"
|
||||
},
|
||||
"qa_answer_vote_created_for": {
|
||||
"name": "qa_answer_vote_created_for",
|
||||
"type": "INT",
|
||||
"null": false,
|
||||
"foreignTable": "account",
|
||||
"foreignKey": "account_id"
|
||||
},
|
||||
"qa_answer_vote_score": {
|
||||
"name": "qa_answer_vote_score",
|
||||
"type": "TINYINT",
|
||||
|
|
|
|||
|
|
@ -100,4 +100,15 @@ return [
|
|||
],
|
||||
],
|
||||
],
|
||||
'^.*/qa/answer/accept(\?.*|$)' => [
|
||||
[
|
||||
'dest' => '\Modules\QA\Controller\ApiController:apiChangeAnsweredStatus',
|
||||
'verb' => RouteVerb::PUT | RouteVerb::SET,
|
||||
'permission' => [
|
||||
'module' => ApiController::NAME,
|
||||
'type' => PermissionType::CREATE,
|
||||
'state' => PermissionCategory::ACCEPT,
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ namespace Modules\QA\Controller;
|
|||
use Modules\Admin\Models\NullAccount;
|
||||
use Modules\Media\Models\NullMedia;
|
||||
use Modules\Profile\Models\Profile;
|
||||
use Modules\QA\Models\NullQAAnswer;
|
||||
use Modules\QA\Models\NullQAAnswerVote;
|
||||
use Modules\QA\Models\NullQAApp;
|
||||
use Modules\QA\Models\NullQAQuestion;
|
||||
|
|
@ -331,9 +332,24 @@ final class ApiController extends Controller
|
|||
*/
|
||||
public function apiChangeAnsweredStatus(RequestAbstract $request, ResponseAbstract $response, $data = null) : void
|
||||
{
|
||||
// @todo: check if is allowed to change
|
||||
|
||||
$old = clone QAAnswerMapper::get()->where('id', (int) $request->getData('id'))->execute();
|
||||
$oldAccepted = QAAnswerMapper::get()
|
||||
->where('question', $old->question->getId())
|
||||
->where('isAccepted', true)
|
||||
->execute();
|
||||
|
||||
if ($old->getId() !== $oldAccepted->getId()) {
|
||||
$oldUnaccepted = clone $oldAccepted;
|
||||
$oldUnaccepted->isAccepted = !$oldUnaccepted->isAccepted;
|
||||
|
||||
$this->updateModel($request->header->account, $oldAccepted, $oldUnaccepted, QAAnswerMapper::class, 'answer', $request->getOrigin());
|
||||
}
|
||||
|
||||
$new = $this->updateAnsweredStatusFromRequest($request);
|
||||
$this->updateModel($request->header->account, $old, $new, QAAnswerMapper::class, 'answer', $request->getOrigin());
|
||||
|
||||
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Answer', 'Answer successfully updated.', $new);
|
||||
}
|
||||
|
||||
|
|
@ -349,7 +365,7 @@ final class ApiController extends Controller
|
|||
public function updateAnsweredStatusFromRequest(RequestAbstract $request) : QAAnswer
|
||||
{
|
||||
$answer = QAAnswerMapper::get()->where('id', (int) $request->getData('id'))->execute();
|
||||
$answer->isAccepted = $request->getData('accepted', 'bool') ?? false;
|
||||
$answer->isAccepted = !$answer->isAccepted;
|
||||
|
||||
return $answer;
|
||||
}
|
||||
|
|
@ -440,23 +456,30 @@ final class ApiController extends Controller
|
|||
return;
|
||||
}
|
||||
|
||||
// @todo: check if is allowed to change
|
||||
|
||||
$questionVote = QAQuestionVoteMapper::get()
|
||||
->where('question', (int) $request->getData('id'))
|
||||
->where('createdBy', $request->header->account)
|
||||
->execute();
|
||||
|
||||
if ($questionVote === false || $questionVote instanceof NullQAQuestionVote || $questionVote === null) {
|
||||
$question = QAQuestionMapper::get()->where('id', (int) $request->getData('id'))->execute();
|
||||
|
||||
$new = new QAQuestionVote();
|
||||
$new->score = (int) $request->getData('type');
|
||||
$new->question = (int) $request->getData('id');
|
||||
$new->createdBy = new NullAccount($request->header->account);
|
||||
$new->createdFor = $question->createdBy->getId();
|
||||
|
||||
$this->createModel($request->header->account, $new, QAQuestionVoteMapper::class, 'qa_question_vote', $request->getOrigin());
|
||||
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Vote', 'Sucessfully voted.', $new);
|
||||
} else {
|
||||
/** @var QAQuestionVote $questionVote */
|
||||
$new = clone $questionVote;
|
||||
$new->score = (int) $request->getData('type');
|
||||
$new->score = ((int) $request->getData('type')) === $new->score
|
||||
? 0
|
||||
: (int) $request->getData('type');
|
||||
|
||||
$this->updateModel($request->header->account, $questionVote, $new, QAQuestionVoteMapper::class, 'qa_question_vote', $request->getOrigin());
|
||||
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Vote', 'Vote successfully changed.', $new);
|
||||
|
|
@ -506,23 +529,30 @@ final class ApiController extends Controller
|
|||
return;
|
||||
}
|
||||
|
||||
// @todo: check if is allowed to change
|
||||
|
||||
$answerVote = QAAnswerVoteMapper::get()
|
||||
->where('answer', (int) $request->getData('id'))
|
||||
->where('createdBy', $request->header->account)
|
||||
->execute();
|
||||
|
||||
if ($answerVote === false || $answerVote instanceof NullQAAnswerVote || $answerVote === null) {
|
||||
$answer = QAAnswerMapper::get()->where('id', (int) $request->getData('id'))->execute();
|
||||
|
||||
$new = new QAAnswerVote();
|
||||
$new->score = (int) $request->getData('type');
|
||||
$new->answer = (int) $request->getData('id');
|
||||
$new->createdBy = new NullAccount($request->header->account);
|
||||
$new->createdFor = $answer->createdBy->getId();
|
||||
|
||||
$this->createModel($request->header->account, $new, QAAnswerVoteMapper::class, 'qa_answer_vote', $request->getOrigin());
|
||||
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Vote', 'Sucessfully voted.', $new);
|
||||
} else {
|
||||
/** @var QAAnswerVote $answerVote */
|
||||
$new = clone $answerVote;
|
||||
$new->score = (int) $request->getData('type');
|
||||
$new->score = ((int) $request->getData('type')) === $new->score
|
||||
? 0
|
||||
: (int) $request->getData('type');
|
||||
|
||||
$this->updateModel($request->header->account, $answerVote, $new, QAAnswerVoteMapper::class, 'qa_answer_vote', $request->getOrigin());
|
||||
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Vote', 'Vote successfully changed.', $new);
|
||||
|
|
|
|||
|
|
@ -35,4 +35,6 @@ abstract class PermissionCategory extends Enum
|
|||
public const VOTE = 4;
|
||||
|
||||
public const APP = 5;
|
||||
|
||||
public const ACCEPT = 5;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,14 @@ class QAAnswerVote
|
|||
*/
|
||||
public Account $createdBy;
|
||||
|
||||
/**
|
||||
* Account
|
||||
*
|
||||
* @var int
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public int $createdFor = 0;
|
||||
|
||||
/**
|
||||
* Created at
|
||||
*
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ final class QAAnswerVoteMapper extends DataMapperFactory
|
|||
'qa_answer_vote_score' => ['name' => 'qa_answer_vote_score', 'type' => 'int', 'internal' => 'score'],
|
||||
'qa_answer_vote_answer' => ['name' => 'qa_answer_vote_answer', 'type' => 'int', 'internal' => 'answer', 'readonly' => true],
|
||||
'qa_answer_vote_created_by' => ['name' => 'qa_answer_vote_created_by', 'type' => 'int', 'internal' => 'createdBy', 'readonly' => true],
|
||||
'qa_answer_vote_created_for' => ['name' => 'qa_answer_vote_created_for', 'type' => 'int', 'internal' => 'createdFor', 'readonly' => true],
|
||||
'qa_answer_vote_created_at' => ['name' => 'qa_answer_vote_created_at', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt', 'readonly' => true],
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -39,34 +39,30 @@ final class QAHelperMapper extends DataMapperFactory
|
|||
$scores = [];
|
||||
|
||||
$query = new Builder(self::$db);
|
||||
$questionScore = $query->select('qa_question_created_by')
|
||||
$questionScore = $query->select('qa_question_vote_created_for')
|
||||
->selectAs('SUM(qa_question_vote_score)', 'score')
|
||||
->from(QAQuestionVoteMapper::TABLE)
|
||||
->leftJoin(QAQuestionMapper::TABLE)
|
||||
->on(QAQuestionVoteMapper::TABLE . '.qa_question_vote_question', '=', QAQuestionMapper::TABLE . '.qa_question_id')
|
||||
->where(QAQuestionMapper::TABLE . '.qa_question_created_by', 'in', $accounts)
|
||||
->groupBy('qa_question_created_by')
|
||||
->where(QAQuestionVoteMapper::TABLE . '.qa_question_vote_created_for', 'in', $accounts)
|
||||
->groupBy('qa_question_vote_created_for')
|
||||
->execute()
|
||||
->fetchAll();
|
||||
|
||||
foreach ($questionScore as $votes) {
|
||||
$scores[(int) $votes['qa_question_created_by']] = (int) $votes['score'];
|
||||
$scores[(int) $votes['qa_question_vote_created_for']] = (int) $votes['score'];
|
||||
}
|
||||
|
||||
$query = new Builder(self::$db);
|
||||
$answerScore = $query->select('qa_answer_created_by')
|
||||
$answerScore = $query->select('qa_answer_vote_created_for')
|
||||
->selectAs('SUM(qa_answer_vote_score)', 'score')
|
||||
->from(QAAnswerVoteMapper::TABLE)
|
||||
->leftJoin(QAAnswerMapper::TABLE)
|
||||
->on(QAAnswerVoteMapper::TABLE . '.qa_answer_vote_answer', '=', QAAnswerMapper::TABLE . '.qa_answer_id')
|
||||
->where(QAAnswerMapper::TABLE . '.qa_answer_created_by', 'in', $accounts)
|
||||
->groupBy('qa_answer_created_by')
|
||||
->where(QAAnswerMapper::TABLE . '.qa_answer_vote_created_for', 'in', $accounts)
|
||||
->groupBy('qa_answer_vote_created_for')
|
||||
->execute()
|
||||
->fetchAll();
|
||||
|
||||
foreach ($answerScore as $votes) {
|
||||
$scores[(int) $votes['qa_answer_created_by']] ??= 0;
|
||||
$scores[(int) $votes['qa_answer_created_by']] += (int) $votes['score'];
|
||||
$scores[(int) $votes['qa_answer_vote_created_for']] ??= 0;
|
||||
$scores[(int) $votes['qa_answer_vote_created_for']] += (int) $votes['score'];
|
||||
}
|
||||
|
||||
return $scores;
|
||||
|
|
|
|||
|
|
@ -43,6 +43,14 @@ class QAQuestionVote
|
|||
*/
|
||||
public Account $createdBy;
|
||||
|
||||
/**
|
||||
* Account
|
||||
*
|
||||
* @var int
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public int $createdFor = 0;
|
||||
|
||||
/**
|
||||
* Created at
|
||||
*
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ final class QAQuestionVoteMapper extends DataMapperFactory
|
|||
'qa_question_vote_score' => ['name' => 'qa_question_vote_score', 'type' => 'int', 'internal' => 'score'],
|
||||
'qa_question_vote_question' => ['name' => 'qa_question_vote_question', 'type' => 'int', 'internal' => 'question', 'readonly' => true],
|
||||
'qa_question_vote_created_by' => ['name' => 'qa_question_vote_created_by', 'type' => 'int', 'internal' => 'createdBy', 'readonly' => true],
|
||||
'qa_question_vote_created_for' => ['name' => 'qa_question_vote_created_for', 'type' => 'int', 'internal' => 'createdFor', 'readonly' => true],
|
||||
'qa_question_vote_created_at' => ['name' => 'qa_question_vote_created_at', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt', 'readonly' => true],
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -33,10 +33,28 @@ echo $this->getData('nav')->render();
|
|||
<div class="score">
|
||||
<div class="counter-area">
|
||||
<div class="counter-container">
|
||||
<i class="fa fa-chevron-up qa-vote<?= $this->printHtml($question->getAccountVoteScore($this->request->header->account) > 0 ? ' voted' : ' open'); ?>"></i>
|
||||
<a id="qa-question-upvote" data-action='[
|
||||
{
|
||||
"key": 1, "listener": "click", "action": [
|
||||
{"key": 1, "type": "event.prevent"},
|
||||
{"key": 2, "type": "message.request", "uri": "<?= UriFactory::build('{/base}/{/lang}/{/api}qa/question/vote?id=' . $question->getId());?>&type=1", "method": "PUT", "request_type": "json"}
|
||||
]
|
||||
}
|
||||
]' href="#">
|
||||
<i class="fa fa-chevron-up qa-vote<?= $this->printHtml($question->getAccountVoteScore($this->request->header->account) > 0 ? ' voted' : ' open'); ?>"></i>
|
||||
</a>
|
||||
<span class="counter"><?= $question->getVoteScore(); ?></span>
|
||||
<span class="text">Score</span>
|
||||
<i class="fa fa-chevron-down qa-vote<?= $this->printHtml($question->getAccountVoteScore($this->request->header->account) < 0 ? ' voted' : ' open'); ?>"></i>
|
||||
<a id="qa-question-downvote" data-action='[
|
||||
{
|
||||
"key": 1, "listener": "click", "action": [
|
||||
{"key": 1, "type": "event.prevent"},
|
||||
{"key": 2, "type": "message.request", "uri": "<?= UriFactory::build('{/base}/{/lang}/{/api}qa/question/vote?id=' . $question->getId());?>&type=-1", "method": "PUT", "request_type": "json"}
|
||||
]
|
||||
}
|
||||
]' href="#">
|
||||
<i class="fa fa-chevron-down qa-vote<?= $this->printHtml($question->getAccountVoteScore($this->request->header->account) < 0 ? ' voted' : ' open'); ?>"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="counter-container">
|
||||
<span class="counter score<?= $this->printHtml($question->hasAccepted() ? ' done' : ' open'); ?>"><?= $question->getAnswerCount(); ?></span>
|
||||
|
|
@ -83,13 +101,40 @@ echo $this->getData('nav')->render();
|
|||
<div class="score">
|
||||
<div class="counter-area">
|
||||
<div class="counter-container">
|
||||
<i class="fa fa-chevron-up qa-vote<?= $this->printHtml($answer->getAccountVoteScore($this->request->header->account) > 0 ? ' voted' : ' open'); ?>"></i>
|
||||
<a id="qa-answer-upvote-<?= $answer->getId() ?>" data-action='[
|
||||
{
|
||||
"key": 1, "listener": "click", "action": [
|
||||
{"key": 1, "type": "event.prevent"},
|
||||
{"key": 2, "type": "message.request", "uri": "<?= UriFactory::build('{/base}/{/lang}/{/api}qa/answer/vote?id=' . $answer->getId());?>&type=1", "method": "PUT", "request_type": "json"}
|
||||
]
|
||||
}
|
||||
]' href="#">
|
||||
<i class="fa fa-chevron-up qa-vote<?= $this->printHtml($answer->getAccountVoteScore($this->request->header->account) > 0 ? ' voted' : ' open'); ?>"></i>
|
||||
</a>
|
||||
<span class="counter"><?= $answer->getVoteScore(); ?></span>
|
||||
<span class="text">Score</span>
|
||||
<i class="fa fa-chevron-down qa-vote<?= $this->printHtml($answer->getAccountVoteScore($this->request->header->account) < 0 ? ' voted' : ' open'); ?>"></i>
|
||||
<a id="qa-answer-downvote-<?= $answer->getId() ?>" data-action='[
|
||||
{
|
||||
"key": 1, "listener": "click", "action": [
|
||||
{"key": 1, "type": "event.prevent"},
|
||||
{"key": 2, "type": "message.request", "uri": "<?= UriFactory::build('{/base}/{/lang}/{/api}qa/answer/vote?id=' . $answer->getId());?>&type=-1", "method": "PUT", "request_type": "json"}
|
||||
]
|
||||
}
|
||||
]' href="#">
|
||||
<i class="fa fa-chevron-down qa-vote<?= $this->printHtml($answer->getAccountVoteScore($this->request->header->account) < 0 ? ' voted' : ' open'); ?>"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="counter-container">
|
||||
<i class="fa fa-check qa-accept"></i>
|
||||
<a id="qa-answer-accept-<?= $answer->getId() ?>" data-action='[
|
||||
{
|
||||
"key": 1, "listener": "click", "action": [
|
||||
{"key": 1, "type": "event.prevent"},
|
||||
{"key": 2, "type": "message.request", "uri": "<?= UriFactory::build('{/base}/{/lang}/{/api}qa/answer/accept?id=' . $answer->getId());?>&type=1", "method": "PUT", "request_type": "json"}
|
||||
]
|
||||
}
|
||||
]' href="#">
|
||||
<i class="fa fa-check qa-accept"></i>
|
||||
</a>
|
||||
<span class="text"><?= $this->printHtml($answer->isAccepted ? 'Accepted' : 'Accept'); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user