Commit f24542bb by Scott

Coding style (app posts/admin)

parent 5a94ef80
......@@ -20,18 +20,18 @@
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
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../');
exit;
}
}
function qa_admin_check_privileges(&$qa_content)
/*
Return true if user is logged in with admin privileges. If not, return false
and set up $qa_content with the appropriate title and error message
*/
{
/**
* Return true if user is logged in with admin privileges. If not, return false
* and set up $qa_content with the appropriate title and error message
*/
function qa_admin_check_privileges(&$qa_content)
{
if (!qa_is_logged_in()) {
require_once QA_INCLUDE_DIR.'app/format.php';
......@@ -52,14 +52,14 @@
}
return true;
}
}
/**
/**
* Return a sorted array of available languages, [short code] => [long name]
*/
function qa_admin_language_options()
{
function qa_admin_language_options()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
/**
......@@ -133,14 +133,14 @@
asort($options, SORT_STRING);
return $options;
}
}
/**
/**
* Return a sorted array of available themes, [theme name] => [theme name]
*/
function qa_admin_theme_options()
{
function qa_admin_theme_options()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$metadataUtil = new Q2A_Util_Metadata();
......@@ -157,14 +157,14 @@
asort($options, SORT_STRING);
return $options;
}
}
function qa_admin_place_options()
/*
Return an array of widget placement options, with keys matching the database value
*/
{
/**
* Return an array of widget placement options, with keys matching the database value
*/
function qa_admin_place_options()
{
return array(
'FT' => qa_lang_html('options/place_full_top'),
'FH' => qa_lang_html('options/place_full_below_nav'),
......@@ -179,14 +179,14 @@
'SL' => qa_lang_html('options/place_side_low'),
'SB' => qa_lang_html('options/place_side_last'),
);
}
}
function qa_admin_page_size_options($maximum)
/*
Return an array of page size options up to $maximum, [page size] => [page size]
*/
{
/**
* Return an array of page size options up to $maximum, [page size] => [page size]
*/
function qa_admin_page_size_options($maximum)
{
$rawoptions=array(5, 10, 15, 20, 25, 30, 40, 50, 60, 80, 100, 120, 150, 200, 250, 300, 400, 500, 600, 800, 1000);
$options=array();
......@@ -198,14 +198,14 @@
}
return $options;
}
}
function qa_admin_match_options()
/*
Return an array of options representing matching precision, [value] => [label]
*/
{
/**
* Return an array of options representing matching precision, [value] => [label]
*/
function qa_admin_match_options()
{
return array(
5 => qa_lang_html('options/match_5'),
4 => qa_lang_html('options/match_4'),
......@@ -213,15 +213,15 @@
2 => qa_lang_html('options/match_2'),
1 => qa_lang_html('options/match_1'),
);
}
}
function qa_admin_permit_options($widest, $narrowest, $doconfirms=true, $dopoints=true)
/*
Return an array of options representing permission restrictions, [value] => [label]
ranging from $widest to $narrowest. Set $doconfirms to whether email confirmations are on
*/
{
/**
* Return an array of options representing permission restrictions, [value] => [label]
* ranging from $widest to $narrowest. Set $doconfirms to whether email confirmations are on
*/
function qa_admin_permit_options($widest, $narrowest, $doconfirms=true, $dopoints=true)
{
require_once QA_INCLUDE_DIR.'app/options.php';
$options=array(
......@@ -260,14 +260,14 @@
}
return $options;
}
}
function qa_admin_sub_navigation()
/*
Return the sub navigation structure common to admin pages
*/
{
/**
* Return the sub navigation structure common to admin pages
*/
function qa_admin_sub_navigation()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$navigation=array();
......@@ -399,14 +399,14 @@
}
return $navigation;
}
}
function qa_admin_page_error()
/*
Return the error that needs to displayed on all admin pages, or null if none
*/
{
/**
* Return the error that needs to displayed on all admin pages, or null if none
*/
function qa_admin_page_error()
{
if (file_exists(QA_INCLUDE_DIR.'db/install.php')) // file can be removed for extra security
include_once QA_INCLUDE_DIR.'db/install.php';
......@@ -425,23 +425,23 @@
else
return null;
}
}
function qa_admin_url_test_html()
/*
Return an HTML fragment to display for a URL test which has passed
*/
{
/**
* Return an HTML fragment to display for a URL test which has passed
*/
function qa_admin_url_test_html()
{
return '; font-size:9px; color:#060; font-weight:bold; font-family:arial,sans-serif; border-color:#060;">OK<';
}
}
function qa_admin_is_slug_reserved($requestpart)
/*
Returns whether a URL path beginning with $requestpart is reserved by the engine or a plugin page module
*/
{
/**
* Returns whether a URL path beginning with $requestpart is reserved by the engine or a plugin page module
*/
function qa_admin_is_slug_reserved($requestpart)
{
$requestpart=trim(strtolower($requestpart));
$routing=qa_page_routing();
......@@ -471,15 +471,15 @@
return true;
return false;
}
}
function qa_admin_single_click($entityid, $action)
/*
Returns true if admin (hidden/flagged/approve/moderate) page $action performed on $entityid is permitted by the
logged in user and was processed successfully
*/
{
/**
* Returns true if admin (hidden/flagged/approve/moderate) page $action performed on $entityid is permitted by the
* logged in user and was processed successfully
*/
function qa_admin_single_click($entityid, $action)
{
$userid=qa_get_logged_in_userid();
if ( (!QA_FINAL_EXTERNAL_USERS) && (($action=='userapprove') || ($action=='userblock')) ) { // approve/block moderated users
......@@ -561,14 +561,14 @@
}
return false;
}
}
function qa_admin_check_clicks()
/*
Checks for a POSTed click on an admin (hidden/flagged/approve/moderate) page, and refresh the page if processed successfully (non Ajax)
*/
{
/**
* Checks for a POSTed click on an admin (hidden/flagged/approve/moderate) page, and refresh the page if processed successfully (non Ajax)
*/
function qa_admin_check_clicks()
{
if (qa_is_http_post())
foreach ($_POST as $field => $value)
if (strpos($field, 'admin_')===0) {
......@@ -583,16 +583,16 @@
}
return null;
}
}
/**
/**
* Retrieve metadata information from the $contents of a qa-theme.php or qa-plugin.php file, mapping via $fields.
*
* @deprecated Deprecated from 1.7; use `qa_addon_metadata($contents, $type)` instead.
*/
function qa_admin_addon_metadata($contents, $fields)
{
function qa_admin_addon_metadata($contents, $fields)
{
$metadata=array();
foreach ($fields as $key => $field)
......@@ -600,43 +600,38 @@
$metadata[$key]=trim($matches[1]);
return $metadata;
}
}
/**
/**
* Return the hash code for the plugin in $directory (without trailing slash), used for in-page navigation on admin/plugins page
*/
function qa_admin_plugin_directory_hash($directory)
{
function qa_admin_plugin_directory_hash($directory)
{
$pluginManager = new Q2A_Plugin_PluginManager();
$hashes = $pluginManager->getHashesForPlugins(array($directory));
return reset($hashes);
}
}
/**
/**
* Return the URL (relative to the current page) to navigate to the options panel for the plugin in $directory (without trailing slash)
*/
function qa_admin_plugin_options_path($directory)
{
function qa_admin_plugin_options_path($directory)
{
$hash = qa_admin_plugin_directory_hash($directory);
return qa_path_html('admin/plugins', array('show' => $hash), null, null, $hash);
}
}
/**
/**
* Return the URL (relative to the current page) to navigate to the options panel for plugin module $name of $type
*/
function qa_admin_module_options_path($type, $name)
{
function qa_admin_module_options_path($type, $name)
{
$info = qa_get_module_info($type, $name);
$dir = rtrim($info['directory'], '/');
return qa_admin_plugin_options_path($dir);
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
}
......@@ -20,43 +20,63 @@
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
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../');
exit;
}
require_once QA_INCLUDE_DIR.'db/maxima.php';
require_once QA_INCLUDE_DIR.'db/post-create.php';
require_once QA_INCLUDE_DIR.'db/points.php';
require_once QA_INCLUDE_DIR.'db/hotness.php';
require_once QA_INCLUDE_DIR.'util/string.php';
function qa_combine_notify_email($userid, $notify, $email)
/*
Return value to store in database combining $notify and $email values entered by user $userid (or null for anonymous)
*/
{
}
require_once QA_INCLUDE_DIR . 'db/maxima.php';
require_once QA_INCLUDE_DIR . 'db/post-create.php';
require_once QA_INCLUDE_DIR . 'db/points.php';
require_once QA_INCLUDE_DIR . 'db/hotness.php';
require_once QA_INCLUDE_DIR . 'util/string.php';
/**
* Return value to store in database combining $notify and $email values entered by user $userid (or null for anonymous)
* @param $userid
* @param $notify
* @param $email
* @return null|string
*/
function qa_combine_notify_email($userid, $notify, $email)
{
return $notify ? (empty($email) ? (isset($userid) ? '@' : null) : $email) : null;
}
function qa_question_create($followanswer, $userid, $handle, $cookieid, $title, $content, $format, $text, $tagstring, $notify, $email,
$categoryid=null, $extravalue=null, $queued=false, $name=null)
/*
Add a question (application level) - create record, update appropriate counts, index it, send notifications.
If question is follow-on from an answer, $followanswer should contain answer database record, otherwise null.
See qa-app-posts.php for a higher-level function which is easier to use.
*/
{
require_once QA_INCLUDE_DIR.'db/selects.php';
$postid=qa_db_post_create($queued ? 'Q_QUEUED' : 'Q', @$followanswer['postid'], $userid, isset($userid) ? null : $cookieid,
}
/**
* Add a question (application level) - create record, update appropriate counts, index it, send notifications.
* If question is follow-on from an answer, $followanswer should contain answer database record, otherwise null.
* See qa-app-posts.php for a higher-level function which is easier to use.
* @param $followanswer
* @param $userid
* @param $handle
* @param $cookieid
* @param $title
* @param $content
* @param $format
* @param $text
* @param $tagstring
* @param $notify
* @param $email
* @param $categoryid
* @param $extravalue
* @param bool $queued
* @param $name
* @return mixed
*/
function qa_question_create($followanswer, $userid, $handle, $cookieid, $title, $content, $format, $text, $tagstring, $notify, $email,
$categoryid = null, $extravalue = null, $queued = false, $name = null)
{
require_once QA_INCLUDE_DIR . 'db/selects.php';
$postid = qa_db_post_create($queued ? 'Q_QUEUED' : 'Q', @$followanswer['postid'], $userid, isset($userid) ? null : $cookieid,
qa_remote_ip_address(), $title, $content, $format, $tagstring, qa_combine_notify_email($userid, $notify, $email),
$categoryid, isset($userid) ? null : $name);
if (isset($extravalue)) {
require_once QA_INCLUDE_DIR.'db/metas.php';
require_once QA_INCLUDE_DIR . 'db/metas.php';
qa_db_postmeta_set($postid, 'qa_q_extra', $extravalue);
}
......@@ -89,14 +109,15 @@
));
return $postid;
}
}
function qa_update_counts_for_q($postid)
/*
Perform various common cached count updating operations to reflect changes in the question whose id is $postid
*/
{
/**
* Perform various common cached count updating operations to reflect changes in the question whose id is $postid
* @param $postid
*/
function qa_update_counts_for_q($postid)
{
if (isset($postid)) // post might no longer exist
qa_db_category_path_qcount_update(qa_db_post_get_category_path($postid));
......@@ -104,63 +125,90 @@
qa_db_unaqcount_update();
qa_db_unselqcount_update();
qa_db_unupaqcount_update();
}
}
function qa_array_filter_by_keys($inarray, $keys)
/*
Return an array containing the elements of $inarray whose key is in $keys
*/
{
$outarray=array();
/**
* Return an array containing the elements of $inarray whose key is in $keys
* @param $inarray
* @param $keys
* @return array
*/
function qa_array_filter_by_keys($inarray, $keys)
{
$outarray = array();
foreach ($keys as $key)
foreach ($keys as $key) {
if (isset($inarray[$key]))
$outarray[$key]=$inarray[$key];
$outarray[$key] = $inarray[$key];
}
return $outarray;
}
}
function qa_suspend_post_indexing($suspend=true)
/*
Suspend the indexing (and unindexing) of posts via qa_post_index(...) and qa_post_unindex(...)
if $suspend is true, otherwise reinstate it. A counter is kept to allow multiple calls.
*/
{
/**
* Suspend the indexing (and unindexing) of posts via qa_post_index(...) and qa_post_unindex(...)
* if $suspend is true, otherwise reinstate it. A counter is kept to allow multiple calls.
* @param bool $suspend
*/
function qa_suspend_post_indexing($suspend = true)
{
global $qa_post_indexing_suspended;
$qa_post_indexing_suspended+=($suspend ? 1 : -1);
}
function qa_post_index($postid, $type, $questionid, $parentid, $title, $content, $format, $text, $tagstring, $categoryid)
/*
Add post $postid (which comes under $questionid) of $type (Q/A/C) to the database index, with $title, $text,
$tagstring and $categoryid. Calls through to all installed search modules.
*/
{
$qa_post_indexing_suspended += ($suspend ? 1 : -1);
}
/**
* Add post $postid (which comes under $questionid) of $type (Q/A/C) to the database index, with $title, $text,
* $tagstring and $categoryid. Calls through to all installed search modules.
* @param $postid
* @param $type
* @param $questionid
* @param $parentid
* @param $title
* @param $content
* @param $format
* @param $text
* @param $tagstring
* @param $categoryid
*/
function qa_post_index($postid, $type, $questionid, $parentid, $title, $content, $format, $text, $tagstring, $categoryid)
{
global $qa_post_indexing_suspended;
if ($qa_post_indexing_suspended>0)
if ($qa_post_indexing_suspended > 0)
return;
// Send through to any search modules for indexing
$searches=qa_load_modules_with('search', 'index_post');
$searches = qa_load_modules_with('search', 'index_post');
foreach ($searches as $search)
$search->index_post($postid, $type, $questionid, $parentid, $title, $content, $format, $text, $tagstring, $categoryid);
}
function qa_answer_create($userid, $handle, $cookieid, $content, $format, $text, $notify, $email, $question, $queued=false, $name=null)
/*
Add an answer (application level) - create record, update appropriate counts, index it, send notifications.
$question should contain database record for the question this is an answer to.
See qa-app-posts.php for a higher-level function which is easier to use.
*/
{
$postid=qa_db_post_create($queued ? 'A_QUEUED' : 'A', $question['postid'], $userid, isset($userid) ? null : $cookieid,
}
/**
* Add an answer (application level) - create record, update appropriate counts, index it, send notifications.
* $question should contain database record for the question this is an answer to.
* See qa-app-posts.php for a higher-level function which is easier to use.
* @param $userid
* @param $handle
* @param $cookieid
* @param $content
* @param $format
* @param $text
* @param $notify
* @param $email
* @param $question
* @param bool $queued
* @param $name
* @return mixed
*/
function qa_answer_create($userid, $handle, $cookieid, $content, $format, $text, $notify, $email, $question, $queued = false, $name = null)
{
$postid = qa_db_post_create($queued ? 'A_QUEUED' : 'A', $question['postid'], $userid, isset($userid) ? null : $cookieid,
qa_remote_ip_address(), null, $content, $format, null, qa_combine_notify_email($userid, $notify, $email),
$question['categoryid'], isset($userid) ? null : $name);
......@@ -170,7 +218,7 @@
qa_db_queuedcount_update();
} else {
if ($question['type']=='Q') // don't index answer if parent question is hidden or queued
if ($question['type'] == 'Q') // don't index answer if parent question is hidden or queued
qa_post_index($postid, 'A', $question['postid'], $question['postid'], null, $content, $format, $text, null, $question['categoryid']);
qa_update_q_counts_for_a($question['postid']);
......@@ -191,41 +239,56 @@
));
return $postid;
}
}
function qa_update_q_counts_for_a($questionid)
/*
Perform various common cached count updating operations to reflect changes in an answer of question $questionid
*/
{
/**
* Perform various common cached count updating operations to reflect changes in an answer of question $questionid
* @param $questionid
*/
function qa_update_q_counts_for_a($questionid)
{
qa_db_post_acount_update($questionid);
qa_db_hotness_update($questionid);
qa_db_acount_update();
qa_db_unaqcount_update();
qa_db_unupaqcount_update();
}
function qa_comment_create($userid, $handle, $cookieid, $content, $format, $text, $notify, $email, $question, $parent, $commentsfollows, $queued=false, $name=null)
/*
Add a comment (application level) - create record, update appropriate counts, index it, send notifications.
$question should contain database record for the question this is part of (as direct or comment on Q's answer).
If this is a comment on an answer, $answer should contain database record for the answer, otherwise null.
$commentsfollows should contain database records for all previous comments on the same question or answer,
but it can also contain other records that are ignored.
See qa-app-posts.php for a higher-level function which is easier to use.
*/
{
require_once QA_INCLUDE_DIR.'app/emails.php';
require_once QA_INCLUDE_DIR.'app/options.php';
require_once QA_INCLUDE_DIR.'app/format.php';
require_once QA_INCLUDE_DIR.'util/string.php';
}
/**
* Add a comment (application level) - create record, update appropriate counts, index it, send notifications.
* $question should contain database record for the question this is part of (as direct or comment on Q's answer).
* If this is a comment on an answer, $answer should contain database record for the answer, otherwise null.
* $commentsfollows should contain database records for all previous comments on the same question or answer,
* but it can also contain other records that are ignored.
* See qa-app-posts.php for a higher-level function which is easier to use.
* @param $userid
* @param $handle
* @param $cookieid
* @param $content
* @param $format
* @param $text
* @param $notify
* @param $email
* @param $question
* @param $parent
* @param $commentsfollows
* @param bool $queued
* @param $name
* @return mixed
*/
function qa_comment_create($userid, $handle, $cookieid, $content, $format, $text, $notify, $email, $question, $parent, $commentsfollows, $queued = false, $name = null)
{
require_once QA_INCLUDE_DIR . 'app/emails.php';
require_once QA_INCLUDE_DIR . 'app/options.php';
require_once QA_INCLUDE_DIR . 'app/format.php';
require_once QA_INCLUDE_DIR . 'util/string.php';
if (!isset($parent))
$parent=$question; // for backwards compatibility with old answer parameter
$parent = $question; // for backwards compatibility with old answer parameter
$postid=qa_db_post_create($queued ? 'C_QUEUED' : 'C', $parent['postid'], $userid, isset($userid) ? null : $cookieid,
$postid = qa_db_post_create($queued ? 'C_QUEUED' : 'C', $parent['postid'], $userid, isset($userid) ? null : $cookieid,
qa_remote_ip_address(), null, $content, $format, null, qa_combine_notify_email($userid, $notify, $email),
$question['categoryid'], isset($userid) ? null : $name);
......@@ -235,18 +298,19 @@
qa_db_queuedcount_update();
} else {
if ( ($question['type']=='Q') && (($parent['type']=='Q') || ($parent['type']=='A')) ) // only index if antecedents fully visible
if (($question['type'] == 'Q') && (($parent['type'] == 'Q') || ($parent['type'] == 'A'))) // only index if antecedents fully visible
qa_post_index($postid, 'C', $question['postid'], $parent['postid'], null, $content, $format, $text, null, $question['categoryid']);
qa_db_points_update_ifuser($userid, 'cposts');
qa_db_ccount_update();
}
$thread=array();
$thread = array();
foreach ($commentsfollows as $comment)
if (($comment['type']=='C') && ($comment['parentid']==$parent['postid'])) // find just those for this parent, fully visible
$thread[]=$comment;
foreach ($commentsfollows as $comment) {
if (($comment['type'] == 'C') && ($comment['parentid'] == $parent['postid'])) // find just those for this parent, fully visible
$thread[] = $comment;
}
qa_report_event($queued ? 'c_queue' : 'c_post', $userid, $handle, $cookieid, array(
'postid' => $postid,
......@@ -266,9 +330,4 @@
));
return $postid;
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
}
......@@ -20,34 +20,48 @@
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
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/updates.php';
require_once QA_INCLUDE_DIR.'db/post-create.php';
require_once QA_INCLUDE_DIR.'db/post-update.php';
require_once QA_INCLUDE_DIR.'db/points.php';
require_once QA_INCLUDE_DIR.'db/hotness.php';
define('QA_POST_STATUS_NORMAL', 0);
define('QA_POST_STATUS_HIDDEN', 1);
define('QA_POST_STATUS_QUEUED', 2);
function qa_question_set_content($oldquestion, $title, $content, $format, $text, $tagstring, $notify, $userid, $handle, $cookieid, $extravalue=null, $name=null, $remoderate=false, $silent=false)
/*
Change the fields of a question (application level) to $title, $content, $format, $tagstring, $notify, $extravalue
and $name, then reindex based on $text. For backwards compatibility if $name is null then the name will not be
changed. Pass the question's database record before changes in $oldquestion and details of the user doing this in
$userid, $handle and $cookieid. Set $remoderate to true if the question should be requeued for moderation if
modified. Set $silent to true to not mark the question as edited. Reports event as appropriate. See qa-app-posts.php
for a higher-level function which is easier to use.
*/
{
}
require_once QA_INCLUDE_DIR . 'app/post-create.php';
require_once QA_INCLUDE_DIR . 'app/updates.php';
require_once QA_INCLUDE_DIR . 'db/post-create.php';
require_once QA_INCLUDE_DIR . 'db/post-update.php';
require_once QA_INCLUDE_DIR . 'db/points.php';
require_once QA_INCLUDE_DIR . 'db/hotness.php';
define('QA_POST_STATUS_NORMAL', 0);
define('QA_POST_STATUS_HIDDEN', 1);
define('QA_POST_STATUS_QUEUED', 2);
/**
* Change the fields of a question (application level) to $title, $content, $format, $tagstring, $notify, $extravalue
* and $name, then reindex based on $text. For backwards compatibility if $name is null then the name will not be
* changed. Pass the question's database record before changes in $oldquestion and details of the user doing this in
* $userid, $handle and $cookieid. Set $remoderate to true if the question should be requeued for moderation if
* modified. Set $silent to true to not mark the question as edited. Reports event as appropriate. See qa-app-posts.php
* for a higher-level function which is easier to use.
* @param $oldquestion
* @param $title
* @param $content
* @param $format
* @param $text
* @param $tagstring
* @param $notify
* @param $userid
* @param $handle
* @param $cookieid
* @param $extravalue
* @param $name
* @param bool $remoderate
* @param bool $silent
*/
function qa_question_set_content($oldquestion, $title, $content, $format, $text, $tagstring, $notify, $userid, $handle, $cookieid, $extravalue = null, $name = null, $remoderate = false, $silent = false)
{
qa_post_unindex($oldquestion['postid']);
$wasqueued = ($oldquestion['type'] == 'Q_QUEUED');
......@@ -61,12 +75,12 @@
($titlechanged || $contentchanged) ? QA_UPDATE_CONTENT : QA_UPDATE_TAGS, $name);
if (isset($extravalue)) {
require_once QA_INCLUDE_DIR.'db/metas.php';
require_once QA_INCLUDE_DIR . 'db/metas.php';
qa_db_postmeta_set($oldquestion['postid'], 'qa_q_extra', $extravalue);
}
if ($setupdated && $remoderate) {
require_once QA_INCLUDE_DIR.'app/posts.php';
require_once QA_INCLUDE_DIR . 'app/posts.php';
$answers = qa_post_get_question_answers($oldquestion['postid']);
$commentsfollows = qa_post_get_question_commentsfollows($oldquestion['postid']);
......@@ -91,12 +105,11 @@
if ($oldquestion['flagcount'])
qa_db_flaggedcount_update();
}
elseif ($oldquestion['type'] == 'Q') { // not hidden or queued
} elseif ($oldquestion['type'] == 'Q') { // not hidden or queued
qa_post_index($oldquestion['postid'], 'Q', $oldquestion['postid'], $oldquestion['parentid'], $title, $content, $format, $text, $tagstring, $oldquestion['categoryid']);
}
$eventparams=array(
$eventparams = array(
'postid' => $oldquestion['postid'],
'title' => $title,
'content' => $content,
......@@ -121,18 +134,24 @@
if ($setupdated && $remoderate)
qa_report_event('q_requeue', $userid, $handle, $cookieid, $eventparams);
}
function qa_question_set_selchildid($userid, $handle, $cookieid, $oldquestion, $selchildid, $answers)
/*
Set the selected answer (application level) of $oldquestion to $selchildid. Pass details of the user doing this
in $userid, $handle and $cookieid, and the database records for the selected and deselected answers in $answers.
Handles user points values and notifications.
See qa-app-posts.php for a higher-level function which is easier to use.
*/
{
$oldselchildid=$oldquestion['selchildid'];
}
/**
* Set the selected answer (application level) of $oldquestion to $selchildid. Pass details of the user doing this
* in $userid, $handle and $cookieid, and the database records for the selected and deselected answers in $answers.
* Handles user points values and notifications.
* See qa-app-posts.php for a higher-level function which is easier to use.
* @param $userid
* @param $handle
* @param $cookieid
* @param $oldquestion
* @param $selchildid
* @param $answers
*/
function qa_question_set_selchildid($userid, $handle, $cookieid, $oldquestion, $selchildid, $answers)
{
$oldselchildid = $oldquestion['selchildid'];
qa_db_post_set_selchildid($oldquestion['postid'], isset($selchildid) ? $selchildid : null, $userid, qa_remote_ip_address());
qa_db_points_update_ifuser($oldquestion['userid'], 'aselects');
......@@ -159,20 +178,25 @@
'answer' => $answers[$selchildid],
));
}
}
function qa_question_close_clear($oldquestion, $oldclosepost, $userid, $handle, $cookieid)
/*
Reopen $oldquestion if it was closed. Pass details of the user doing this in $userid, $handle and $cookieid, and the
$oldclosepost (to match $oldquestion['closedbyid']) if any.
See qa-app-posts.php for a higher-level function which is easier to use.
*/
{
}
/**
* Reopen $oldquestion if it was closed. Pass details of the user doing this in $userid, $handle and $cookieid, and the
* $oldclosepost (to match $oldquestion['closedbyid']) if any.
* See qa-app-posts.php for a higher-level function which is easier to use.
* @param $oldquestion
* @param $oldclosepost
* @param $userid
* @param $handle
* @param $cookieid
*/
function qa_question_close_clear($oldquestion, $oldclosepost, $userid, $handle, $cookieid)
{
if (isset($oldquestion['closedbyid'])) {
qa_db_post_set_closed($oldquestion['postid'], null, $userid, qa_remote_ip_address());
if (isset($oldclosepost) && ($oldclosepost['parentid']==$oldquestion['postid'])) {
if (isset($oldclosepost) && ($oldclosepost['parentid'] == $oldquestion['postid'])) {
qa_post_unindex($oldclosepost['postid']);
qa_db_post_delete($oldclosepost['postid']);
}
......@@ -182,16 +206,22 @@
'oldquestion' => $oldquestion,
));
}
}
function qa_question_close_duplicate($oldquestion, $oldclosepost, $originalpostid, $userid, $handle, $cookieid)
/*
Close $oldquestion as a duplicate of the question with id $originalpostid. Pass details of the user doing this in
$userid, $handle and $cookieid, and the $oldclosepost (to match $oldquestion['closedbyid']) if any. See
qa-app-posts.php for a higher-level function which is easier to use.
*/
{
}
/**
* Close $oldquestion as a duplicate of the question with id $originalpostid. Pass details of the user doing this in
* $userid, $handle and $cookieid, and the $oldclosepost (to match $oldquestion['closedbyid']) if any. See
* qa-app-posts.php for a higher-level function which is easier to use.
* @param $oldquestion
* @param $oldclosepost
* @param $originalpostid
* @param $userid
* @param $handle
* @param $cookieid
*/
function qa_question_close_duplicate($oldquestion, $oldclosepost, $originalpostid, $userid, $handle, $cookieid)
{
qa_question_close_clear($oldquestion, $oldclosepost, $userid, $handle, $cookieid);
qa_db_post_set_closed($oldquestion['postid'], $originalpostid, $userid, qa_remote_ip_address());
......@@ -202,24 +232,30 @@
'reason' => 'duplicate',
'originalid' => $originalpostid,
));
}
function qa_question_close_other($oldquestion, $oldclosepost, $note, $userid, $handle, $cookieid)
/*
Close $oldquestion with the reason given in $note. Pass details of the user doing this in $userid, $handle and
$cookieid, and the $oldclosepost (to match $oldquestion['closedbyid']) if any.
See qa-app-posts.php for a higher-level function which is easier to use.
*/
{
}
/**
* Close $oldquestion with the reason given in $note. Pass details of the user doing this in $userid, $handle and
* $cookieid, and the $oldclosepost (to match $oldquestion['closedbyid']) if any.
* See qa-app-posts.php for a higher-level function which is easier to use.
* @param $oldquestion
* @param $oldclosepost
* @param $note
* @param $userid
* @param $handle
* @param $cookieid
*/
function qa_question_close_other($oldquestion, $oldclosepost, $note, $userid, $handle, $cookieid)
{
qa_question_close_clear($oldquestion, $oldclosepost, $userid, $handle, $cookieid);
$postid=qa_db_post_create('NOTE', $oldquestion['postid'], $userid, isset($userid) ? null : $cookieid,
$postid = qa_db_post_create('NOTE', $oldquestion['postid'], $userid, isset($userid) ? null : $cookieid,
qa_remote_ip_address(), null, $note, '', null, null, $oldquestion['categoryid']);
qa_db_posts_calc_category_path($postid);
if ($oldquestion['type']=='Q')
if ($oldquestion['type'] == 'Q')
qa_post_index($postid, 'NOTE', $oldquestion['postid'], $oldquestion['postid'], null, $note, '', $note, null, $oldquestion['categoryid']);
qa_db_post_set_closed($oldquestion['postid'], $postid, $userid, qa_remote_ip_address());
......@@ -230,79 +266,97 @@
'reason' => 'other',
'note' => $note,
));
}
function qa_question_set_hidden($oldquestion, $hidden, $userid, $handle, $cookieid, $answers, $commentsfollows, $closepost=null)
/*
Set $oldquestion to hidden if $hidden is true, visible/normal if otherwise. All other parameters are as for qa_question_set_status(...)
This function is included mainly for backwards compatibility.
*/
{
}
/**
* Set $oldquestion to hidden if $hidden is true, visible/normal if otherwise. All other parameters are as for qa_question_set_status(...)
* This function is included mainly for backwards compatibility.
* @param $oldquestion
* @param $hidden
* @param $userid
* @param $handle
* @param $cookieid
* @param $answers
* @param $commentsfollows
* @param $closepost
*/
function qa_question_set_hidden($oldquestion, $hidden, $userid, $handle, $cookieid, $answers, $commentsfollows, $closepost = null)
{
qa_question_set_status($oldquestion, $hidden ? QA_POST_STATUS_HIDDEN : QA_POST_STATUS_NORMAL, $userid, $handle, $cookieid, $answers, $commentsfollows, $closepost);
}
function qa_question_set_status($oldquestion, $status, $userid, $handle, $cookieid, $answers, $commentsfollows, $closepost=null)
/*
Set the status (application level) of $oldquestion to $status, one of the QA_POST_STATUS_* constants above. Pass
details of the user doing this in $userid, $handle and $cookieid, the database records for all answers to the
question in $answers, the database records for all comments on the question or the question's answers in
$commentsfollows ($commentsfollows can also contain records for follow-on questions which are ignored), and
$closepost to match $oldquestion['closedbyid'] (if any). Handles indexing, user points, cached counts and event
reports. See qa-app-posts.php for a higher-level function which is easier to use.
*/
{
require_once QA_INCLUDE_DIR.'app/format.php';
require_once QA_INCLUDE_DIR.'app/updates.php';
$washidden=($oldquestion['type']=='Q_HIDDEN');
$wasqueued=($oldquestion['type']=='Q_QUEUED');
$wasrequeued=$wasqueued && isset($oldquestion['updated']);
}
/**
* Set the status (application level) of $oldquestion to $status, one of the QA_POST_STATUS_* constants above. Pass
* details of the user doing this in $userid, $handle and $cookieid, the database records for all answers to the
* question in $answers, the database records for all comments on the question or the question's answers in
* $commentsfollows ($commentsfollows can also contain records for follow-on questions which are ignored), and
* $closepost to match $oldquestion['closedbyid'] (if any). Handles indexing, user points, cached counts and event
* reports. See qa-app-posts.php for a higher-level function which is easier to use.
* @param $oldquestion
* @param $status
* @param $userid
* @param $handle
* @param $cookieid
* @param $answers
* @param $commentsfollows
* @param $closepost
*/
function qa_question_set_status($oldquestion, $status, $userid, $handle, $cookieid, $answers, $commentsfollows, $closepost = null)
{
require_once QA_INCLUDE_DIR . 'app/format.php';
require_once QA_INCLUDE_DIR . 'app/updates.php';
$washidden = ($oldquestion['type'] == 'Q_HIDDEN');
$wasqueued = ($oldquestion['type'] == 'Q_QUEUED');
$wasrequeued = $wasqueued && isset($oldquestion['updated']);
qa_post_unindex($oldquestion['postid']);
foreach ($answers as $answer)
foreach ($answers as $answer) {
qa_post_unindex($answer['postid']);
}
foreach ($commentsfollows as $comment)
if ($comment['basetype']=='C')
foreach ($commentsfollows as $comment) {
if ($comment['basetype'] == 'C')
qa_post_unindex($comment['postid']);
}
if (@$closepost['parentid']==$oldquestion['postid'])
if (@$closepost['parentid'] == $oldquestion['postid'])
qa_post_unindex($closepost['postid']);
$setupdated=false;
$event=null;
$setupdated = false;
$event = null;
if ($status==QA_POST_STATUS_QUEUED) {
$newtype='Q_QUEUED';
if ($status == QA_POST_STATUS_QUEUED) {
$newtype = 'Q_QUEUED';
if (!$wasqueued)
$event='q_requeue'; // same event whether it was hidden or shown before
$event = 'q_requeue'; // same event whether it was hidden or shown before
} elseif ($status==QA_POST_STATUS_HIDDEN) {
$newtype='Q_HIDDEN';
} elseif ($status == QA_POST_STATUS_HIDDEN) {
$newtype = 'Q_HIDDEN';
if (!$washidden) {
$event=$wasqueued ? 'q_reject' : 'q_hide';
$event = $wasqueued ? 'q_reject' : 'q_hide';
if (!$wasqueued)
$setupdated=true;
$setupdated = true;
}
} elseif ($status==QA_POST_STATUS_NORMAL) {
$newtype='Q';
} elseif ($status == QA_POST_STATUS_NORMAL) {
$newtype = 'Q';
if ($wasqueued)
$event='q_approve';
$event = 'q_approve';
elseif ($washidden) {
$event='q_reshow';
$setupdated=true;
$event = 'q_reshow';
$setupdated = true;
}
} else
qa_fatal_error('Unknown status in qa_question_set_status(): '.$status);
qa_fatal_error('Unknown status in qa_question_set_status(): ' . $status);
qa_db_post_set_type($oldquestion['postid'], $newtype, $setupdated ? $userid : null, $setupdated ? qa_remote_ip_address() : null, QA_UPDATE_VISIBLE);
if ( $wasqueued && ($status==QA_POST_STATUS_NORMAL) && qa_opt('moderate_update_time') ) { // ... for approval of a post, can set time to now instead
if ($wasqueued && $status == QA_POST_STATUS_NORMAL && qa_opt('moderate_update_time')) { // ... for approval of a post, can set time to now instead
if ($wasrequeued) // reset edit time to now if there was one, since we're approving the edit...
qa_db_post_set_updated($oldquestion['postid'], null);
......@@ -315,36 +369,41 @@
qa_update_counts_for_q($oldquestion['postid']);
qa_db_points_update_ifuser($oldquestion['userid'], array('qposts', 'aselects'));
if ($wasqueued || ($status==QA_POST_STATUS_QUEUED))
if ($wasqueued || ($status == QA_POST_STATUS_QUEUED))
qa_db_queuedcount_update();
if ($oldquestion['flagcount'])
qa_db_flaggedcount_update();
if ($status==QA_POST_STATUS_NORMAL) {
if ($status == QA_POST_STATUS_NORMAL) {
qa_post_index($oldquestion['postid'], 'Q', $oldquestion['postid'], $oldquestion['parentid'], $oldquestion['title'], $oldquestion['content'],
$oldquestion['format'], qa_viewer_text($oldquestion['content'], $oldquestion['format']), $oldquestion['tags'], $oldquestion['categoryid']);
foreach ($answers as $answer)
if ($answer['type']=='A') // even if question visible, don't index hidden or queued answers
foreach ($answers as $answer) {
if ($answer['type'] == 'A') { // even if question visible, don't index hidden or queued answers
qa_post_index($answer['postid'], $answer['type'], $oldquestion['postid'], $answer['parentid'], null,
$answer['content'], $answer['format'], qa_viewer_text($answer['content'], $answer['format']), null, $answer['categoryid']);
}
}
foreach ($commentsfollows as $comment)
if ($comment['type']=='C') {
$answer=@$answers[$comment['parentid']];
foreach ($commentsfollows as $comment) {
if ($comment['type'] == 'C') {
$answer = @$answers[$comment['parentid']];
if ( (!isset($answer)) || ($answer['type']=='A') ) // don't index comment if it or its parent is hidden
if ((!isset($answer)) || ($answer['type'] == 'A')) { // don't index comment if it or its parent is hidden
qa_post_index($comment['postid'], $comment['type'], $oldquestion['postid'], $comment['parentid'], null,
$comment['content'], $comment['format'], qa_viewer_text($comment['content'], $comment['format']), null, $comment['categoryid']);
}
}
}
if ($closepost['parentid']==$oldquestion['postid'])
if ($closepost['parentid'] == $oldquestion['postid']) {
qa_post_index($closepost['postid'], $closepost['type'], $oldquestion['postid'], $closepost['parentid'], null,
$closepost['content'], $closepost['format'], qa_viewer_text($closepost['content'], $closepost['format']), null, $closepost['categoryid']);
}
}
$eventparams=array(
$eventparams = array(
'postid' => $oldquestion['postid'],
'parentid' => $oldquestion['parentid'],
'parent' => isset($oldquestion['parentid']) ? qa_db_single_select(qa_db_full_post_selectspec(null, $oldquestion['parentid'])) : null,
......@@ -357,14 +416,15 @@
'name' => $oldquestion['name'],
);
if (isset($event))
if (isset($event)) {
qa_report_event($event, $userid, $handle, $cookieid, $eventparams + array(
'oldquestion' => $oldquestion,
));
}
if ($wasqueued && ($status==QA_POST_STATUS_NORMAL) && !$wasrequeued) {
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR.'util/string.php';
if ($wasqueued && ($status == QA_POST_STATUS_NORMAL) && !$wasrequeued) {
require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR . 'util/string.php';
qa_report_event('q_post', $oldquestion['userid'], $oldquestion['handle'], $oldquestion['cookieid'], $eventparams + array(
'notify' => isset($oldquestion['notify']),
......@@ -372,48 +432,60 @@
'delayed' => $oldquestion['created'],
));
}
}
function qa_question_set_category($oldquestion, $categoryid, $userid, $handle, $cookieid, $answers, $commentsfollows, $closepost=null, $silent=false)
/*
Sets the category (application level) of $oldquestion to $categoryid. Pass details of the user doing this in
$userid, $handle and $cookieid, the database records for all answers to the question in $answers, the database
records for all comments on the question or the question's answers in $commentsfollows ($commentsfollows can also
contain records for follow-on questions which are ignored), and $closepost to match $oldquestion['closedbyid'] (if any).
Set $silent to true to not mark the question as edited. Handles cached counts and event reports and will reset category
IDs and paths for all answers and comments. See qa-app-posts.php for a higher-level function which is easier to use.
*/
{
$oldpath=qa_db_post_get_category_path($oldquestion['postid']);
}
/**
* Sets the category (application level) of $oldquestion to $categoryid. Pass details of the user doing this in
* $userid, $handle and $cookieid, the database records for all answers to the question in $answers, the database
* records for all comments on the question or the question's answers in $commentsfollows ($commentsfollows can also
* contain records for follow-on questions which are ignored), and $closepost to match $oldquestion['closedbyid'] (if any).
* Set $silent to true to not mark the question as edited. Handles cached counts and event reports and will reset category
* IDs and paths for all answers and comments. See qa-app-posts.php for a higher-level function which is easier to use.
* @param $oldquestion
* @param $categoryid
* @param $userid
* @param $handle
* @param $cookieid
* @param $answers
* @param $commentsfollows
* @param $closepost
* @param bool $silent
*/
function qa_question_set_category($oldquestion, $categoryid, $userid, $handle, $cookieid, $answers, $commentsfollows, $closepost = null, $silent = false)
{
$oldpath = qa_db_post_get_category_path($oldquestion['postid']);
qa_db_post_set_category($oldquestion['postid'], $categoryid, $silent ? null : $userid, $silent ? null : qa_remote_ip_address());
qa_db_posts_calc_category_path($oldquestion['postid']);
$newpath=qa_db_post_get_category_path($oldquestion['postid']);
$newpath = qa_db_post_get_category_path($oldquestion['postid']);
qa_db_category_path_qcount_update($oldpath);
qa_db_category_path_qcount_update($newpath);
$otherpostids=array();
foreach ($answers as $answer)
$otherpostids[]=$answer['postid'];
$otherpostids = array();
foreach ($answers as $answer) {
$otherpostids[] = $answer['postid'];
}
foreach ($commentsfollows as $comment)
if ($comment['basetype']=='C')
$otherpostids[]=$comment['postid'];
foreach ($commentsfollows as $comment) {
if ($comment['basetype'] == 'C')
$otherpostids[] = $comment['postid'];
}
if (@$closepost['parentid']==$oldquestion['postid'])
$otherpostids[]=$closepost['postid'];
if (@$closepost['parentid'] == $oldquestion['postid'])
$otherpostids[] = $closepost['postid'];
qa_db_posts_set_category_path($otherpostids, $newpath);
$searchmodules=qa_load_modules_with('search', 'move_post');
$searchmodules = qa_load_modules_with('search', 'move_post');
foreach ($searchmodules as $searchmodule) {
$searchmodule->move_post($oldquestion['postid'], $categoryid);
foreach ($otherpostids as $otherpostid)
foreach ($otherpostids as $otherpostid) {
$searchmodule->move_post($otherpostid, $categoryid);
}
}
qa_report_event('q_move', $userid, $handle, $cookieid, array(
'postid' => $oldquestion['postid'],
......@@ -421,20 +493,25 @@
'categoryid' => $categoryid,
'oldcategoryid' => $oldquestion['categoryid'],
));
}
function qa_question_delete($oldquestion, $userid, $handle, $cookieid, $oldclosepost=null)
/*
Permanently delete a question (application level) from the database. The question must not have any answers or
comments on it. Pass details of the user doing this in $userid, $handle and $cookieid, and $closepost to match
$oldquestion['closedbyid'] (if any). Handles unindexing, votes, points, cached counts and event reports.
See qa-app-posts.php for a higher-level function which is easier to use.
*/
{
require_once QA_INCLUDE_DIR.'db/votes.php';
if ($oldquestion['type']!='Q_HIDDEN')
}
/**
* Permanently delete a question (application level) from the database. The question must not have any answers or
* comments on it. Pass details of the user doing this in $userid, $handle and $cookieid, and $closepost to match
* $oldquestion['closedbyid'] (if any). Handles unindexing, votes, points, cached counts and event reports.
* See qa-app-posts.php for a higher-level function which is easier to use.
* @param $oldquestion
* @param $userid
* @param $handle
* @param $cookieid
* @param $oldclosepost
*/
function qa_question_delete($oldquestion, $userid, $handle, $cookieid, $oldclosepost = null)
{
require_once QA_INCLUDE_DIR . 'db/votes.php';
if ($oldquestion['type'] != 'Q_HIDDEN')
qa_fatal_error('Tried to delete a non-hidden question');
$params = array(
......@@ -444,14 +521,14 @@
qa_report_event('q_delete_before', $userid, $handle, $cookieid, $params);
if (isset($oldclosepost) && ($oldclosepost['parentid']==$oldquestion['postid'])) {
if (isset($oldclosepost) && ($oldclosepost['parentid'] == $oldquestion['postid'])) {
qa_db_post_set_closed($oldquestion['postid'], null); // for foreign key constraint
qa_post_unindex($oldclosepost['postid']);
qa_db_post_delete($oldclosepost['postid']);
}
$useridvotes=qa_db_uservote_post_get($oldquestion['postid']);
$oldpath=qa_db_post_get_category_path($oldquestion['postid']);
$useridvotes = qa_db_uservote_post_get($oldquestion['postid']);
$oldpath = qa_db_post_get_category_path($oldquestion['postid']);
qa_post_unindex($oldquestion['postid']);
qa_db_post_delete($oldquestion['postid']); // also deletes any related voteds due to foreign key cascading
......@@ -459,21 +536,26 @@
qa_db_category_path_qcount_update($oldpath); // don't do inside qa_update_counts_for_q() since post no longer exists
qa_db_points_update_ifuser($oldquestion['userid'], array('qposts', 'aselects', 'qvoteds', 'upvoteds', 'downvoteds'));
foreach ($useridvotes as $voteruserid => $vote)
qa_db_points_update_ifuser($voteruserid, ($vote>0) ? 'qupvotes' : 'qdownvotes');
foreach ($useridvotes as $voteruserid => $vote) {
// could do this in one query like in qa_db_users_recalc_points() but this will do for now - unlikely to be many votes
qa_db_points_update_ifuser($voteruserid, ($vote > 0) ? 'qupvotes' : 'qdownvotes');
}
qa_report_event('q_delete', $userid, $handle, $cookieid, $params);
}
}
function qa_question_set_userid($oldquestion, $userid, $handle, $cookieid)
/*
Set the author (application level) of $oldquestion to $userid and also pass $handle and $cookieid
of user. Updates points and reports events as appropriate.
*/
{
require_once QA_INCLUDE_DIR.'db/votes.php';
/**
* Set the author (application level) of $oldquestion to $userid and also pass $handle and $cookieid
* of user. Updates points and reports events as appropriate.
* @param $oldquestion
* @param $userid
* @param $handle
* @param $cookieid
*/
function qa_question_set_userid($oldquestion, $userid, $handle, $cookieid)
{
require_once QA_INCLUDE_DIR . 'db/votes.php';
$postid = $oldquestion['postid'];
......@@ -488,54 +570,69 @@
'postid' => $postid,
'oldquestion' => $oldquestion,
));
}
}
function qa_post_unindex($postid)
/*
Remove post $postid from our index and update appropriate word counts. Calls through to all search modules.
*/
{
/**
* Remove post $postid from our index and update appropriate word counts. Calls through to all search modules.
* @param $postid
*/
function qa_post_unindex($postid)
{
global $qa_post_indexing_suspended;
if ($qa_post_indexing_suspended>0)
if ($qa_post_indexing_suspended > 0)
return;
// Send through to any search modules for unindexing
$searchmodules=qa_load_modules_with('search', 'unindex_post');
foreach ($searchmodules as $searchmodule)
$searchmodules = qa_load_modules_with('search', 'unindex_post');
foreach ($searchmodules as $searchmodule) {
$searchmodule->unindex_post($postid);
}
function qa_answer_set_content($oldanswer, $content, $format, $text, $notify, $userid, $handle, $cookieid, $question, $name=null, $remoderate=false, $silent=false)
/*
Change the fields of an answer (application level) to $content, $format, $notify and $name, then reindex based on
$text. For backwards compatibility if $name is null then the name will not be changed. Pass the answer's database
record before changes in $oldanswer, the question's in $question, and details of the user doing this in $userid,
$handle and $cookieid. Set $remoderate to true if the question should be requeued for moderation if modified. Set
$silent to true to not mark the question as edited. Handle indexing and event reports as appropriate. See
qa-app-posts.php for a higher-level function which is easier to use.
*/
{
}
/**
* Change the fields of an answer (application level) to $content, $format, $notify and $name, then reindex based on
* $text. For backwards compatibility if $name is null then the name will not be changed. Pass the answer's database
* record before changes in $oldanswer, the question's in $question, and details of the user doing this in $userid,
* $handle and $cookieid. Set $remoderate to true if the question should be requeued for moderation if modified. Set
* $silent to true to not mark the question as edited. Handle indexing and event reports as appropriate. See
* qa-app-posts.php for a higher-level function which is easier to use.
* @param $oldanswer
* @param $content
* @param $format
* @param $text
* @param $notify
* @param $userid
* @param $handle
* @param $cookieid
* @param $question
* @param $name
* @param bool $remoderate
* @param bool $silent
*/
function qa_answer_set_content($oldanswer, $content, $format, $text, $notify, $userid, $handle, $cookieid, $question, $name = null, $remoderate = false, $silent = false)
{
qa_post_unindex($oldanswer['postid']);
$wasqueued=($oldanswer['type']=='A_QUEUED');
$contentchanged=strcmp($oldanswer['content'], $content) || strcmp($oldanswer['format'], $format);
$setupdated=$contentchanged && (!$wasqueued) && !$silent;
$wasqueued = ($oldanswer['type'] == 'A_QUEUED');
$contentchanged = strcmp($oldanswer['content'], $content) || strcmp($oldanswer['format'], $format);
$setupdated = $contentchanged && (!$wasqueued) && !$silent;
qa_db_post_set_content($oldanswer['postid'], $oldanswer['title'], $content, $format, $oldanswer['tags'], $notify,
$setupdated ? $userid : null, $setupdated ? qa_remote_ip_address() : null, QA_UPDATE_CONTENT, $name);
if ($setupdated && $remoderate) {
require_once QA_INCLUDE_DIR.'app/posts.php';
require_once QA_INCLUDE_DIR . 'app/posts.php';
$commentsfollows=qa_post_get_answer_commentsfollows($oldanswer['postid']);
$commentsfollows = qa_post_get_answer_commentsfollows($oldanswer['postid']);
foreach ($commentsfollows as $comment)
if ( ($comment['basetype']=='C') && ($comment['parentid']==$oldanswer['postid']) )
foreach ($commentsfollows as $comment) {
if (($comment['basetype'] == 'C') && ($comment['parentid'] == $oldanswer['postid']))
qa_post_unindex($comment['postid']);
}
qa_db_post_set_type($oldanswer['postid'], 'A_QUEUED');
qa_update_q_counts_for_a($question['postid']);
......@@ -545,11 +642,11 @@
if ($oldanswer['flagcount'])
qa_db_flaggedcount_update();
} elseif ( ($oldanswer['type']=='A') && ($question['type']=='Q') ) { // don't index if question or answer are hidden/queued
} elseif (($oldanswer['type'] == 'A') && ($question['type'] == 'Q')) { // don't index if question or answer are hidden/queued
qa_post_index($oldanswer['postid'], 'A', $question['postid'], $oldanswer['parentid'], null, $content, $format, $text, null, $oldanswer['categoryid']);
}
$eventparams=array(
$eventparams = array(
'postid' => $oldanswer['postid'],
'parentid' => $oldanswer['parentid'],
'parent' => $question,
......@@ -569,75 +666,90 @@
if ($setupdated && $remoderate)
qa_report_event('a_requeue', $userid, $handle, $cookieid, $eventparams);
}
function qa_answer_set_hidden($oldanswer, $hidden, $userid, $handle, $cookieid, $question, $commentsfollows)
/*
Set $oldanswer to hidden if $hidden is true, visible/normal if otherwise. All other parameters are as for qa_answer_set_status(...)
This function is included mainly for backwards compatibility.
*/
{
}
/**
* Set $oldanswer to hidden if $hidden is true, visible/normal if otherwise. All other parameters are as for qa_answer_set_status(...)
* This function is included mainly for backwards compatibility.
* @param $oldanswer
* @param $hidden
* @param $userid
* @param $handle
* @param $cookieid
* @param $question
* @param $commentsfollows
*/
function qa_answer_set_hidden($oldanswer, $hidden, $userid, $handle, $cookieid, $question, $commentsfollows)
{
qa_answer_set_status($oldanswer, $hidden ? QA_POST_STATUS_HIDDEN : QA_POST_STATUS_NORMAL, $userid, $handle, $cookieid, $question, $commentsfollows);
}
function qa_answer_set_status($oldanswer, $status, $userid, $handle, $cookieid, $question, $commentsfollows)
/*
Set the status (application level) of $oldanswer to $status, one of the QA_POST_STATUS_* constants above. Pass
details of the user doing this in $userid, $handle and $cookieid, the database record for the question in $question,
and the database records for all comments on the answer in $commentsfollows ($commentsfollows can also contain other
records which are ignored). Handles indexing, user points, cached counts and event reports. See qa-app-posts.php for
a higher-level function which is easier to use.
*/
{
require_once QA_INCLUDE_DIR.'app/format.php';
$washidden=($oldanswer['type']=='A_HIDDEN');
$wasqueued=($oldanswer['type']=='A_QUEUED');
$wasrequeued=$wasqueued && isset($oldanswer['updated']);
}
/**
* Set the status (application level) of $oldanswer to $status, one of the QA_POST_STATUS_* constants above. Pass
* details of the user doing this in $userid, $handle and $cookieid, the database record for the question in $question,
* and the database records for all comments on the answer in $commentsfollows ($commentsfollows can also contain other
* records which are ignored). Handles indexing, user points, cached counts and event reports. See qa-app-posts.php for
* a higher-level function which is easier to use.
* @param $oldanswer
* @param $status
* @param $userid
* @param $handle
* @param $cookieid
* @param $question
* @param $commentsfollows
*/
function qa_answer_set_status($oldanswer, $status, $userid, $handle, $cookieid, $question, $commentsfollows)
{
require_once QA_INCLUDE_DIR . 'app/format.php';
$washidden = ($oldanswer['type'] == 'A_HIDDEN');
$wasqueued = ($oldanswer['type'] == 'A_QUEUED');
$wasrequeued = $wasqueued && isset($oldanswer['updated']);
qa_post_unindex($oldanswer['postid']);
foreach ($commentsfollows as $comment)
if ( ($comment['basetype']=='C') && ($comment['parentid']==$oldanswer['postid']) )
foreach ($commentsfollows as $comment) {
if (($comment['basetype'] == 'C') && ($comment['parentid'] == $oldanswer['postid']))
qa_post_unindex($comment['postid']);
}
$setupdated=false;
$event=null;
$setupdated = false;
$event = null;
if ($status==QA_POST_STATUS_QUEUED) {
$newtype='A_QUEUED';
if ($status == QA_POST_STATUS_QUEUED) {
$newtype = 'A_QUEUED';
if (!$wasqueued)
$event='a_requeue'; // same event whether it was hidden or shown before
$event = 'a_requeue'; // same event whether it was hidden or shown before
} elseif ($status==QA_POST_STATUS_HIDDEN) {
$newtype='A_HIDDEN';
} elseif ($status == QA_POST_STATUS_HIDDEN) {
$newtype = 'A_HIDDEN';
if (!$washidden) {
$event=$wasqueued ? 'a_reject' : 'a_hide';
$event = $wasqueued ? 'a_reject' : 'a_hide';
if (!$wasqueued)
$setupdated=true;
$setupdated = true;
}
if ($question['selchildid'] == $oldanswer['postid']) { // remove selected answer
qa_question_set_selchildid(null, null, null, $question, null, array($oldanswer['postid'] => $oldanswer));
}
} elseif ($status==QA_POST_STATUS_NORMAL) {
$newtype='A';
} elseif ($status == QA_POST_STATUS_NORMAL) {
$newtype = 'A';
if ($wasqueued)
$event='a_approve';
$event = 'a_approve';
elseif ($washidden) {
$event='a_reshow';
$setupdated=true;
$event = 'a_reshow';
$setupdated = true;
}
} else
qa_fatal_error('Unknown status in qa_answer_set_status(): '.$status);
qa_fatal_error('Unknown status in qa_answer_set_status(): ' . $status);
qa_db_post_set_type($oldanswer['postid'], $newtype, $setupdated ? $userid : null, $setupdated ? qa_remote_ip_address() : null, QA_UPDATE_VISIBLE);
if ( $wasqueued && ($status==QA_POST_STATUS_NORMAL) && qa_opt('moderate_update_time') ) { // ... for approval of a post, can set time to now instead
if ($wasqueued && ($status == QA_POST_STATUS_NORMAL) && qa_opt('moderate_update_time')) { // ... for approval of a post, can set time to now instead
if ($wasrequeued)
qa_db_post_set_updated($oldanswer['postid'], null);
else
......@@ -647,23 +759,25 @@
qa_update_q_counts_for_a($question['postid']);
qa_db_points_update_ifuser($oldanswer['userid'], array('aposts', 'aselecteds'));
if ($wasqueued || ($status==QA_POST_STATUS_QUEUED))
if ($wasqueued || $status == QA_POST_STATUS_QUEUED)
qa_db_queuedcount_update();
if ($oldanswer['flagcount'])
qa_db_flaggedcount_update();
if (($question['type']=='Q') && ($status==QA_POST_STATUS_NORMAL)) { // even if answer visible, don't index if question is hidden or queued
if (($question['type'] == 'Q') && ($status == QA_POST_STATUS_NORMAL)) { // even if answer visible, don't index if question is hidden or queued
qa_post_index($oldanswer['postid'], 'A', $question['postid'], $oldanswer['parentid'], null, $oldanswer['content'],
$oldanswer['format'], qa_viewer_text($oldanswer['content'], $oldanswer['format']), null, $oldanswer['categoryid']);
foreach ($commentsfollows as $comment)
if ( ($comment['type']=='C') && ($comment['parentid']==$oldanswer['postid']) ) // and don't index hidden/queued comments
foreach ($commentsfollows as $comment) {
if (($comment['type'] == 'C') && ($comment['parentid'] == $oldanswer['postid'])) { // and don't index hidden/queued comments
qa_post_index($comment['postid'], $comment['type'], $question['postid'], $comment['parentid'], null, $comment['content'],
$comment['format'], qa_viewer_text($comment['content'], $comment['format']), null, $comment['categoryid']);
}
}
}
$eventparams=array(
$eventparams = array(
'postid' => $oldanswer['postid'],
'parentid' => $oldanswer['parentid'],
'parent' => $question,
......@@ -674,13 +788,14 @@
'name' => $oldanswer['name'],
);
if (isset($event))
if (isset($event)) {
qa_report_event($event, $userid, $handle, $cookieid, $eventparams + array(
'oldanswer' => $oldanswer,
));
}
if ($wasqueued && ($status==QA_POST_STATUS_NORMAL) && !$wasrequeued) {
require_once QA_INCLUDE_DIR.'util/string.php';
if ($wasqueued && ($status == QA_POST_STATUS_NORMAL) && !$wasrequeued) {
require_once QA_INCLUDE_DIR . 'util/string.php';
qa_report_event('a_post', $oldanswer['userid'], $oldanswer['handle'], $oldanswer['cookieid'], $eventparams + array(
'notify' => isset($oldanswer['notify']),
......@@ -688,23 +803,28 @@
'delayed' => $oldanswer['created'],
));
}
}
function qa_answer_delete($oldanswer, $question, $userid, $handle, $cookieid)
/*
Permanently delete an answer (application level) from the database. The answer must not have any comments or
follow-on questions. Pass the database record for the question in $question and details of the user doing this
in $userid, $handle and $cookieid. Handles unindexing, votes, points, cached counts and event reports.
See qa-app-posts.php for a higher-level function which is easier to use.
*/
{
require_once QA_INCLUDE_DIR.'db/votes.php';
if ($oldanswer['type']!='A_HIDDEN')
}
/**
* Permanently delete an answer (application level) from the database. The answer must not have any comments or
* follow-on questions. Pass the database record for the question in $question and details of the user doing this
* in $userid, $handle and $cookieid. Handles unindexing, votes, points, cached counts and event reports.
* See qa-app-posts.php for a higher-level function which is easier to use.
* @param $oldanswer
* @param $question
* @param $userid
* @param $handle
* @param $cookieid
*/
function qa_answer_delete($oldanswer, $question, $userid, $handle, $cookieid)
{
require_once QA_INCLUDE_DIR . 'db/votes.php';
if ($oldanswer['type'] != 'A_HIDDEN')
qa_fatal_error('Tried to delete a non-hidden answer');
$useridvotes=qa_db_uservote_post_get($oldanswer['postid']);
$useridvotes = qa_db_uservote_post_get($oldanswer['postid']);
$params = array(
'postid' => $oldanswer['postid'],
......@@ -717,7 +837,7 @@
qa_post_unindex($oldanswer['postid']);
qa_db_post_delete($oldanswer['postid']); // also deletes any related voteds due to cascading
if ($question['selchildid']==$oldanswer['postid']) {
if ($question['selchildid'] == $oldanswer['postid']) {
qa_db_post_set_selchildid($question['postid'], null);
qa_db_points_update_ifuser($question['userid'], 'aselects');
qa_db_unselqcount_update();
......@@ -726,21 +846,26 @@
qa_update_q_counts_for_a($question['postid']);
qa_db_points_update_ifuser($oldanswer['userid'], array('aposts', 'aselecteds', 'avoteds', 'upvoteds', 'downvoteds'));
foreach ($useridvotes as $voteruserid => $vote)
qa_db_points_update_ifuser($voteruserid, ($vote>0) ? 'aupvotes' : 'adownvotes');
foreach ($useridvotes as $voteruserid => $vote) {
// could do this in one query like in qa_db_users_recalc_points() but this will do for now - unlikely to be many votes
qa_db_points_update_ifuser($voteruserid, ($vote > 0) ? 'aupvotes' : 'adownvotes');
}
qa_report_event('a_delete', $userid, $handle, $cookieid, $params);
}
}
function qa_answer_set_userid($oldanswer, $userid, $handle, $cookieid)
/*
Set the author (application level) of $oldanswer to $userid and also pass $handle and $cookieid
of user. Updates points and reports events as appropriate.
*/
{
require_once QA_INCLUDE_DIR.'db/votes.php';
/**
* Set the author (application level) of $oldanswer to $userid and also pass $handle and $cookieid
* of user. Updates points and reports events as appropriate.
* @param $oldanswer
* @param $userid
* @param $handle
* @param $cookieid
*/
function qa_answer_set_userid($oldanswer, $userid, $handle, $cookieid)
{
require_once QA_INCLUDE_DIR . 'db/votes.php';
$postid = $oldanswer['postid'];
......@@ -756,28 +881,41 @@
'parentid' => $oldanswer['parentid'],
'oldanswer' => $oldanswer,
));
}
function qa_comment_set_content($oldcomment, $content, $format, $text, $notify, $userid, $handle, $cookieid, $question, $parent, $name=null, $remoderate=false, $silent=false)
/*
Change the fields of a comment (application level) to $content, $format, $notify and $name, then reindex based on
$text. For backwards compatibility if $name is null then the name will not be changed. Pass the comment's database
record before changes in $oldcomment, details of the user doing this in $userid, $handle and $cookieid, the
antecedent question in $question and the answer's database record in $answer if this is a comment on an answer,
otherwise null. Set $remoderate to true if the question should be requeued for moderation if modified. Set $silent
to true to not mark the question as edited. Handles unindexing and event reports. See qa-app-posts.php for a
higher-level function which is easier to use.
*/
{
}
/**
* Change the fields of a comment (application level) to $content, $format, $notify and $name, then reindex based on
* $text. For backwards compatibility if $name is null then the name will not be changed. Pass the comment's database
* record before changes in $oldcomment, details of the user doing this in $userid, $handle and $cookieid, the
* antecedent question in $question and the answer's database record in $answer if this is a comment on an answer,
* otherwise null. Set $remoderate to true if the question should be requeued for moderation if modified. Set $silent
* to true to not mark the question as edited. Handles unindexing and event reports. See qa-app-posts.php for a
* higher-level function which is easier to use.
* @param $oldcomment
* @param $content
* @param $format
* @param $text
* @param $notify
* @param $userid
* @param $handle
* @param $cookieid
* @param $question
* @param $parent
* @param $name
* @param bool $remoderate
* @param bool $silent
*/
function qa_comment_set_content($oldcomment, $content, $format, $text, $notify, $userid, $handle, $cookieid, $question, $parent, $name = null, $remoderate = false, $silent = false)
{
if (!isset($parent))
$parent=$question; // for backwards compatibility with old answer parameter
$parent = $question; // for backwards compatibility with old answer parameter
qa_post_unindex($oldcomment['postid']);
$wasqueued=($oldcomment['type']=='C_QUEUED');
$contentchanged=strcmp($oldcomment['content'], $content) || strcmp($oldcomment['format'], $format);
$setupdated=$contentchanged && (!$wasqueued) && !$silent;
$wasqueued = ($oldcomment['type'] == 'C_QUEUED');
$contentchanged = strcmp($oldcomment['content'], $content) || strcmp($oldcomment['format'], $format);
$setupdated = $contentchanged && (!$wasqueued) && !$silent;
qa_db_post_set_content($oldcomment['postid'], $oldcomment['title'], $content, $format, $oldcomment['tags'], $notify,
$setupdated ? $userid : null, $setupdated ? qa_remote_ip_address() : null, QA_UPDATE_CONTENT, $name);
......@@ -791,11 +929,11 @@
if ($oldcomment['flagcount'])
qa_db_flaggedcount_update();
} elseif ( ($oldcomment['type']=='C') && ($question['type']=='Q') && (($parent['type']=='Q') || ($parent['type']=='A')) ) { // all must be visible
} elseif ($oldcomment['type'] == 'C' && $question['type'] == 'Q' && ($parent['type'] == 'Q' || $parent['type'] == 'A')) { // all must be visible
qa_post_index($oldcomment['postid'], 'C', $question['postid'], $oldcomment['parentid'], null, $content, $format, $text, null, $oldcomment['categoryid']);
}
$eventparams=array(
$eventparams = array(
'postid' => $oldcomment['postid'],
'parentid' => $oldcomment['parentid'],
'parenttype' => $parent['basetype'],
......@@ -818,35 +956,50 @@
if ($setupdated && $remoderate)
qa_report_event('c_requeue', $userid, $handle, $cookieid, $eventparams);
}
function qa_answer_to_comment($oldanswer, $parentid, $content, $format, $text, $notify, $userid, $handle, $cookieid, $question, $answers, $commentsfollows, $name=null, $remoderate=false, $silent=false)
/*
Convert an answer to a comment (application level) and set its fields to $content, $format, $notify and $name. For
backwards compatibility if $name is null then the name will not be changed. Pass the answer's database record before
changes in $oldanswer, the new comment's $parentid to be, details of the user doing this in $userid, $handle and
$cookieid, the antecedent question's record in $question, the records for all answers to that question in $answers,
and the records for all comments on the (old) answer and questions following from the (old) answer in
$commentsfollows ($commentsfollows can also contain other records which are ignored). Set $remoderate to true if the
question should be requeued for moderation if modified. Set $silent to true to not mark the question as edited.
Handles indexing (based on $text), user points, cached counts and event reports.
*/
{
require_once QA_INCLUDE_DIR.'db/votes.php';
$parent=isset($answers[$parentid]) ? $answers[$parentid] : $question;
}
/**
* Convert an answer to a comment (application level) and set its fields to $content, $format, $notify and $name. For
* backwards compatibility if $name is null then the name will not be changed. Pass the answer's database record before
* changes in $oldanswer, the new comment's $parentid to be, details of the user doing this in $userid, $handle and
* $cookieid, the antecedent question's record in $question, the records for all answers to that question in $answers,
* and the records for all comments on the (old) answer and questions following from the (old) answer in
* $commentsfollows ($commentsfollows can also contain other records which are ignored). Set $remoderate to true if the
* question should be requeued for moderation if modified. Set $silent to true to not mark the question as edited.
* Handles indexing (based on $text), user points, cached counts and event reports.
* @param $oldanswer
* @param $parentid
* @param $content
* @param $format
* @param $text
* @param $notify
* @param $userid
* @param $handle
* @param $cookieid
* @param $question
* @param $answers
* @param $commentsfollows
* @param $name
* @param bool $remoderate
* @param bool $silent
*/
function qa_answer_to_comment($oldanswer, $parentid, $content, $format, $text, $notify, $userid, $handle, $cookieid, $question, $answers, $commentsfollows, $name = null, $remoderate = false, $silent = false)
{
require_once QA_INCLUDE_DIR . 'db/votes.php';
$parent = isset($answers[$parentid]) ? $answers[$parentid] : $question;
qa_post_unindex($oldanswer['postid']);
$wasqueued=($oldanswer['type']=='A_QUEUED');
$contentchanged=strcmp($oldanswer['content'], $content) || strcmp($oldanswer['format'], $format);
$setupdated=$contentchanged && (!$wasqueued) && !$silent;
$wasqueued = ($oldanswer['type'] == 'A_QUEUED');
$contentchanged = strcmp($oldanswer['content'], $content) || strcmp($oldanswer['format'], $format);
$setupdated = $contentchanged && (!$wasqueued) && !$silent;
if ($setupdated && $remoderate)
$newtype='C_QUEUED';
$newtype = 'C_QUEUED';
else
$newtype=substr_replace($oldanswer['type'], 'C', 0, 1);
$newtype = substr_replace($oldanswer['type'], 'C', 0, 1);
qa_db_post_set_type($oldanswer['postid'], $newtype, ($wasqueued || $silent) ? null : $userid,
($wasqueued || $silent) ? null : qa_remote_ip_address(), QA_UPDATE_TYPE);
......@@ -854,18 +1007,20 @@
qa_db_post_set_content($oldanswer['postid'], $oldanswer['title'], $content, $format, $oldanswer['tags'], $notify,
$setupdated ? $userid : null, $setupdated ? qa_remote_ip_address() : null, QA_UPDATE_CONTENT, $name);
foreach ($commentsfollows as $commentfollow)
if ($commentfollow['parentid']==$oldanswer['postid']) // do same thing for comments and follows
foreach ($commentsfollows as $commentfollow) {
if ($commentfollow['parentid'] == $oldanswer['postid']) // do same thing for comments and follows
qa_db_post_set_parent($commentfollow['postid'], $parentid);
}
qa_update_q_counts_for_a($question['postid']);
qa_db_ccount_update();
qa_db_points_update_ifuser($oldanswer['userid'], array('aposts', 'aselecteds', 'cposts', 'avoteds'));
$useridvotes=qa_db_uservote_post_get($oldanswer['postid']);
foreach ($useridvotes as $voteruserid => $vote)
qa_db_points_update_ifuser($voteruserid, ($vote>0) ? 'aupvotes' : 'adownvotes');
$useridvotes = qa_db_uservote_post_get($oldanswer['postid']);
foreach ($useridvotes as $voteruserid => $vote) {
// could do this in one query like in qa_db_users_recalc_points() but this will do for now - unlikely to be many votes
qa_db_points_update_ifuser($voteruserid, ($vote > 0) ? 'aupvotes' : 'adownvotes');
}
if ($setupdated && $remoderate) {
qa_db_queuedcount_update();
......@@ -873,14 +1028,14 @@
if ($oldanswer['flagcount'])
qa_db_flaggedcount_update();
} elseif ( ($oldanswer['type']=='A') && ($question['type']=='Q') && (($parent['type']=='Q') || ($parent['type']=='A')) ) // only if all fully visible
} elseif (($oldanswer['type'] == 'A') && ($question['type'] == 'Q') && (($parent['type'] == 'Q') || ($parent['type'] == 'A'))) // only if all fully visible
qa_post_index($oldanswer['postid'], 'C', $question['postid'], $parentid, null, $content, $format, $text, null, $oldanswer['categoryid']);
if ($question['selchildid'] == $oldanswer['postid']) { // remove selected answer
qa_question_set_selchildid(null, null, null, $question, null, array($oldanswer['postid'] => $oldanswer));
}
$eventparams=array(
$eventparams = array(
'postid' => $oldanswer['postid'],
'parentid' => $parentid,
'parenttype' => $parent['basetype'],
......@@ -901,72 +1056,87 @@
'contentchanged' => $contentchanged,
));
if ($setupdated && $remoderate)
qa_report_event('c_requeue', $userid, $handle, $cookieid, $eventparams);
if ($setupdated && $remoderate) {
// a-to-c conversion can be detected by presence of $event['oldanswer'] instead of $event['oldcomment']
qa_report_event('c_requeue', $userid, $handle, $cookieid, $eventparams);
}
function qa_comment_set_hidden($oldcomment, $hidden, $userid, $handle, $cookieid, $question, $parent)
/*
Set $oldcomment to hidden if $hidden is true, visible/normal if otherwise. All other parameters are as for qa_comment_set_status(...)
This function is included mainly for backwards compatibility.
*/
{
}
/**
* Set $oldcomment to hidden if $hidden is true, visible/normal if otherwise. All other parameters are as for qa_comment_set_status(...)
* This function is included mainly for backwards compatibility.
* @param $oldcomment
* @param $hidden
* @param $userid
* @param $handle
* @param $cookieid
* @param $question
* @param $parent
*/
function qa_comment_set_hidden($oldcomment, $hidden, $userid, $handle, $cookieid, $question, $parent)
{
qa_comment_set_status($oldcomment, $hidden ? QA_POST_STATUS_HIDDEN : QA_POST_STATUS_NORMAL, $userid, $handle, $cookieid, $question, $parent);
}
function qa_comment_set_status($oldcomment, $status, $userid, $handle, $cookieid, $question, $parent)
/*
Set the status (application level) of $oldcomment to $status, one of the QA_POST_STATUS_* constants above. Pass the
antecedent question's record in $question, details of the user doing this in $userid, $handle and $cookieid, and the
answer's database record in $answer if this is a comment on an answer, otherwise null. Handles indexing, user
points, cached counts and event reports. See qa-app-posts.php for a higher-level function which is easier to use.
*/
{
require_once QA_INCLUDE_DIR.'app/format.php';
}
/**
* Set the status (application level) of $oldcomment to $status, one of the QA_POST_STATUS_* constants above. Pass the
* antecedent question's record in $question, details of the user doing this in $userid, $handle and $cookieid, and the
* answer's database record in $answer if this is a comment on an answer, otherwise null. Handles indexing, user
* points, cached counts and event reports. See qa-app-posts.php for a higher-level function which is easier to use.
* @param $oldcomment
* @param $status
* @param $userid
* @param $handle
* @param $cookieid
* @param $question
* @param $parent
*/
function qa_comment_set_status($oldcomment, $status, $userid, $handle, $cookieid, $question, $parent)
{
require_once QA_INCLUDE_DIR . 'app/format.php';
if (!isset($parent))
$parent=$question; // for backwards compatibility with old answer parameter
$parent = $question; // for backwards compatibility with old answer parameter
$washidden=($oldcomment['type']=='C_HIDDEN');
$wasqueued=($oldcomment['type']=='C_QUEUED');
$wasrequeued=$wasqueued && isset($oldcomment['updated']);
$washidden = ($oldcomment['type'] == 'C_HIDDEN');
$wasqueued = ($oldcomment['type'] == 'C_QUEUED');
$wasrequeued = $wasqueued && isset($oldcomment['updated']);
qa_post_unindex($oldcomment['postid']);
$setupdated=false;
$event=null;
$setupdated = false;
$event = null;
if ($status==QA_POST_STATUS_QUEUED) {
$newtype='C_QUEUED';
if ($status == QA_POST_STATUS_QUEUED) {
$newtype = 'C_QUEUED';
if (!$wasqueued)
$event='c_requeue'; // same event whether it was hidden or shown before
$event = 'c_requeue'; // same event whether it was hidden or shown before
} elseif ($status==QA_POST_STATUS_HIDDEN) {
$newtype='C_HIDDEN';
} elseif ($status == QA_POST_STATUS_HIDDEN) {
$newtype = 'C_HIDDEN';
if (!$washidden) {
$event=$wasqueued ? 'c_reject' : 'c_hide';
$event = $wasqueued ? 'c_reject' : 'c_hide';
if (!$wasqueued)
$setupdated=true;
$setupdated = true;
}
} elseif ($status==QA_POST_STATUS_NORMAL) {
$newtype='C';
} elseif ($status == QA_POST_STATUS_NORMAL) {
$newtype = 'C';
if ($wasqueued)
$event='c_approve';
$event = 'c_approve';
elseif ($washidden) {
$event='c_reshow';
$setupdated=true;
$event = 'c_reshow';
$setupdated = true;
}
} else
qa_fatal_error('Unknown status in qa_comment_set_status(): '.$status);
qa_fatal_error('Unknown status in qa_comment_set_status(): ' . $status);
qa_db_post_set_type($oldcomment['postid'], $newtype, $setupdated ? $userid : null, $setupdated ? qa_remote_ip_address() : null, QA_UPDATE_VISIBLE);
if ( $wasqueued && ($status==QA_POST_STATUS_NORMAL) && qa_opt('moderate_update_time') ) { // ... for approval of a post, can set time to now instead
if ($wasqueued && ($status == QA_POST_STATUS_NORMAL) && qa_opt('moderate_update_time')) { // ... for approval of a post, can set time to now instead
if ($wasrequeued)
qa_db_post_set_updated($oldcomment['postid'], null);
else
......@@ -976,17 +1146,19 @@
qa_db_ccount_update();
qa_db_points_update_ifuser($oldcomment['userid'], array('cposts'));
if ($wasqueued || ($status==QA_POST_STATUS_QUEUED))
if ($wasqueued || $status == QA_POST_STATUS_QUEUED)
qa_db_queuedcount_update();
if ($oldcomment['flagcount'])
qa_db_flaggedcount_update();
if ( ($question['type']=='Q') && (($parent['type']=='Q') || ($parent['type']=='A')) && ($status==QA_POST_STATUS_NORMAL)) // only index if none of the things it depends on are hidden or queued
if ($question['type'] == 'Q' && ($parent['type'] == 'Q' || $parent['type'] == 'A') && $status == QA_POST_STATUS_NORMAL) {
// only index if none of the things it depends on are hidden or queued
qa_post_index($oldcomment['postid'], 'C', $question['postid'], $oldcomment['parentid'], null, $oldcomment['content'],
$oldcomment['format'], qa_viewer_text($oldcomment['content'], $oldcomment['format']), null, $oldcomment['categoryid']);
}
$eventparams=array(
$eventparams = array(
'postid' => $oldcomment['postid'],
'parentid' => $oldcomment['parentid'],
'parenttype' => $parent['basetype'],
......@@ -1000,21 +1172,23 @@
'name' => $oldcomment['name'],
);
if (isset($event))
if (isset($event)) {
qa_report_event($event, $userid, $handle, $cookieid, $eventparams + array(
'oldcomment' => $oldcomment,
));
}
if ($wasqueued && ($status==QA_POST_STATUS_NORMAL) && !$wasrequeued) {
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR.'util/string.php';
if ($wasqueued && $status == QA_POST_STATUS_NORMAL && !$wasrequeued) {
require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR . 'util/string.php';
$commentsfollows=qa_db_single_select(qa_db_full_child_posts_selectspec(null, $oldcomment['parentid']));
$thread=array();
$commentsfollows = qa_db_single_select(qa_db_full_child_posts_selectspec(null, $oldcomment['parentid']));
$thread = array();
foreach ($commentsfollows as $comment)
if (($comment['type']=='C') && ($comment['parentid']==$parent['postid']))
$thread[]=$comment;
foreach ($commentsfollows as $comment) {
if ($comment['type'] == 'C' && $comment['parentid'] == $parent['postid'])
$thread[] = $comment;
}
qa_report_event('c_post', $oldcomment['userid'], $oldcomment['handle'], $oldcomment['cookieid'], $eventparams + array(
'thread' => $thread,
......@@ -1023,21 +1197,27 @@
'delayed' => $oldcomment['created'],
));
}
}
function qa_comment_delete($oldcomment, $question, $parent, $userid, $handle, $cookieid)
/*
Permanently delete a comment in $oldcomment (application level) from the database. Pass the database question in $question
and the answer's database record in $answer if this is a comment on an answer, otherwise null. Pass details of the user
doing this in $userid, $handle and $cookieid. Handles unindexing, points, cached counts and event reports.
See qa-app-posts.php for a higher-level function which is easier to use.
*/
{
}
/**
* Permanently delete a comment in $oldcomment (application level) from the database. Pass the database question in $question
* and the answer's database record in $answer if this is a comment on an answer, otherwise null. Pass details of the user
* doing this in $userid, $handle and $cookieid. Handles unindexing, points, cached counts and event reports.
* See qa-app-posts.php for a higher-level function which is easier to use.
* @param $oldcomment
* @param $question
* @param $parent
* @param $userid
* @param $handle
* @param $cookieid
*/
function qa_comment_delete($oldcomment, $question, $parent, $userid, $handle, $cookieid)
{
if (!isset($parent))
$parent=$question; // for backwards compatibility with old answer parameter
$parent = $question; // for backwards compatibility with old answer parameter
if ($oldcomment['type']!='C_HIDDEN')
if ($oldcomment['type'] != 'C_HIDDEN')
qa_fatal_error('Tried to delete a non-hidden comment');
$params = array(
......@@ -1056,16 +1236,20 @@
qa_db_ccount_update();
qa_report_event('c_delete', $userid, $handle, $cookieid, $params);
}
}
function qa_comment_set_userid($oldcomment, $userid, $handle, $cookieid)
/*
Set the author (application level) of $oldcomment to $userid and also pass $handle and $cookieid
of user. Updates points and reports events as appropriate.
*/
{
require_once QA_INCLUDE_DIR.'db/votes.php';
/**
* Set the author (application level) of $oldcomment to $userid and also pass $handle and $cookieid
* of user. Updates points and reports events as appropriate.
* @param $oldcomment
* @param $userid
* @param $handle
* @param $cookieid
*/
function qa_comment_set_userid($oldcomment, $userid, $handle, $cookieid)
{
require_once QA_INCLUDE_DIR . 'db/votes.php';
$postid = $oldcomment['postid'];
......@@ -1081,8 +1265,4 @@
'parentid' => $oldcomment['parentid'],
'oldcomment' => $oldcomment,
));
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
}
......@@ -56,28 +56,28 @@
[but these are not entirely redundant since they can contain historical information no longer in ^posts]
*/
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../');
exit;
}
require_once QA_INCLUDE_DIR.'db/recalc.php';
require_once QA_INCLUDE_DIR.'db/post-create.php';
require_once QA_INCLUDE_DIR.'db/points.php';
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR.'db/admin.php';
require_once QA_INCLUDE_DIR.'db/users.php';
require_once QA_INCLUDE_DIR.'app/options.php';
require_once QA_INCLUDE_DIR.'app/post-create.php';
require_once QA_INCLUDE_DIR.'app/post-update.php';
function qa_recalc_perform_step(&$state)
/*
Advance the recalculation operation represented by $state by a single step.
$state can also be the name of a recalculation operation on its own.
*/
{
}
require_once QA_INCLUDE_DIR.'db/recalc.php';
require_once QA_INCLUDE_DIR.'db/post-create.php';
require_once QA_INCLUDE_DIR.'db/points.php';
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR.'db/admin.php';
require_once QA_INCLUDE_DIR.'db/users.php';
require_once QA_INCLUDE_DIR.'app/options.php';
require_once QA_INCLUDE_DIR.'app/post-create.php';
require_once QA_INCLUDE_DIR.'app/post-update.php';
/**
* Advance the recalculation operation represented by $state by a single step.
* $state can also be the name of a recalculation operation on its own.
*/
function qa_recalc_perform_step(&$state)
{
$continue=false;
@list($operation, $length, $next, $done)=explode("\t", $state);
......@@ -528,27 +528,27 @@
$state=$operation."\t".$length."\t".$next."\t".$done;
return $continue && ($done<$length);
}
}
function qa_recalc_transition(&$state, $operation)
/*
Change the $state to represent the beginning of a new $operation
*/
{
/**
* Change the $state to represent the beginning of a new $operation
*/
function qa_recalc_transition(&$state, $operation)
{
$length=qa_recalc_stage_length($operation);
$next=(QA_FINAL_EXTERNAL_USERS && ($operation=='dorecalcpoints_recalc')) ? '' : 0;
$done=0;
$state=$operation."\t".$length."\t".$next."\t".$done;
}
}
function qa_recalc_stage_length($operation)
/*
Return how many steps there will be in recalculation $operation
*/
{
/**
* Return how many steps there will be in recalculation $operation
*/
function qa_recalc_stage_length($operation)
{
switch ($operation) {
case 'doreindexcontent_pagereindex':
$length=qa_db_count_pages();
......@@ -607,10 +607,10 @@
}
return $length;
}
}
/**
/**
* Return the translated language ID string replacing the progress and total in it.
* @access private
* @param string $langId Language string ID that contains 2 placeholders (^1 and ^2)
......@@ -620,20 +620,20 @@
* @return string Returns the language string ID with their placeholders replaced with
* the formatted progress and total numbers
*/
function qa_recalc_progress_lang($langId, $progress, $total)
{
function qa_recalc_progress_lang($langId, $progress, $total)
{
return strtr(qa_lang($langId), array(
'^1' => qa_format_number($progress),
'^2' => qa_format_number($total)
));
}
}
function qa_recalc_get_message($state)
/*
Return a string which gives a user-viewable version of $state
*/
{
/**
* Return a string which gives a user-viewable version of $state
*/
function qa_recalc_get_message($state)
{
require_once QA_INCLUDE_DIR . 'app/format.php';
@list($operation, $length, $next, $done) = explode("\t", $state);
......@@ -745,9 +745,4 @@
}
return $message;
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
}
......@@ -20,58 +20,56 @@
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
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../');
exit;
}
}
define('QA_USER_LEVEL_BASIC', 0);
define('QA_USER_LEVEL_APPROVED', 10);
define('QA_USER_LEVEL_EXPERT', 20);
define('QA_USER_LEVEL_EDITOR', 50);
define('QA_USER_LEVEL_MODERATOR', 80);
define('QA_USER_LEVEL_ADMIN', 100);
define('QA_USER_LEVEL_SUPER', 120);
define('QA_USER_LEVEL_BASIC', 0);
define('QA_USER_LEVEL_APPROVED', 10);
define('QA_USER_LEVEL_EXPERT', 20);
define('QA_USER_LEVEL_EDITOR', 50);
define('QA_USER_LEVEL_MODERATOR', 80);
define('QA_USER_LEVEL_ADMIN', 100);
define('QA_USER_LEVEL_SUPER', 120);
define('QA_USER_FLAGS_EMAIL_CONFIRMED', 1);
define('QA_USER_FLAGS_USER_BLOCKED', 2);
define('QA_USER_FLAGS_SHOW_AVATAR', 4);
define('QA_USER_FLAGS_SHOW_GRAVATAR', 8);
define('QA_USER_FLAGS_NO_MESSAGES', 16);
define('QA_USER_FLAGS_NO_MAILINGS', 32);
define('QA_USER_FLAGS_WELCOME_NOTICE', 64);
define('QA_USER_FLAGS_MUST_CONFIRM', 128);
define('QA_USER_FLAGS_NO_WALL_POSTS', 256);
define('QA_USER_FLAGS_MUST_APPROVE', 512);
define('QA_USER_FLAGS_EMAIL_CONFIRMED', 1);
define('QA_USER_FLAGS_USER_BLOCKED', 2);
define('QA_USER_FLAGS_SHOW_AVATAR', 4);
define('QA_USER_FLAGS_SHOW_GRAVATAR', 8);
define('QA_USER_FLAGS_NO_MESSAGES', 16);
define('QA_USER_FLAGS_NO_MAILINGS', 32);
define('QA_USER_FLAGS_WELCOME_NOTICE', 64);
define('QA_USER_FLAGS_MUST_CONFIRM', 128);
define('QA_USER_FLAGS_NO_WALL_POSTS', 256);
define('QA_USER_FLAGS_MUST_APPROVE', 512);
define('QA_FIELD_FLAGS_MULTI_LINE', 1);
define('QA_FIELD_FLAGS_LINK_URL', 2);
define('QA_FIELD_FLAGS_ON_REGISTER', 4);
define('QA_FIELD_FLAGS_MULTI_LINE', 1);
define('QA_FIELD_FLAGS_LINK_URL', 2);
define('QA_FIELD_FLAGS_ON_REGISTER', 4);
@define('QA_FORM_EXPIRY_SECS', 86400); // how many seconds a form is valid for submission
@define('QA_FORM_KEY_LENGTH', 32);
@define('QA_FORM_EXPIRY_SECS', 86400); // how many seconds a form is valid for submission
@define('QA_FORM_KEY_LENGTH', 32);
if (QA_FINAL_EXTERNAL_USERS) {
if (QA_FINAL_EXTERNAL_USERS) {
// If we're using single sign-on integration (WordPress or otherwise), load PHP file for that
if (defined('QA_FINAL_WORDPRESS_INTEGRATE_PATH')) {
require_once QA_INCLUDE_DIR.'util/external-users-wp.php';
}
elseif (defined('QA_FINAL_JOOMLA_INTEGRATE_PATH')) {
require_once QA_INCLUDE_DIR.'util/external-users-joomla.php';
}
else {
require_once QA_EXTERNAL_DIR.'qa-external-users.php';
require_once QA_INCLUDE_DIR . 'util/external-users-wp.php';
} elseif (defined('QA_FINAL_JOOMLA_INTEGRATE_PATH')) {
require_once QA_INCLUDE_DIR . 'util/external-users-joomla.php';
} else {
require_once QA_EXTERNAL_DIR . 'qa-external-users.php';
}
// Access functions for user information
function qa_get_logged_in_user_cache()
/*
Return array of information about the currently logged in user, cache to ensure only one call to external code
/**
* Return array of information about the currently logged in user, cache to ensure only one call to external code
*/
function qa_get_logged_in_user_cache()
{
global $qa_cached_logged_in_user;
......@@ -81,8 +79,7 @@
if (isset($user)) {
$user['flags'] = isset($user['blocked']) ? QA_USER_FLAGS_USER_BLOCKED : 0;
$qa_cached_logged_in_user = $user;
}
else
} else
$qa_cached_logged_in_user = false;
}
......@@ -90,47 +87,53 @@
}
function qa_get_logged_in_user_field($field)
/*
Return $field of the currently logged in user, or null if not available
/**
* Return $field of the currently logged in user, or null if not available
* @param $field
* @return null
*/
function qa_get_logged_in_user_field($field)
{
$user=qa_get_logged_in_user_cache();
$user = qa_get_logged_in_user_cache();
return isset($user[$field]) ? $user[$field] : null;
}
function qa_get_logged_in_userid()
/*
Return the userid of the currently logged in user, or null if none
/**
* Return the userid of the currently logged in user, or null if none
*/
function qa_get_logged_in_userid()
{
return qa_get_logged_in_user_field('userid');
}
function qa_get_logged_in_points()
/*
Return the number of points of the currently logged in user, or null if none is logged in
/**
* Return the number of points of the currently logged in user, or null if none is logged in
*/
function qa_get_logged_in_points()
{
global $qa_cached_logged_in_points;
if (!isset($qa_cached_logged_in_points)) {
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
$qa_cached_logged_in_points=qa_db_select_with_pending(qa_db_user_points_selectspec(qa_get_logged_in_userid(), true));
$qa_cached_logged_in_points = qa_db_select_with_pending(qa_db_user_points_selectspec(qa_get_logged_in_userid(), true));
}
return $qa_cached_logged_in_points['points'];
}
function qa_get_external_avatar_html($userid, $size, $padding=false)
/*
Return HTML to display for the avatar of $userid, constrained to $size pixels, with optional $padding to that size
/**
* Return HTML to display for the avatar of $userid, constrained to $size pixels, with optional $padding to that size
* @param $userid
* @param $size
* @param bool $padding
* @return mixed|null|string
*/
function qa_get_external_avatar_html($userid, $size, $padding = false)
{
if (function_exists('qa_avatar_html_from_userid'))
return qa_avatar_html_from_userid($userid, $size, $padding);
......@@ -139,12 +142,12 @@
}
} else {
} else {
function qa_start_session()
/*
Open a PHP session if one isn't opened already
/**
* Open a PHP session if one isn't opened already
*/
function qa_start_session()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
......@@ -157,52 +160,58 @@
}
function qa_session_var_suffix()
/*
Returns a suffix to be used for names of session variables to prevent them being shared between multiple Q2A sites on the same server
/**
* Returns a suffix to be used for names of session variables to prevent them being shared between multiple Q2A sites on the same server
*/
function qa_session_var_suffix()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
global $qa_session_suffix;
if (!$qa_session_suffix) {
$prefix=defined('QA_MYSQL_USERS_PREFIX') ? QA_MYSQL_USERS_PREFIX : QA_MYSQL_TABLE_PREFIX;
$qa_session_suffix = md5(QA_FINAL_MYSQL_HOSTNAME.'/'.QA_FINAL_MYSQL_USERNAME.'/'.QA_FINAL_MYSQL_PASSWORD.'/'.QA_FINAL_MYSQL_DATABASE.'/'.$prefix);
$prefix = defined('QA_MYSQL_USERS_PREFIX') ? QA_MYSQL_USERS_PREFIX : QA_MYSQL_TABLE_PREFIX;
$qa_session_suffix = md5(QA_FINAL_MYSQL_HOSTNAME . '/' . QA_FINAL_MYSQL_USERNAME . '/' . QA_FINAL_MYSQL_PASSWORD . '/' . QA_FINAL_MYSQL_DATABASE . '/' . $prefix);
}
return $qa_session_suffix;
}
function qa_session_verify_code($userid)
/*
Returns a verification code used to ensure that a user session can't be generated by another PHP script running on the same server
/**
* Returns a verification code used to ensure that a user session can't be generated by another PHP script running on the same server
* @param $userid
* @return mixed|string
*/
function qa_session_verify_code($userid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return sha1($userid.'/'.QA_MYSQL_TABLE_PREFIX.'/'.QA_FINAL_MYSQL_DATABASE.'/'.QA_FINAL_MYSQL_PASSWORD.'/'.QA_FINAL_MYSQL_USERNAME.'/'.QA_FINAL_MYSQL_HOSTNAME);
return sha1($userid . '/' . QA_MYSQL_TABLE_PREFIX . '/' . QA_FINAL_MYSQL_DATABASE . '/' . QA_FINAL_MYSQL_PASSWORD . '/' . QA_FINAL_MYSQL_USERNAME . '/' . QA_FINAL_MYSQL_HOSTNAME);
}
function qa_set_session_cookie($handle, $sessioncode, $remember)
/*
Set cookie in browser for username $handle with $sessioncode (in database).
Pass true if user checked 'Remember me' (either now or previously, as learned from cookie).
/**
* Set cookie in browser for username $handle with $sessioncode (in database).
* Pass true if user checked 'Remember me' (either now or previously, as learned from cookie).
* @param $handle
* @param $sessioncode
* @param $remember
* @return mixed
*/
function qa_set_session_cookie($handle, $sessioncode, $remember)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
// if $remember is true, store in browser for a month, otherwise store only until browser is closed
setcookie('qa_session', $handle.'/'.$sessioncode.'/'.($remember ? 1 : 0), $remember ? (time()+2592000) : 0, '/', QA_COOKIE_DOMAIN, (bool)ini_get('session.cookie_secure'), true);
setcookie('qa_session', $handle . '/' . $sessioncode . '/' . ($remember ? 1 : 0), $remember ? (time() + 2592000) : 0, '/', QA_COOKIE_DOMAIN, (bool)ini_get('session.cookie_secure'), true);
}
function qa_clear_session_cookie()
/*
Remove session cookie from browser
/**
* Remove session cookie from browser
*/
function qa_clear_session_cookie()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
......@@ -210,46 +219,54 @@
}
function qa_set_session_user($userid, $source)
/*
Set the session variables to indicate that $userid is logged in from $source
/**
* Set the session variables to indicate that $userid is logged in from $source
* @param $userid
* @param $source
* @return mixed
*/
function qa_set_session_user($userid, $source)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$suffix=qa_session_var_suffix();
$suffix = qa_session_var_suffix();
$_SESSION['qa_session_userid_'.$suffix]=$userid;
$_SESSION['qa_session_source_'.$suffix]=$source;
$_SESSION['qa_session_verify_'.$suffix]=qa_session_verify_code($userid);
$_SESSION['qa_session_userid_' . $suffix] = $userid;
$_SESSION['qa_session_source_' . $suffix] = $source;
// prevents one account on a shared server being able to create a log in a user to Q2A on another account on same server
$_SESSION['qa_session_verify_' . $suffix] = qa_session_verify_code($userid);
}
function qa_clear_session_user()
/*
Clear the session variables indicating that a user is logged in
/**
* Clear the session variables indicating that a user is logged in
*/
function qa_clear_session_user()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$suffix=qa_session_var_suffix();
$suffix = qa_session_var_suffix();
unset($_SESSION['qa_session_userid_'.$suffix]);
unset($_SESSION['qa_session_source_'.$suffix]);
unset($_SESSION['qa_session_verify_'.$suffix]);
unset($_SESSION['qa_session_userid_' . $suffix]);
unset($_SESSION['qa_session_source_' . $suffix]);
unset($_SESSION['qa_session_verify_' . $suffix]);
}
function qa_set_logged_in_user($userid, $handle='', $remember=false, $source=null)
/*
Call for successful log in by $userid and $handle or successful log out with $userid=null.
$remember states if 'Remember me' was checked in the login form.
/**
* Call for successful log in by $userid and $handle or successful log out with $userid=null.
* $remember states if 'Remember me' was checked in the login form.
* @param $userid
* @param string $handle
* @param bool $remember
* @param $source
* @return mixed
*/
function qa_set_logged_in_user($userid, $handle = '', $remember = false, $source = null)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'app/cookies.php';
require_once QA_INCLUDE_DIR . 'app/cookies.php';
qa_start_session();
......@@ -260,19 +277,19 @@
// Logging in from a second browser will make the previous browser's 'Remember me' no longer
// work - I'm not sure if this is the right behavior - could see it either way.
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
$userinfo=qa_db_single_select(qa_db_user_account_selectspec($userid, true));
$userinfo = qa_db_single_select(qa_db_user_account_selectspec($userid, true));
// if we have logged in before, and are logging in the same way as before, we don't need to change the sessioncode/source
// this means it will be possible to automatically log in (via cookies) to the same account from more than one browser
if (empty($userinfo['sessioncode']) || ($source!==$userinfo['sessionsource'])) {
$sessioncode=qa_db_user_rand_sessioncode();
if (empty($userinfo['sessioncode']) || ($source !== $userinfo['sessionsource'])) {
$sessioncode = qa_db_user_rand_sessioncode();
qa_db_user_set($userid, 'sessioncode', $sessioncode);
qa_db_user_set($userid, 'sessionsource', $source);
} else
$sessioncode=$userinfo['sessioncode'];
$sessioncode = $userinfo['sessioncode'];
qa_db_user_logged_in($userid, qa_remote_ip_address());
qa_set_session_cookie($handle, $sessioncode, $remember);
......@@ -280,8 +297,8 @@
qa_report_event('u_login', $userid, $userinfo['handle'], qa_cookie_get());
} else {
$olduserid=qa_get_logged_in_userid();
$oldhandle=qa_get_logged_in_handle();
$olduserid = qa_get_logged_in_userid();
$oldhandle = qa_get_logged_in_handle();
qa_clear_session_cookie();
qa_clear_session_user();
......@@ -291,41 +308,45 @@
}
function qa_log_in_external_user($source, $identifier, $fields)
/*
Call to log in a user based on an external identity provider $source with external $identifier
A new user is created based on $fields if it's a new combination of $source and $identifier
/**
* Call to log in a user based on an external identity provider $source with external $identifier
* A new user is created based on $fields if it's a new combination of $source and $identifier
* @param $source
* @param $identifier
* @param $fields
* @return mixed
*/
function qa_log_in_external_user($source, $identifier, $fields)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/users.php';
require_once QA_INCLUDE_DIR . 'db/users.php';
$users=qa_db_user_login_find($source, $identifier);
$countusers=count($users);
$users = qa_db_user_login_find($source, $identifier);
$countusers = count($users);
if ($countusers>1)
if ($countusers > 1)
qa_fatal_error('External login mapped to more than one user'); // should never happen
if ($countusers) // user exists so log them in
qa_set_logged_in_user($users[0]['userid'], $users[0]['handle'], false, $source);
else { // create and log in user
require_once QA_INCLUDE_DIR.'app/users-edit.php';
require_once QA_INCLUDE_DIR . 'app/users-edit.php';
qa_db_user_login_sync(true);
$users=qa_db_user_login_find($source, $identifier); // check again after table is locked
$users = qa_db_user_login_find($source, $identifier); // check again after table is locked
if (count($users)==1) {
if (count($users) == 1) {
qa_db_user_login_sync(false);
qa_set_logged_in_user($users[0]['userid'], $users[0]['handle'], false, $source);
} else {
$handle=qa_handle_make_valid(@$fields['handle']);
$handle = qa_handle_make_valid(@$fields['handle']);
if (strlen(@$fields['email'])) { // remove email address if it will cause a duplicate
$emailusers=qa_db_user_find_by_email($fields['email']);
$emailusers = qa_db_user_find_by_email($fields['email']);
if (count($emailusers)) {
qa_redirect('login', array('e' => $fields['email'], 'ee' => '1'));
unset($fields['email']);
......@@ -333,17 +354,18 @@
}
}
$userid=qa_create_new_user((string)@$fields['email'], null /* no password */, $handle,
$userid = qa_create_new_user((string)@$fields['email'], null /* no password */, $handle,
isset($fields['level']) ? $fields['level'] : QA_USER_LEVEL_BASIC, @$fields['confirmed']);
qa_db_user_login_add($userid, $source, $identifier);
qa_db_user_login_sync(false);
$profilefields=array('name', 'location', 'website', 'about');
$profilefields = array('name', 'location', 'website', 'about');
foreach ($profilefields as $fieldname)
foreach ($profilefields as $fieldname) {
if (strlen(@$fields[$fieldname]))
qa_db_user_profile_set($userid, $fieldname, $fields[$fieldname]);
}
if (strlen(@$fields['avatar']))
qa_set_user_avatar($userid, $fields['avatar']);
......@@ -354,39 +376,39 @@
}
function qa_get_logged_in_userid()
/*
Return the userid of the currently logged in user, or null if none logged in
/**
* Return the userid of the currently logged in user, or null if none logged in
*/
function qa_get_logged_in_userid()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
global $qa_logged_in_userid_checked;
$suffix=qa_session_var_suffix();
$suffix = qa_session_var_suffix();
if (!$qa_logged_in_userid_checked) { // only check once
qa_start_session(); // this will load logged in userid from the native PHP session, but that's not enough
$sessionuserid=@$_SESSION['qa_session_userid_'.$suffix];
$sessionuserid = @$_SESSION['qa_session_userid_' . $suffix];
if (isset($sessionuserid)) // check verify code matches
if (!hash_equals(qa_session_verify_code($sessionuserid), @$_SESSION['qa_session_verify_'.$suffix]))
if (!hash_equals(qa_session_verify_code($sessionuserid), @$_SESSION['qa_session_verify_' . $suffix]))
qa_clear_session_user();
if (!empty($_COOKIE['qa_session'])) {
@list($handle, $sessioncode, $remember)=explode('/', $_COOKIE['qa_session']);
@list($handle, $sessioncode, $remember) = explode('/', $_COOKIE['qa_session']);
if ($remember)
qa_set_session_cookie($handle, $sessioncode, $remember); // extend 'remember me' cookies each time
$sessioncode=trim($sessioncode); // trim to prevent passing in blank values to match uninitiated DB rows
$sessioncode = trim($sessioncode); // trim to prevent passing in blank values to match uninitiated DB rows
// Try to recover session from the database if PHP session has timed out
if ( (!isset($_SESSION['qa_session_userid_'.$suffix])) && (!empty($handle)) && (!empty($sessioncode)) ) {
require_once QA_INCLUDE_DIR.'db/selects.php';
if ((!isset($_SESSION['qa_session_userid_' . $suffix])) && (!empty($handle)) && (!empty($sessioncode))) {
require_once QA_INCLUDE_DIR . 'db/selects.php';
$userinfo=qa_db_single_select(qa_db_user_account_selectspec($handle, false)); // don't get any pending
$userinfo = qa_db_single_select(qa_db_user_account_selectspec($handle, false)); // don't get any pending
if (strtolower(trim($userinfo['sessioncode'])) == strtolower($sessioncode))
qa_set_session_user($userinfo['userid'], $userinfo['sessionsource']);
......@@ -395,25 +417,25 @@
}
}
$qa_logged_in_userid_checked=true;
$qa_logged_in_userid_checked = true;
}
return @$_SESSION['qa_session_userid_'.$suffix];
return @$_SESSION['qa_session_userid_' . $suffix];
}
function qa_get_logged_in_source()
/*
Get the source of the currently logged in user, from call to qa_log_in_external_user() or null if logged in normally
/**
* Get the source of the currently logged in user, from call to qa_log_in_external_user() or null if logged in normally
*/
function qa_get_logged_in_source()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$userid=qa_get_logged_in_userid();
$suffix=qa_session_var_suffix();
$userid = qa_get_logged_in_userid();
$suffix = qa_session_var_suffix();
if (isset($userid))
return @$_SESSION['qa_session_source_'.$suffix];
return @$_SESSION['qa_session_source_' . $suffix];
}
......@@ -428,7 +450,7 @@
$userid = qa_get_logged_in_userid();
if (isset($userid)) {
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
$qa_cached_logged_in_user = qa_db_get_pending_result('loggedinuser', qa_db_user_account_selectspec($userid, true));
if (!isset($qa_cached_logged_in_user)) {
......@@ -445,6 +467,8 @@
/**
* Return $field of the currently logged in user
* @param $field
* @return mixed|null
*/
function qa_get_logged_in_user_field($field)
{
......@@ -456,10 +480,10 @@
}
function qa_get_logged_in_points()
/*
Return the number of points of the currently logged in user, or null if none is logged in
/**
* Return the number of points of the currently logged in user, or null if none is logged in
*/
function qa_get_logged_in_points()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
......@@ -467,10 +491,10 @@
}
function qa_get_mysql_user_column_type()
/*
Return column type to use for users (if not using single sign-on integration)
/**
* Return column type to use for users (if not using single sign-on integration)
*/
function qa_get_mysql_user_column_type()
{
return 'INT UNSIGNED';
}
......@@ -515,20 +539,20 @@
* @param bool $favorited Show the user as favorited.
* @return string The user HTML.
*/
function qa_get_one_user_html($handle, $microdata=false, $favorited=false)
function qa_get_one_user_html($handle, $microdata = false, $favorited = false)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if (!strlen($handle))
return '';
$url = qa_path_html('user/'.$handle);
$url = qa_path_html('user/' . $handle);
$favclass = $favorited ? ' qa-user-favorited' : '';
$mfAttr = $microdata ? ' itemprop="name"' : '';
$mfPrefix = $microdata ? '<span itemprop="author" itemscope itemtype="http://schema.org/Person">' : '';
$mfSuffix = $microdata ? '</span>' : '';
return $mfPrefix . '<a href="'.$url.'" class="qa-user-link'.$favclass.'"'.$mfAttr.'>'.qa_html($handle).'</a>' . $mfSuffix;
return $mfPrefix . '<a href="' . $url . '" class="qa-user-link' . $favclass . '"' . $mfAttr . '>' . qa_html($handle) . '</a>' . $mfSuffix;
}
......@@ -543,7 +567,6 @@
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$link = 'https://www.gravatar.com/avatar/%s';
$params = array(md5(strtolower(trim($email))));
......@@ -657,60 +680,70 @@
}
function qa_get_user_email($userid)
/*
Return email address for user $userid (if not using single sign-on integration)
/**
* Return email address for user $userid (if not using single sign-on integration)
* @param $userid
* @return
*/
function qa_get_user_email($userid)
{
$userinfo=qa_db_select_with_pending(qa_db_user_account_selectspec($userid, true));
$userinfo = qa_db_select_with_pending(qa_db_user_account_selectspec($userid, true));
return $userinfo['email'];
}
function qa_user_report_action($userid, $action)
/*
Called after a database write $action performed by a user $userid
/**
* Called after a database write $action performed by a user $userid
* @param $userid
* @param $action
* @return mixed
*/
function qa_user_report_action($userid, $action)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/users.php';
require_once QA_INCLUDE_DIR . 'db/users.php';
qa_db_user_written($userid, qa_remote_ip_address());
}
function qa_user_level_string($level)
/*
Return textual representation of the user $level
/**
* Return textual representation of the user $level
* @param $level
* @return mixed|string
*/
function qa_user_level_string($level)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if ($level>=QA_USER_LEVEL_SUPER)
$string='users/level_super';
elseif ($level>=QA_USER_LEVEL_ADMIN)
$string='users/level_admin';
elseif ($level>=QA_USER_LEVEL_MODERATOR)
$string='users/level_moderator';
elseif ($level>=QA_USER_LEVEL_EDITOR)
$string='users/level_editor';
elseif ($level>=QA_USER_LEVEL_EXPERT)
$string='users/level_expert';
elseif ($level>=QA_USER_LEVEL_APPROVED)
$string='users/approved_user';
if ($level >= QA_USER_LEVEL_SUPER)
$string = 'users/level_super';
elseif ($level >= QA_USER_LEVEL_ADMIN)
$string = 'users/level_admin';
elseif ($level >= QA_USER_LEVEL_MODERATOR)
$string = 'users/level_moderator';
elseif ($level >= QA_USER_LEVEL_EDITOR)
$string = 'users/level_editor';
elseif ($level >= QA_USER_LEVEL_EXPERT)
$string = 'users/level_expert';
elseif ($level >= QA_USER_LEVEL_APPROVED)
$string = 'users/approved_user';
else
$string='users/registered_user';
$string = 'users/registered_user';
return qa_lang($string);
}
function qa_get_login_links($rooturl, $tourl)
/*
Return an array of links to login, register, email confirm and logout pages (if not using single sign-on integration)
/**
* Return an array of links to login, register, email confirm and logout pages (if not using single sign-on integration)
* @param $rooturl
* @param $tourl
* @return array
*/
function qa_get_login_links($rooturl, $tourl)
{
return array(
'login' => qa_path('login', isset($tourl) ? array('to' => $tourl) : null, $rooturl),
......@@ -720,235 +753,260 @@
);
}
} // end of: if (QA_FINAL_EXTERNAL_USERS) { ... } else { ... }
} // end of: if (QA_FINAL_EXTERNAL_USERS) { ... } else { ... }
function qa_is_logged_in()
/*
Return whether someone is logged in at the moment
*/
{
$userid=qa_get_logged_in_userid();
/**
* Return whether someone is logged in at the moment
*/
function qa_is_logged_in()
{
$userid = qa_get_logged_in_userid();
return isset($userid);
}
}
function qa_get_logged_in_handle()
/*
Return displayable handle/username of currently logged in user, or null if none
*/
{
/**
* Return displayable handle/username of currently logged in user, or null if none
*/
function qa_get_logged_in_handle()
{
return qa_get_logged_in_user_field(QA_FINAL_EXTERNAL_USERS ? 'publicusername' : 'handle');
}
}
function qa_get_logged_in_email()
/*
Return email of currently logged in user, or null if none
*/
{
/**
* Return email of currently logged in user, or null if none
*/
function qa_get_logged_in_email()
{
return qa_get_logged_in_user_field('email');
}
}
function qa_get_logged_in_level()
/*
Return level of currently logged in user, or null if none
*/
{
/**
* Return level of currently logged in user, or null if none
*/
function qa_get_logged_in_level()
{
return qa_get_logged_in_user_field('level');
}
}
function qa_get_logged_in_flags()
/*
Return flags (see QA_USER_FLAGS_*) of currently logged in user, or null if none
*/
{
/**
* Return flags (see QA_USER_FLAGS_*) of currently logged in user, or null if none
*/
function qa_get_logged_in_flags()
{
if (QA_FINAL_EXTERNAL_USERS)
return qa_get_logged_in_user_field('blocked') ? QA_USER_FLAGS_USER_BLOCKED : 0;
else
return qa_get_logged_in_user_field('flags');
}
}
function qa_get_logged_in_levels()
/*
Return an array of all the specific (e.g. per category) level privileges for the logged in user, retrieving from the database if necessary
*/
{
require_once QA_INCLUDE_DIR.'db/selects.php';
/**
* Return an array of all the specific (e.g. per category) level privileges for the logged in user, retrieving from the database if necessary
*/
function qa_get_logged_in_levels()
{
require_once QA_INCLUDE_DIR . 'db/selects.php';
return qa_db_get_pending_result('userlevels', qa_db_user_levels_selectspec(qa_get_logged_in_userid(), true));
}
}
function qa_userids_to_handles($userids)
/*
Return an array mapping each userid in $userids to that user's handle (public username), or to null if not found
*/
{
/**
* Return an array mapping each userid in $userids to that user's handle (public username), or to null if not found
* @param $userids
* @return array
*/
function qa_userids_to_handles($userids)
{
if (QA_FINAL_EXTERNAL_USERS)
$rawuseridhandles=qa_get_public_from_userids($userids);
$rawuseridhandles = qa_get_public_from_userids($userids);
else {
require_once QA_INCLUDE_DIR.'db/users.php';
$rawuseridhandles=qa_db_user_get_userid_handles($userids);
require_once QA_INCLUDE_DIR . 'db/users.php';
$rawuseridhandles = qa_db_user_get_userid_handles($userids);
}
$gotuseridhandles=array();
$gotuseridhandles = array();
foreach ($userids as $userid)
$gotuseridhandles[$userid]=@$rawuseridhandles[$userid];
$gotuseridhandles[$userid] = @$rawuseridhandles[$userid];
return $gotuseridhandles;
}
}
function qa_userid_to_handle($userid)
/*
Return an string mapping the received userid to that user's handle (public username), or to null if not found
*/
{
$handles=qa_userids_to_handles(array($userid));
/**
* Return an string mapping the received userid to that user's handle (public username), or to null if not found
* @param $userid
* @return mixed|null
*/
function qa_userid_to_handle($userid)
{
$handles = qa_userids_to_handles(array($userid));
return empty($handles) ? null : $handles[$userid];
}
}
function qa_handles_to_userids($handles, $exactonly=false)
/*
Return an array mapping each handle in $handles the user's userid, or null if not found. If $exactonly is true then
$handles must have the correct case and accents. Otherwise, handles are case- and accent-insensitive, and the keys
of the returned array will match the $handles provided, not necessary those in the DB.
*/
{
require_once QA_INCLUDE_DIR.'util/string.php';
/**
* Return an array mapping each handle in $handles the user's userid, or null if not found. If $exactonly is true then
* $handles must have the correct case and accents. Otherwise, handles are case- and accent-insensitive, and the keys
* of the returned array will match the $handles provided, not necessary those in the DB.
* @param $handles
* @param bool $exactonly
* @return array
*/
function qa_handles_to_userids($handles, $exactonly = false)
{
require_once QA_INCLUDE_DIR . 'util/string.php';
if (QA_FINAL_EXTERNAL_USERS)
$rawhandleuserids=qa_get_userids_from_public($handles);
$rawhandleuserids = qa_get_userids_from_public($handles);
else {
require_once QA_INCLUDE_DIR.'db/users.php';
$rawhandleuserids=qa_db_user_get_handle_userids($handles);
require_once QA_INCLUDE_DIR . 'db/users.php';
$rawhandleuserids = qa_db_user_get_handle_userids($handles);
}
$gothandleuserids=array();
$gothandleuserids = array();
if ($exactonly) { // only take the exact matches
foreach ($handles as $handle)
$gothandleuserids[$handle]=@$rawhandleuserids[$handle];
$gothandleuserids[$handle] = @$rawhandleuserids[$handle];
} else { // normalize to lowercase without accents, and then find matches
$normhandleuserids=array();
$normhandleuserids = array();
foreach ($rawhandleuserids as $handle => $userid)
$normhandleuserids[qa_string_remove_accents(qa_strtolower($handle))]=$userid;
$normhandleuserids[qa_string_remove_accents(qa_strtolower($handle))] = $userid;
foreach ($handles as $handle)
$gothandleuserids[$handle]=@$normhandleuserids[qa_string_remove_accents(qa_strtolower($handle))];
$gothandleuserids[$handle] = @$normhandleuserids[qa_string_remove_accents(qa_strtolower($handle))];
}
return $gothandleuserids;
}
}
function qa_handle_to_userid($handle)
/*
Return the userid corresponding to $handle (not case- or accent-sensitive)
*/
{
/**
* Return the userid corresponding to $handle (not case- or accent-sensitive)
* @param $handle
* @return mixed|null
*/
function qa_handle_to_userid($handle)
{
if (QA_FINAL_EXTERNAL_USERS)
$handleuserids=qa_get_userids_from_public(array($handle));
$handleuserids = qa_get_userids_from_public(array($handle));
else {
require_once QA_INCLUDE_DIR.'db/users.php';
$handleuserids=qa_db_user_get_handle_userids(array($handle));
require_once QA_INCLUDE_DIR . 'db/users.php';
$handleuserids = qa_db_user_get_handle_userids(array($handle));
}
if (count($handleuserids)==1)
if (count($handleuserids) == 1)
return reset($handleuserids); // don't use $handleuserids[$handle] since capitalization might be different
return null;
}
}
function qa_user_level_for_categories($categoryids)
/*
Return the level of the logged in user for a post with $categoryids (expressing the full hierarchy to the final category)
*/
{
/**
* Return the level of the logged in user for a post with $categoryids (expressing the full hierarchy to the final category)
* @param $categoryids
* @return mixed|null
*/
function qa_user_level_for_categories($categoryids)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'app/updates.php';
require_once QA_INCLUDE_DIR . 'app/updates.php';
$level=qa_get_logged_in_level();
$level = qa_get_logged_in_level();
if (count($categoryids)) {
$userlevels=qa_get_logged_in_levels();
$userlevels = qa_get_logged_in_levels();
$categorylevels=array(); // create a map
foreach ($userlevels as $userlevel)
if ($userlevel['entitytype']==QA_ENTITY_CATEGORY)
$categorylevels[$userlevel['entityid']]=$userlevel['level'];
$categorylevels = array(); // create a map
foreach ($userlevels as $userlevel) {
if ($userlevel['entitytype'] == QA_ENTITY_CATEGORY)
$categorylevels[$userlevel['entityid']] = $userlevel['level'];
}
foreach ($categoryids as $categoryid)
$level=max($level, @$categorylevels[$categoryid]);
foreach ($categoryids as $categoryid) {
$level = max($level, @$categorylevels[$categoryid]);
}
}
return $level;
}
}
function qa_user_level_for_post($post)
/*
Return the level of the logged in user for $post, as retrieved from the database
*/
{
/**
* Return the level of the logged in user for $post, as retrieved from the database
* @param $post
* @return mixed|null
*/
function qa_user_level_for_post($post)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if (strlen(@$post['categoryids']))
return qa_user_level_for_categories(explode(',', $post['categoryids']));
return null;
}
}
function qa_user_level_maximum()
/*
Return the maximum possible level of the logged in user in any context (i.e. for any category)
*/
{
/**
* Return the maximum possible level of the logged in user in any context (i.e. for any category)
*/
function qa_user_level_maximum()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$level=qa_get_logged_in_level();
$level = qa_get_logged_in_level();
$userlevels=qa_get_logged_in_levels();
foreach ($userlevels as $userlevel)
$level=max($level, $userlevel['level']);
$userlevels = qa_get_logged_in_levels();
foreach ($userlevels as $userlevel) {
$level = max($level, $userlevel['level']);
}
return $level;
}
}
function qa_user_post_permit_error($permitoption, $post, $limitaction=null, $checkblocks=true)
/*
Check whether the logged in user has permission to perform $permitoption on post $post (from the database)
Other parameters and the return value are as for qa_user_permit_error(...)
*/
{
/**
* Check whether the logged in user has permission to perform $permitoption on post $post (from the database)
* Other parameters and the return value are as for qa_user_permit_error(...)
* @param $permitoption
* @param $post
* @param $limitaction
* @param bool $checkblocks
* @return bool|string
*/
function qa_user_post_permit_error($permitoption, $post, $limitaction = null, $checkblocks = true)
{
return qa_user_permit_error($permitoption, $limitaction, qa_user_level_for_post($post), $checkblocks);
}
}
function qa_user_maximum_permit_error($permitoption, $limitaction=null, $checkblocks=true)
/*
Check whether the logged in user would have permittion to perform $permitoption in any context (i.e. for any category)
Other parameters and the return value are as for qa_user_permit_error(...)
*/
{
/**
* Check whether the logged in user would have permittion to perform $permitoption in any context (i.e. for any category)
* Other parameters and the return value are as for qa_user_permit_error(...)
* @param $permitoption
* @param $limitaction
* @param bool $checkblocks
* @return bool|string
*/
function qa_user_maximum_permit_error($permitoption, $limitaction = null, $checkblocks = true)
{
return qa_user_permit_error($permitoption, $limitaction, qa_user_level_maximum(), $checkblocks);
}
}
/**
/**
* Check whether the logged in user has permission to perform an action.
*
* @param string $permitoption The permission to check (if null, this simply checks whether the user is blocked).
......@@ -968,11 +1026,11 @@
* 'limit' => the user or IP address has reached a rate limit (if $limitaction specified)
* false => the operation can go ahead
*/
function qa_user_permit_error($permitoption=null, $limitaction=null, $userlevel=null, $checkblocks=true, $userfields=null)
{
function qa_user_permit_error($permitoption = null, $limitaction = null, $userlevel = null, $checkblocks = true, $userfields = null)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'app/limits.php';
require_once QA_INCLUDE_DIR . 'app/limits.php';
if (!isset($userfields))
$userfields = qa_get_logged_in_user_cache();
......@@ -1003,10 +1061,10 @@
}
return $error;
}
}
/**
/**
* Check whether user can perform $permitoption. Result as for qa_user_permit_error(...).
*
* @param string $permitoption Permission option name (from database) for action.
......@@ -1017,8 +1075,8 @@
*
* @return string|bool Reason the user is not permitted, or false if the operation can go ahead.
*/
function qa_permit_error($permitoption, $userid, $userlevel, $userflags, $userpoints=null)
{
function qa_permit_error($permitoption, $userid, $userlevel, $userflags, $userpoints = null)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$permit = isset($permitoption) ? qa_opt($permitoption) : QA_PERMIT_ALL;
......@@ -1038,10 +1096,10 @@
}
return qa_permit_value_error($permit, $userid, $userlevel, $userflags);
}
}
/**
/**
* Check whether user can reach the permission level. Result as for qa_user_permit_error(...).
*
* @param int $permit Permission constant.
......@@ -1051,8 +1109,8 @@
*
* @return string|bool Reason the user is not permitted, or false if the operation can go ahead
*/
function qa_permit_value_error($permit, $userid, $userlevel, $userflags)
{
function qa_permit_value_error($permit, $userid, $userlevel, $userflags)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if (!isset($userid) && $permit < QA_PERMIT_ALL)
......@@ -1083,8 +1141,7 @@
!$confirmed // actual confirmation
)
return 'confirm';
}
elseif ($permit >= QA_PERMIT_APPROVED) {
} elseif ($permit >= QA_PERMIT_APPROVED) {
if (
qa_opt('moderate_users') && // if this option off, we can't ask it of the user
$userlevel < QA_USER_LEVEL_APPROVED // user has not been approved
......@@ -1093,107 +1150,115 @@
}
return false;
}
}
function qa_user_captcha_reason($userlevel=null)
/*
Return whether a captcha is required for posts submitted by the current user. You can pass in a QA_USER_LEVEL_*
constant in $userlevel to consider the user at a different level to usual (e.g. if they are performing this action
in a category for which they have elevated privileges).
Possible results:
'login' => captcha required because the user is not logged in
'approve' => captcha required because the user has not been approved
'confirm' => captcha required because the user has not confirmed their email address
false => captcha is not required
*/
{
/**
* Return whether a captcha is required for posts submitted by the current user. You can pass in a QA_USER_LEVEL_*
* constant in $userlevel to consider the user at a different level to usual (e.g. if they are performing this action
* in a category for which they have elevated privileges).
*
* Possible results:
* 'login' => captcha required because the user is not logged in
* 'approve' => captcha required because the user has not been approved
* 'confirm' => captcha required because the user has not confirmed their email address
* false => captcha is not required
* @param $userlevel
* @return bool|mixed|string
*/
function qa_user_captcha_reason($userlevel = null)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$reason=false;
$reason = false;
if (!isset($userlevel))
$userlevel=qa_get_logged_in_level();
$userlevel = qa_get_logged_in_level();
if ($userlevel < QA_USER_LEVEL_APPROVED) { // approved users and above aren't shown captchas
$userid=qa_get_logged_in_userid();
$userid = qa_get_logged_in_userid();
if (qa_opt('captcha_on_anon_post') && !isset($userid))
$reason='login';
$reason = 'login';
elseif (qa_opt('moderate_users') && qa_opt('captcha_on_unapproved'))
$reason='approve';
elseif (qa_opt('confirm_user_emails') && qa_opt('captcha_on_unconfirmed') && !(qa_get_logged_in_flags() & QA_USER_FLAGS_EMAIL_CONFIRMED) )
$reason='confirm';
$reason = 'approve';
elseif (qa_opt('confirm_user_emails') && qa_opt('captcha_on_unconfirmed') && !(qa_get_logged_in_flags() & QA_USER_FLAGS_EMAIL_CONFIRMED))
$reason = 'confirm';
}
return $reason;
}
}
function qa_user_use_captcha($userlevel=null)
/*
Return whether a captcha should be presented to the logged in user for writing posts. You can pass in a
QA_USER_LEVEL_* constant in $userlevel to consider the user at a different level to usual.
*/
{
/**
* Return whether a captcha should be presented to the logged in user for writing posts. You can pass in a
* QA_USER_LEVEL_* constant in $userlevel to consider the user at a different level to usual.
* @param $userlevel
* @return bool|mixed
*/
function qa_user_use_captcha($userlevel = null)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return qa_user_captcha_reason($userlevel)!=false;
}
return qa_user_captcha_reason($userlevel) != false;
}
function qa_user_moderation_reason($userlevel=null)
/*
Return whether moderation is required for posts submitted by the current user. You can pass in a QA_USER_LEVEL_*
constant in $userlevel to consider the user at a different level to usual (e.g. if they are performing this action
in a category for which they have elevated privileges).
Possible results:
'login' => moderation required because the user is not logged in
'approve' => moderation required because the user has not been approved
'confirm' => moderation required because the user has not confirmed their email address
'points' => moderation required because the user has insufficient points
false => moderation is not required
*/
{
/**
* Return whether moderation is required for posts submitted by the current user. You can pass in a QA_USER_LEVEL_*
* constant in $userlevel to consider the user at a different level to usual (e.g. if they are performing this action
* in a category for which they have elevated privileges).
*
* Possible results:
* 'login' => moderation required because the user is not logged in
* 'approve' => moderation required because the user has not been approved
* 'confirm' => moderation required because the user has not confirmed their email address
* 'points' => moderation required because the user has insufficient points
* false => moderation is not required
* @param $userlevel
* @return bool|string
*/
function qa_user_moderation_reason($userlevel = null)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$reason=false;
$reason = false;
if (!isset($userlevel))
$userlevel=qa_get_logged_in_level();
$userlevel = qa_get_logged_in_level();
if (
($userlevel < QA_USER_LEVEL_EXPERT) && // experts and above aren't moderated
qa_user_permit_error('permit_moderate') // if the user can approve posts, no point in moderating theirs
) {
$userid=qa_get_logged_in_userid();
$userid = qa_get_logged_in_userid();
if (isset($userid)) {
if (qa_opt('moderate_users') && qa_opt('moderate_unapproved') && ($userlevel<QA_USER_LEVEL_APPROVED))
$reason='approve';
elseif (qa_opt('confirm_user_emails') && qa_opt('moderate_unconfirmed') && !(qa_get_logged_in_flags() & QA_USER_FLAGS_EMAIL_CONFIRMED) )
$reason='confirm';
if (qa_opt('moderate_users') && qa_opt('moderate_unapproved') && ($userlevel < QA_USER_LEVEL_APPROVED))
$reason = 'approve';
elseif (qa_opt('confirm_user_emails') && qa_opt('moderate_unconfirmed') && !(qa_get_logged_in_flags() & QA_USER_FLAGS_EMAIL_CONFIRMED))
$reason = 'confirm';
elseif (qa_opt('moderate_by_points') && (qa_get_logged_in_points() < qa_opt('moderate_points_limit')))
$reason='points';
$reason = 'points';
} elseif (qa_opt('moderate_anon_post'))
$reason='login';
$reason = 'login';
}
return $reason;
}
}
function qa_user_userfield_label($userfield)
/*
Return the label to display for $userfield as retrieved from the database, using default if no name set
*/
{
/**
* Return the label to display for $userfield as retrieved from the database, using default if no name set
* @param $userfield
* @return string
*/
function qa_user_userfield_label($userfield)
{
if (isset($userfield['content']))
return $userfield['content'];
else {
$defaultlabels=array(
$defaultlabels = array(
'name' => 'users/full_name',
'about' => 'users/about',
'location' => 'users/location',
......@@ -1205,136 +1270,144 @@ in a category for which they have elevated privileges).
}
return '';
}
}
function qa_set_form_security_key()
/*
Set or extend the cookie in browser of non logged-in users which identifies them for the purposes of form security (anti-CSRF protection)
*/
{
/**
* Set or extend the cookie in browser of non logged-in users which identifies them for the purposes of form security (anti-CSRF protection)
*/
function qa_set_form_security_key()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
global $qa_form_key_cookie_set;
if ( (!qa_is_logged_in()) && !@$qa_form_key_cookie_set) {
$qa_form_key_cookie_set=true;
if ((!qa_is_logged_in()) && !@$qa_form_key_cookie_set) {
$qa_form_key_cookie_set = true;
if (strlen(@$_COOKIE['qa_key'])!=QA_FORM_KEY_LENGTH) {
require_once QA_INCLUDE_DIR.'util/string.php';
$_COOKIE['qa_key']=qa_random_alphanum(QA_FORM_KEY_LENGTH);
if (strlen(@$_COOKIE['qa_key']) != QA_FORM_KEY_LENGTH) {
require_once QA_INCLUDE_DIR . 'util/string.php';
$_COOKIE['qa_key'] = qa_random_alphanum(QA_FORM_KEY_LENGTH);
}
setcookie('qa_key', $_COOKIE['qa_key'], time()+2*QA_FORM_EXPIRY_SECS, '/', QA_COOKIE_DOMAIN, (bool)ini_get('session.cookie_secure'), true); // extend on every page request
}
setcookie('qa_key', $_COOKIE['qa_key'], time() + 2 * QA_FORM_EXPIRY_SECS, '/', QA_COOKIE_DOMAIN, (bool)ini_get('session.cookie_secure'), true); // extend on every page request
}
}
function qa_calc_form_security_hash($action, $timestamp)
/*
Return the form security (anti-CSRF protection) hash for an $action (any string), that can be performed within
QA_FORM_EXPIRY_SECS of $timestamp (in unix seconds) by the current user.
*/
{
/**
* Return the form security (anti-CSRF protection) hash for an $action (any string), that can be performed within
* QA_FORM_EXPIRY_SECS of $timestamp (in unix seconds) by the current user.
* @param $action
* @param $timestamp
* @return mixed|string
*/
function qa_calc_form_security_hash($action, $timestamp)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$salt=qa_opt('form_security_salt');
$salt = qa_opt('form_security_salt');
if (qa_is_logged_in())
return sha1($salt.'/'.$action.'/'.$timestamp.'/'.qa_get_logged_in_userid().'/'.qa_get_logged_in_user_field('passsalt'));
return sha1($salt . '/' . $action . '/' . $timestamp . '/' . qa_get_logged_in_userid() . '/' . qa_get_logged_in_user_field('passsalt'));
else
return sha1($salt.'/'.$action.'/'.$timestamp.'/'.@$_COOKIE['qa_key']); // lower security for non logged in users - code+cookie can be transferred
}
return sha1($salt . '/' . $action . '/' . $timestamp . '/' . @$_COOKIE['qa_key']); // lower security for non logged in users - code+cookie can be transferred
}
function qa_get_form_security_code($action)
/*
Return the full form security (anti-CSRF protection) code for an $action (any string) performed within
QA_FORM_EXPIRY_SECS of now by the current user.
*/
{
/**
* Return the full form security (anti-CSRF protection) code for an $action (any string) performed within
* QA_FORM_EXPIRY_SECS of now by the current user.
* @param $action
* @return mixed|string
*/
function qa_get_form_security_code($action)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
qa_set_form_security_key();
$timestamp=qa_opt('db_time');
$timestamp = qa_opt('db_time');
return (int)qa_is_logged_in().'-'.$timestamp.'-'.qa_calc_form_security_hash($action, $timestamp);
}
return (int)qa_is_logged_in() . '-' . $timestamp . '-' . qa_calc_form_security_hash($action, $timestamp);
}
function qa_check_form_security_code($action, $value)
/*
Return whether $value matches the expected form security (anti-CSRF protection) code for $action (any string) and
that the code has not expired (if more than QA_FORM_EXPIRY_SECS have passed). Logs causes for suspicion.
*/
{
/**
* Return whether $value matches the expected form security (anti-CSRF protection) code for $action (any string) and
* that the code has not expired (if more than QA_FORM_EXPIRY_SECS have passed). Logs causes for suspicion.
* @param $action
* @param $value
* @return bool
*/
function qa_check_form_security_code($action, $value)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$reportproblems=array();
$silentproblems=array();
$reportproblems = array();
$silentproblems = array();
if (!isset($value))
$silentproblems[]='code missing';
if (!isset($value)) {
$silentproblems[] = 'code missing';
elseif (!strlen($value))
$silentproblems[]='code empty';
} elseif (!strlen($value)) {
$silentproblems[] = 'code empty';
else {
$parts=explode('-', $value);
} else {
$parts = explode('-', $value);
if (count($parts)==3) {
$loggedin=$parts[0];
$timestamp=$parts[1];
$hash=$parts[2];
$timenow=qa_opt('db_time');
if (count($parts) == 3) {
$loggedin = $parts[0];
$timestamp = $parts[1];
$hash = $parts[2];
$timenow = qa_opt('db_time');
if ($timestamp>$timenow)
$reportproblems[]='time '.($timestamp-$timenow).'s in future';
elseif ($timestamp<($timenow-QA_FORM_EXPIRY_SECS))
$silentproblems[]='timeout after '.($timenow-$timestamp).'s';
if ($timestamp > $timenow) {
$reportproblems[] = 'time ' . ($timestamp - $timenow) . 's in future';
} elseif ($timestamp < ($timenow - QA_FORM_EXPIRY_SECS)) {
$silentproblems[] = 'timeout after ' . ($timenow - $timestamp) . 's';
}
if (qa_is_logged_in()) {
if (!$loggedin)
$silentproblems[]='now logged in';
if (!$loggedin) {
$silentproblems[] = 'now logged in';
}
} else {
if ($loggedin)
$silentproblems[]='now logged out';
else {
$key=@$_COOKIE['qa_key'];
if ($loggedin) {
$silentproblems[] = 'now logged out';
} else {
$key = @$_COOKIE['qa_key'];
if (!isset($key))
$silentproblems[]='key cookie missing';
elseif (!strlen($key))
$silentproblems[]='key cookie empty';
elseif (strlen($key)!=QA_FORM_KEY_LENGTH)
$reportproblems[]='key cookie '.$key.' invalid';
if (!isset($key)) {
$silentproblems[] = 'key cookie missing';
} elseif (!strlen($key)) {
$silentproblems[] = 'key cookie empty';
} elseif (strlen($key) != QA_FORM_KEY_LENGTH) {
$reportproblems[] = 'key cookie ' . $key . ' invalid';
}
}
}
if (empty($silentproblems) && empty($reportproblems))
if (!hash_equals(strtolower(qa_calc_form_security_hash($action, $timestamp)), strtolower($hash)))
$reportproblems[]='code mismatch';
if (empty($silentproblems) && empty($reportproblems)) {
if (!hash_equals(strtolower(qa_calc_form_security_hash($action, $timestamp)), strtolower($hash))) {
$reportproblems[] = 'code mismatch';
}
}
} else
$reportproblems[]='code '.$value.' malformed';
} else {
$reportproblems[] = 'code ' . $value . ' malformed';
}
}
if (!empty($reportproblems) && QA_DEBUG_PERFORMANCE)
if (!empty($reportproblems) && QA_DEBUG_PERFORMANCE) {
@error_log(
'PHP Question2Answer form security violation for '.$action.
' by '.(qa_is_logged_in() ? ('userid '.qa_get_logged_in_userid()) : 'anonymous').
' ('.implode(', ', array_merge($reportproblems, $silentproblems)).')'.
' on '.@$_SERVER['REQUEST_URI'].
' via '.@$_SERVER['HTTP_REFERER']
'PHP Question2Answer form security violation for ' . $action .
' by ' . (qa_is_logged_in() ? ('userid ' . qa_get_logged_in_userid()) : 'anonymous') .
' (' . implode(', ', array_merge($reportproblems, $silentproblems)) . ')' .
' on ' . @$_SERVER['REQUEST_URI'] .
' via ' . @$_SERVER['HTTP_REFERER']
);
return (empty($silentproblems) && empty($reportproblems));
}
/*
Omit PHP closing tag to help avoid accidental output
*/
return (empty($silentproblems) && empty($reportproblems));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment