mirror of
https://github.com/godotengine/godot-question2answer.git
synced 2026-01-01 01:48:37 +03:00
This project lived only on the server without version control. This is now the starting point for the repository.
520 lines
19 KiB
PHP
520 lines
19 KiB
PHP
<?php
|
|
/*
|
|
Question2Answer by Gideon Greenspan and contributors
|
|
http://www.question2answer.org/
|
|
|
|
Description: Common functions for question page form submission, either regular or via Ajax
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
More about this license: http://www.question2answer.org/license.php
|
|
*/
|
|
|
|
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
|
|
header('Location: ../../');
|
|
exit;
|
|
}
|
|
|
|
|
|
require_once QA_INCLUDE_DIR . 'app/post-create.php';
|
|
require_once QA_INCLUDE_DIR . 'app/post-update.php';
|
|
|
|
|
|
/**
|
|
* Checks for a POSTed click on $question by the current user and returns true if it was permitted and processed. Pass
|
|
* in the question's $answers, all $commentsfollows from it or its answers, and its closing $closepost (or null if
|
|
* none). If there is an error to display, it will be passed out in $error.
|
|
* @param $question
|
|
* @param $answers
|
|
* @param $commentsfollows
|
|
* @param $closepost
|
|
* @param $error
|
|
* @return bool
|
|
*/
|
|
function qa_page_q_single_click_q($question, $answers, $commentsfollows, $closepost, &$error)
|
|
{
|
|
require_once QA_INCLUDE_DIR . 'app/post-update.php';
|
|
require_once QA_INCLUDE_DIR . 'app/limits.php';
|
|
|
|
$userid = qa_get_logged_in_userid();
|
|
$handle = qa_get_logged_in_handle();
|
|
$cookieid = qa_cookie_get();
|
|
|
|
if (qa_clicked('q_doreopen') && $question['reopenable'] && qa_page_q_click_check_form_code($question, $error)) {
|
|
qa_question_close_clear($question, $closepost, $userid, $handle, $cookieid);
|
|
return true;
|
|
}
|
|
|
|
if ((qa_clicked('q_dohide') && $question['hideable']) || (qa_clicked('q_doreject') && $question['moderatable'])) {
|
|
if (qa_page_q_click_check_form_code($question, $error)) {
|
|
qa_question_set_status($question, QA_POST_STATUS_HIDDEN, $userid, $handle, $cookieid, $answers, $commentsfollows, $closepost);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if ((qa_clicked('q_doreshow') && $question['reshowable']) || (qa_clicked('q_doapprove') && $question['moderatable'])) {
|
|
if (qa_page_q_click_check_form_code($question, $error)) {
|
|
if ($question['moderatable'] || $question['reshowimmed']) {
|
|
$status = QA_POST_STATUS_NORMAL;
|
|
|
|
} else {
|
|
$in = qa_page_q_prepare_post_for_filters($question);
|
|
$filtermodules = qa_load_modules_with('filter', 'filter_question'); // run through filters but only for queued status
|
|
|
|
foreach ($filtermodules as $filtermodule) {
|
|
$tempin = $in; // always pass original question in because we aren't modifying anything else
|
|
$filtermodule->filter_question($tempin, $temperrors, $question);
|
|
$in['queued'] = $tempin['queued']; // only preserve queued status in loop
|
|
}
|
|
|
|
$status = $in['queued'] ? QA_POST_STATUS_QUEUED : QA_POST_STATUS_NORMAL;
|
|
}
|
|
|
|
qa_question_set_status($question, $status, $userid, $handle, $cookieid, $answers, $commentsfollows, $closepost);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (qa_clicked('q_doclaim') && $question['claimable'] && qa_page_q_click_check_form_code($question, $error)) {
|
|
if (qa_user_limits_remaining(QA_LIMIT_QUESTIONS)) { // already checked 'permit_post_q'
|
|
qa_question_set_userid($question, $userid, $handle, $cookieid);
|
|
return true;
|
|
|
|
} else
|
|
$error = qa_lang_html('question/ask_limit');
|
|
}
|
|
|
|
if (qa_clicked('q_doflag') && $question['flagbutton'] && qa_page_q_click_check_form_code($question, $error)) {
|
|
require_once QA_INCLUDE_DIR . 'app/votes.php';
|
|
|
|
$error = qa_flag_error_html($question, $userid, qa_request());
|
|
if (!$error) {
|
|
if (qa_flag_set_tohide($question, $userid, $handle, $cookieid, $question))
|
|
qa_question_set_status($question, QA_POST_STATUS_HIDDEN, null, null, null, $answers, $commentsfollows, $closepost); // hiding not really by this user so pass nulls
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (qa_clicked('q_dounflag') && $question['unflaggable'] && qa_page_q_click_check_form_code($question, $error)) {
|
|
require_once QA_INCLUDE_DIR . 'app/votes.php';
|
|
|
|
qa_flag_clear($question, $userid, $handle, $cookieid);
|
|
return true;
|
|
}
|
|
|
|
if (qa_clicked('q_doclearflags') && $question['clearflaggable'] && qa_page_q_click_check_form_code($question, $error)) {
|
|
require_once QA_INCLUDE_DIR . 'app/votes.php';
|
|
|
|
qa_flags_clear_all($question, $userid, $handle, $cookieid);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Checks for a POSTed click on $answer by the current user and returns true if it was permitted and processed. Pass in
|
|
* the $question, all of its $answers, and all $commentsfollows from it or its answers. Set $allowselectmove to whether
|
|
* it is legitimate to change the selected answer for the question from one to another (this can't be done via Ajax).
|
|
* If there is an error to display, it will be passed out in $error.
|
|
* @param $answer
|
|
* @param $question
|
|
* @param $answers
|
|
* @param $commentsfollows
|
|
* @param $allowselectmove
|
|
* @param $error
|
|
* @return bool
|
|
*/
|
|
function qa_page_q_single_click_a($answer, $question, $answers, $commentsfollows, $allowselectmove, &$error)
|
|
{
|
|
$userid = qa_get_logged_in_userid();
|
|
$handle = qa_get_logged_in_handle();
|
|
$cookieid = qa_cookie_get();
|
|
|
|
$prefix = 'a' . $answer['postid'] . '_';
|
|
|
|
if (qa_clicked($prefix . 'doselect') && $question['aselectable'] && ($allowselectmove || ((!isset($question['selchildid'])) && !qa_opt('do_close_on_select'))) && qa_page_q_click_check_form_code($answer, $error)) {
|
|
qa_question_set_selchildid($userid, $handle, $cookieid, $question, $answer['postid'], $answers);
|
|
return true;
|
|
}
|
|
|
|
if (qa_clicked($prefix . 'dounselect') && $question['aselectable'] && ($question['selchildid'] == $answer['postid']) && ($allowselectmove || !qa_opt('do_close_on_select')) && qa_page_q_click_check_form_code($answer, $error)) {
|
|
qa_question_set_selchildid($userid, $handle, $cookieid, $question, null, $answers);
|
|
return true;
|
|
}
|
|
|
|
if ((qa_clicked($prefix . 'dohide') && $answer['hideable']) || (qa_clicked($prefix . 'doreject') && $answer['moderatable'])) {
|
|
if (qa_page_q_click_check_form_code($answer, $error)) {
|
|
qa_answer_set_status($answer, QA_POST_STATUS_HIDDEN, $userid, $handle, $cookieid, $question, $commentsfollows);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if ((qa_clicked($prefix . 'doreshow') && $answer['reshowable']) || (qa_clicked($prefix . 'doapprove') && $answer['moderatable'])) {
|
|
if (qa_page_q_click_check_form_code($answer, $error)) {
|
|
if ($answer['moderatable'] || $answer['reshowimmed']) {
|
|
$status = QA_POST_STATUS_NORMAL;
|
|
|
|
} else {
|
|
$in = qa_page_q_prepare_post_for_filters($answer);
|
|
$filtermodules = qa_load_modules_with('filter', 'filter_answer'); // run through filters but only for queued status
|
|
|
|
foreach ($filtermodules as $filtermodule) {
|
|
$tempin = $in; // always pass original answer in because we aren't modifying anything else
|
|
$filtermodule->filter_answer($tempin, $temperrors, $question, $answer);
|
|
$in['queued'] = $tempin['queued']; // only preserve queued status in loop
|
|
}
|
|
|
|
$status = $in['queued'] ? QA_POST_STATUS_QUEUED : QA_POST_STATUS_NORMAL;
|
|
}
|
|
|
|
qa_answer_set_status($answer, $status, $userid, $handle, $cookieid, $question, $commentsfollows);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (qa_clicked($prefix . 'dodelete') && $answer['deleteable'] && qa_page_q_click_check_form_code($answer, $error)) {
|
|
qa_answer_delete($answer, $question, $userid, $handle, $cookieid);
|
|
return true;
|
|
}
|
|
|
|
if (qa_clicked($prefix . 'doclaim') && $answer['claimable'] && qa_page_q_click_check_form_code($answer, $error)) {
|
|
if (qa_user_limits_remaining(QA_LIMIT_ANSWERS)) { // already checked 'permit_post_a'
|
|
qa_answer_set_userid($answer, $userid, $handle, $cookieid);
|
|
return true;
|
|
|
|
} else
|
|
$error = qa_lang_html('question/answer_limit');
|
|
}
|
|
|
|
if (qa_clicked($prefix . 'doflag') && $answer['flagbutton'] && qa_page_q_click_check_form_code($answer, $error)) {
|
|
require_once QA_INCLUDE_DIR . 'app/votes.php';
|
|
|
|
$error = qa_flag_error_html($answer, $userid, qa_request());
|
|
if (!$error) {
|
|
if (qa_flag_set_tohide($answer, $userid, $handle, $cookieid, $question))
|
|
qa_answer_set_status($answer, QA_POST_STATUS_HIDDEN, null, null, null, $question, $commentsfollows); // hiding not really by this user so pass nulls
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (qa_clicked($prefix . 'dounflag') && $answer['unflaggable'] && qa_page_q_click_check_form_code($answer, $error)) {
|
|
require_once QA_INCLUDE_DIR . 'app/votes.php';
|
|
|
|
qa_flag_clear($answer, $userid, $handle, $cookieid);
|
|
return true;
|
|
}
|
|
|
|
if (qa_clicked($prefix . 'doclearflags') && $answer['clearflaggable'] && qa_page_q_click_check_form_code($answer, $error)) {
|
|
require_once QA_INCLUDE_DIR . 'app/votes.php';
|
|
|
|
qa_flags_clear_all($answer, $userid, $handle, $cookieid);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Checks for a POSTed click on $comment by the current user and returns true if it was permitted and processed. Pass
|
|
* in the antecedent $question and the comment's $parent post. If there is an error to display, it will be passed out
|
|
* in $error.
|
|
* @param $comment
|
|
* @param $question
|
|
* @param $parent
|
|
* @param $error
|
|
* @return bool
|
|
*/
|
|
function qa_page_q_single_click_c($comment, $question, $parent, &$error)
|
|
{
|
|
$userid = qa_get_logged_in_userid();
|
|
$handle = qa_get_logged_in_handle();
|
|
$cookieid = qa_cookie_get();
|
|
|
|
$prefix = 'c' . $comment['postid'] . '_';
|
|
|
|
if ((qa_clicked($prefix . 'dohide') && $comment['hideable']) || (qa_clicked($prefix . 'doreject') && $comment['moderatable'])) {
|
|
if (qa_page_q_click_check_form_code($parent, $error)) {
|
|
qa_comment_set_status($comment, QA_POST_STATUS_HIDDEN, $userid, $handle, $cookieid, $question, $parent);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if ((qa_clicked($prefix . 'doreshow') && $comment['reshowable']) || (qa_clicked($prefix . 'doapprove') && $comment['moderatable'])) {
|
|
if (qa_page_q_click_check_form_code($parent, $error)) {
|
|
if ($comment['moderatable'] || $comment['reshowimmed']) {
|
|
$status = QA_POST_STATUS_NORMAL;
|
|
|
|
} else {
|
|
$in = qa_page_q_prepare_post_for_filters($comment);
|
|
$filtermodules = qa_load_modules_with('filter', 'filter_comment'); // run through filters but only for queued status
|
|
|
|
foreach ($filtermodules as $filtermodule) {
|
|
$tempin = $in; // always pass original comment in because we aren't modifying anything else
|
|
$filtermodule->filter_comment($tempin, $temperrors, $question, $parent, $comment);
|
|
$in['queued'] = $tempin['queued']; // only preserve queued status in loop
|
|
}
|
|
|
|
$status = $in['queued'] ? QA_POST_STATUS_QUEUED : QA_POST_STATUS_NORMAL;
|
|
}
|
|
|
|
qa_comment_set_status($comment, $status, $userid, $handle, $cookieid, $question, $parent);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (qa_clicked($prefix . 'dodelete') && $comment['deleteable'] && qa_page_q_click_check_form_code($parent, $error)) {
|
|
qa_comment_delete($comment, $question, $parent, $userid, $handle, $cookieid);
|
|
return true;
|
|
}
|
|
|
|
if (qa_clicked($prefix . 'doclaim') && $comment['claimable'] && qa_page_q_click_check_form_code($parent, $error)) {
|
|
if (qa_user_limits_remaining(QA_LIMIT_COMMENTS)) {
|
|
qa_comment_set_userid($comment, $userid, $handle, $cookieid);
|
|
return true;
|
|
|
|
} else
|
|
$error = qa_lang_html('question/comment_limit');
|
|
}
|
|
|
|
if (qa_clicked($prefix . 'doflag') && $comment['flagbutton'] && qa_page_q_click_check_form_code($parent, $error)) {
|
|
require_once QA_INCLUDE_DIR . 'app/votes.php';
|
|
|
|
$error = qa_flag_error_html($comment, $userid, qa_request());
|
|
if (!$error) {
|
|
if (qa_flag_set_tohide($comment, $userid, $handle, $cookieid, $question))
|
|
qa_comment_set_status($comment, QA_POST_STATUS_HIDDEN, null, null, null, $question, $parent); // hiding not really by this user so pass nulls
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (qa_clicked($prefix . 'dounflag') && $comment['unflaggable'] && qa_page_q_click_check_form_code($parent, $error)) {
|
|
require_once QA_INCLUDE_DIR . 'app/votes.php';
|
|
|
|
qa_flag_clear($comment, $userid, $handle, $cookieid);
|
|
return true;
|
|
}
|
|
|
|
if (qa_clicked($prefix . 'doclearflags') && $comment['clearflaggable'] && qa_page_q_click_check_form_code($parent, $error)) {
|
|
require_once QA_INCLUDE_DIR . 'app/votes.php';
|
|
|
|
qa_flags_clear_all($comment, $userid, $handle, $cookieid);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Check the form security (anti-CSRF protection) for one of the buttons shown for post $post. Return true if the
|
|
* security passed, otherwise return false and set an error message in $error
|
|
* @param $post
|
|
* @param $error
|
|
* @return bool
|
|
*/
|
|
function qa_page_q_click_check_form_code($post, &$error)
|
|
{
|
|
$result = qa_check_form_security_code('buttons-' . $post['postid'], qa_post_text('code'));
|
|
|
|
if (!$result)
|
|
$error = qa_lang_html('misc/form_security_again');
|
|
|
|
return $result;
|
|
}
|
|
|
|
|
|
/**
|
|
* Processes a POSTed form to add an answer to $question, returning the postid if successful, otherwise null. Pass in
|
|
* other $answers to the question and whether a $usecaptcha is required. The form fields submitted will be passed out
|
|
* as an array in $in, as well as any $errors on those fields.
|
|
* @param $question
|
|
* @param $answers
|
|
* @param $usecaptcha
|
|
* @param $in
|
|
* @param $errors
|
|
* @return mixed|null
|
|
*/
|
|
function qa_page_q_add_a_submit($question, $answers, $usecaptcha, &$in, &$errors)
|
|
{
|
|
$in = array(
|
|
'name' => qa_opt('allow_anonymous_naming') ? qa_post_text('a_name') : null,
|
|
'notify' => qa_post_text('a_notify') !== null,
|
|
'email' => qa_post_text('a_email'),
|
|
'queued' => qa_user_moderation_reason(qa_user_level_for_post($question)) !== false,
|
|
);
|
|
|
|
qa_get_post_content('a_editor', 'a_content', $in['editor'], $in['content'], $in['format'], $in['text']);
|
|
|
|
$errors = array();
|
|
|
|
if (!qa_check_form_security_code('answer-' . $question['postid'], qa_post_text('code')))
|
|
$errors['content'] = qa_lang_html('misc/form_security_again');
|
|
|
|
else {
|
|
// call any filter plugins
|
|
$filtermodules = qa_load_modules_with('filter', 'filter_answer');
|
|
foreach ($filtermodules as $filtermodule) {
|
|
$oldin = $in;
|
|
$filtermodule->filter_answer($in, $errors, $question, null);
|
|
qa_update_post_text($in, $oldin);
|
|
}
|
|
|
|
// check CAPTCHA
|
|
if ($usecaptcha)
|
|
qa_captcha_validate_post($errors);
|
|
|
|
// check for duplicate posts
|
|
if (empty($errors)) {
|
|
$testwords = implode(' ', qa_string_to_words($in['content']));
|
|
|
|
foreach ($answers as $answer) {
|
|
if (!$answer['hidden']) {
|
|
if (implode(' ', qa_string_to_words($answer['content'])) == $testwords) {
|
|
$errors['content'] = qa_lang_html('question/duplicate_content');
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$userid = qa_get_logged_in_userid();
|
|
|
|
// if this is an additional answer, check we can add it
|
|
if (empty($errors) && !qa_opt('allow_multi_answers')) {
|
|
foreach ($answers as $answer) {
|
|
if (qa_post_is_by_user($answer, $userid, qa_cookie_get())) {
|
|
$errors[] = '';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// create the answer
|
|
if (empty($errors)) {
|
|
$handle = qa_get_logged_in_handle();
|
|
$cookieid = isset($userid) ? qa_cookie_get() : qa_cookie_get_create(); // create a new cookie if necessary
|
|
|
|
$answerid = qa_answer_create($userid, $handle, $cookieid, $in['content'], $in['format'], $in['text'], $in['notify'], $in['email'],
|
|
$question, $in['queued'], $in['name']);
|
|
|
|
return $answerid;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
/**
|
|
* Processes a POSTed form to add a comment, returning the postid if successful, otherwise null. Pass in the antecedent
|
|
* $question and the comment's $parent post. Set $usecaptcha to whether a captcha is required. Pass an array which
|
|
* includes the other comments with the same parent in $commentsfollows (it can contain other posts which are ignored).
|
|
* The form fields submitted will be passed out as an array in $in, as well as any $errors on those fields.
|
|
* @param $question
|
|
* @param $parent
|
|
* @param $commentsfollows
|
|
* @param $usecaptcha
|
|
* @param $in
|
|
* @param $errors
|
|
* @return mixed|null
|
|
*/
|
|
function qa_page_q_add_c_submit($question, $parent, $commentsfollows, $usecaptcha, &$in, &$errors)
|
|
{
|
|
$parentid = $parent['postid'];
|
|
|
|
$prefix = 'c' . $parentid . '_';
|
|
|
|
$in = array(
|
|
'name' => qa_opt('allow_anonymous_naming') ? qa_post_text($prefix . 'name') : null,
|
|
'notify' => qa_post_text($prefix . 'notify') !== null,
|
|
'email' => qa_post_text($prefix . 'email'),
|
|
'queued' => qa_user_moderation_reason(qa_user_level_for_post($parent)) !== false,
|
|
);
|
|
|
|
qa_get_post_content($prefix . 'editor', $prefix . 'content', $in['editor'], $in['content'], $in['format'], $in['text']);
|
|
|
|
$errors = array();
|
|
|
|
if (!qa_check_form_security_code('comment-' . $parent['postid'], qa_post_text($prefix . 'code')))
|
|
$errors['content'] = qa_lang_html('misc/form_security_again');
|
|
|
|
else {
|
|
$filtermodules = qa_load_modules_with('filter', 'filter_comment');
|
|
foreach ($filtermodules as $filtermodule) {
|
|
$oldin = $in;
|
|
$filtermodule->filter_comment($in, $errors, $question, $parent, null);
|
|
qa_update_post_text($in, $oldin);
|
|
}
|
|
|
|
if ($usecaptcha)
|
|
qa_captcha_validate_post($errors);
|
|
|
|
if (empty($errors)) {
|
|
$testwords = implode(' ', qa_string_to_words($in['content']));
|
|
|
|
foreach ($commentsfollows as $comment) {
|
|
if ($comment['basetype'] == 'C' && $comment['parentid'] == $parentid && !$comment['hidden']) {
|
|
if (implode(' ', qa_string_to_words($comment['content'])) == $testwords) {
|
|
$errors['content'] = qa_lang_html('question/duplicate_content');
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (empty($errors)) {
|
|
$userid = qa_get_logged_in_userid();
|
|
$handle = qa_get_logged_in_handle();
|
|
$cookieid = isset($userid) ? qa_cookie_get() : qa_cookie_get_create(); // create a new cookie if necessary
|
|
|
|
$commentid = qa_comment_create($userid, $handle, $cookieid, $in['content'], $in['format'], $in['text'], $in['notify'], $in['email'],
|
|
$question, $parent, $commentsfollows, $in['queued'], $in['name']);
|
|
|
|
return $commentid;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return the array of information to be passed to filter modules for the post in $post (from the database)
|
|
* @param $post
|
|
* @return array
|
|
*/
|
|
function qa_page_q_prepare_post_for_filters($post)
|
|
{
|
|
$in = array(
|
|
'content' => $post['content'],
|
|
'format' => $post['format'],
|
|
'text' => qa_viewer_text($post['content'], $post['format']),
|
|
'notify' => isset($post['notify']),
|
|
'email' => qa_email_validate($post['notify']) ? $post['notify'] : null,
|
|
'queued' => qa_user_moderation_reason(qa_user_level_for_post($post)) !== false,
|
|
);
|
|
|
|
if ($post['basetype'] == 'Q') {
|
|
$in['title'] = $post['title'];
|
|
$in['tags'] = qa_tagstring_to_tags($post['tags']);
|
|
$in['categoryid'] = $post['categoryid'];
|
|
$in['extra'] = $post['extra'];
|
|
}
|
|
|
|
return $in;
|
|
}
|