Commit 54ada742 by Scott

Coding style (app/)

parent f24542bb
...@@ -20,171 +20,199 @@ ...@@ -20,171 +20,199 @@
More about this license: http://www.question2answer.org/license.php 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: ../'); header('Location: ../');
exit; exit;
}
/**
* Return the URL which will output $blobid from the database when requested, $absolute or relative
* @param $blobid
* @param bool $absolute
* @return mixed|string
*/
function qa_get_blob_url($blobid, $absolute = false)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return qa_path('blob', array('qa_blobid' => $blobid), $absolute ? qa_opt('site_url') : null, QA_URL_FORMAT_PARAMS);
}
/**
* Return the full path to the on-disk directory for blob $blobid (subdirectories are named by the first 3 digits of $blobid)
* @param $blobid
* @return mixed|string
*/
function qa_get_blob_directory($blobid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return rtrim(QA_BLOBS_DIRECTORY, '/') . '/' . substr(str_pad($blobid, 20, '0', STR_PAD_LEFT), 0, 3);
}
/**
* Return the full page and filename of blob $blobid which is in $format ($format is used as the file name suffix e.g. .jpg)
* @param $blobid
* @param $format
* @return mixed|string
*/
function qa_get_blob_filename($blobid, $format)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return qa_get_blob_directory($blobid) . '/' . $blobid . '.' . preg_replace('/[^A-Za-z0-9]/', '', $format);
}
/**
* Create a new blob (storing the content in the database or on disk as appropriate) with $content and $format, returning its blobid.
* Pass the original name of the file uploaded in $sourcefilename and the $userid, $cookieid and $ip of the user creating it
* @param $content
* @param $format
* @param $sourcefilename
* @param $userid
* @param $cookieid
* @param $ip
* @return mixed|null|string
*/
function qa_create_blob($content, $format, $sourcefilename = null, $userid = null, $cookieid = null, $ip = null)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR . 'db/blobs.php';
$blobid = qa_db_blob_create(defined('QA_BLOBS_DIRECTORY') ? null : $content, $format, $sourcefilename, $userid, $cookieid, $ip);
if (isset($blobid) && defined('QA_BLOBS_DIRECTORY')) {
// still write content to the database if writing to disk failed
if (!qa_write_blob_file($blobid, $content, $format))
qa_db_blob_set_content($blobid, $content);
} }
return $blobid;
function qa_get_blob_url($blobid, $absolute=false) }
/*
Return the URL which will output $blobid from the database when requested, $absolute or relative
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return qa_path('blob', array('qa_blobid' => $blobid), $absolute ? qa_opt('site_url') : null, QA_URL_FORMAT_PARAMS);
}
function qa_get_blob_directory($blobid)
/*
Return the full path to the on-disk directory for blob $blobid (subdirectories are named by the first 3 digits of $blobid)
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return rtrim(QA_BLOBS_DIRECTORY, '/').'/'.substr(str_pad($blobid, 20, '0', STR_PAD_LEFT), 0, 3);
}
function qa_get_blob_filename($blobid, $format)
/*
Return the full page and filename of blob $blobid which is in $format ($format is used as the file name suffix e.g. .jpg)
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return qa_get_blob_directory($blobid).'/'.$blobid.'.'.preg_replace('/[^A-Za-z0-9]/', '', $format);
}
function qa_create_blob($content, $format, $sourcefilename=null, $userid=null, $cookieid=null, $ip=null)
/*
Create a new blob (storing the content in the database or on disk as appropriate) with $content and $format, returning its blobid.
Pass the original name of the file uploaded in $sourcefilename and the $userid, $cookieid and $ip of the user creating it
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/blobs.php';
$blobid=qa_db_blob_create(defined('QA_BLOBS_DIRECTORY') ? null : $content, $format, $sourcefilename, $userid, $cookieid, $ip);
if (isset($blobid) && defined('QA_BLOBS_DIRECTORY'))
if (!qa_write_blob_file($blobid, $content, $format))
qa_db_blob_set_content($blobid, $content); // still write content to the database if writing to disk failed
return $blobid;
}
function qa_write_blob_file($blobid, $content, $format) /**
/* * Write the on-disk file for blob $blobid with $content and $format. Returns true if the write succeeded, false otherwise.
Write the on-disk file for blob $blobid with $content and $format. Returns true if the write succeeded, false otherwise. * @param $blobid
*/ * @param $content
{ * @param $format
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } * @return bool|mixed
*/
function qa_write_blob_file($blobid, $content, $format)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$written=false; $written = false;
$directory=qa_get_blob_directory($blobid); $directory = qa_get_blob_directory($blobid);
if (is_dir($directory) || mkdir($directory, fileperms(rtrim(QA_BLOBS_DIRECTORY, '/')) & 0777)) { if (is_dir($directory) || mkdir($directory, fileperms(rtrim(QA_BLOBS_DIRECTORY, '/')) & 0777)) {
$filename=qa_get_blob_filename($blobid, $format); $filename = qa_get_blob_filename($blobid, $format);
$file=fopen($filename, 'xb'); $file = fopen($filename, 'xb');
if (is_resource($file)) { if (is_resource($file)) {
if (fwrite($file, $content)>=strlen($content)) if (fwrite($file, $content) >= strlen($content))
$written=true; $written = true;
fclose($file); fclose($file);
if (!$written) if (!$written)
unlink($filename); unlink($filename);
}
} }
return $written;
} }
return $written;
}
function qa_read_blob($blobid)
/*
Retrieve blob $blobid from the database, reading the content from disk if appropriate
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/blobs.php'; /**
* Retrieve blob $blobid from the database, reading the content from disk if appropriate
* @param $blobid
* @return array|mixed|null
*/
function qa_read_blob($blobid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$blob=qa_db_blob_read($blobid); require_once QA_INCLUDE_DIR . 'db/blobs.php';
if (isset($blob) && defined('QA_BLOBS_DIRECTORY') && !isset($blob['content'])) $blob = qa_db_blob_read($blobid);
$blob['content']=qa_read_blob_file($blobid, $blob['format']);
return $blob; if (isset($blob) && defined('QA_BLOBS_DIRECTORY') && !isset($blob['content']))
} $blob['content'] = qa_read_blob_file($blobid, $blob['format']);
return $blob;
}
function qa_read_blob_file($blobid, $format)
/*
Read the content of blob $blobid in $format from disk. On failure, it will return false.
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$filename = qa_get_blob_filename($blobid, $format); /**
if (is_readable($filename)) * Read the content of blob $blobid in $format from disk. On failure, it will return false.
return file_get_contents($filename); * @param $blobid
else * @param $format
return null; * @return mixed|null|string
} */
function qa_read_blob_file($blobid, $format)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$filename = qa_get_blob_filename($blobid, $format);
if (is_readable($filename))
return file_get_contents($filename);
else
return null;
}
function qa_delete_blob($blobid)
/*
Delete blob $blobid from the database, and remove the on-disk file if appropriate
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/blobs.php'; /**
* Delete blob $blobid from the database, and remove the on-disk file if appropriate
* @param $blobid
* @return mixed
*/
function qa_delete_blob($blobid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if (defined('QA_BLOBS_DIRECTORY')) { require_once QA_INCLUDE_DIR . 'db/blobs.php';
$blob=qa_db_blob_read($blobid);
if (isset($blob) && !isset($blob['content'])) if (defined('QA_BLOBS_DIRECTORY')) {
unlink(qa_get_blob_filename($blobid, $blob['format'])); $blob = qa_db_blob_read($blobid);
}
qa_db_blob_delete($blobid); if (isset($blob) && !isset($blob['content']))
unlink(qa_get_blob_filename($blobid, $blob['format']));
} }
qa_db_blob_delete($blobid);
}
function qa_delete_blob_file($blobid, $format)
/*
Delete the on-disk file for blob $blobid in $format
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
unlink(qa_get_blob_filename($blobid, $format));
}
/**
* Delete the on-disk file for blob $blobid in $format
* @param $blobid
* @param $format
* @return mixed
*/
function qa_delete_blob_file($blobid, $format)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
function qa_blob_exists($blobid) unlink(qa_get_blob_filename($blobid, $format));
/* }
Check if blob $blobid exists
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/blobs.php';
return qa_db_blob_exists($blobid); /**
} * Check if blob $blobid exists
* @param $blobid
* @return bool|mixed
*/
function qa_blob_exists($blobid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR . 'db/blobs.php';
/* return qa_db_blob_exists($blobid);
Omit PHP closing tag to help avoid accidental output }
*/
\ No newline at end of file
...@@ -39,6 +39,8 @@ function qa_captcha_available() ...@@ -39,6 +39,8 @@ function qa_captcha_available()
/** /**
* Return an HTML string explaining $captchareason (from qa_user_captcha_reason()) to the user about why they are seeing a captcha * Return an HTML string explaining $captchareason (from qa_user_captcha_reason()) to the user about why they are seeing a captcha
* @param $captchareason
* @return mixed|null|string
*/ */
function qa_captcha_reason_note($captchareason) function qa_captcha_reason_note($captchareason)
{ {
...@@ -65,8 +67,13 @@ function qa_captcha_reason_note($captchareason) ...@@ -65,8 +67,13 @@ function qa_captcha_reason_note($captchareason)
/** /**
* Prepare $qa_content for showing a captcha, adding the element to $fields, given previous $errors, and a $note to display. * Prepare $qa_content for showing a captcha, adding the element to $fields, given previous $errors, and a $note to display.
* Returns JavaScript required to load CAPTCHA when field is shown by user (e.g. clicking comment button). * Returns JavaScript required to load CAPTCHA when field is shown by user (e.g. clicking comment button).
* @param $qa_content
* @param $fields
* @param $errors
* @param $note
* @return string
*/ */
function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note=null) function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note = null)
{ {
if (!qa_captcha_available()) if (!qa_captcha_available())
return ''; return '';
...@@ -79,8 +86,7 @@ function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note=null) ...@@ -79,8 +86,7 @@ function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note=null)
if ($count > 1) { if ($count > 1) {
// use blank captcha in order to load via JS // use blank captcha in order to load via JS
$html = ''; $html = '';
} } else {
else {
// first captcha is always loaded explicitly // first captcha is always loaded explicitly
$qa_content['script_var']['qa_captcha_in'] = 'qa_captcha_div_1'; $qa_content['script_var']['qa_captcha_in'] = 'qa_captcha_div_1';
$html = $captcha->form_html($qa_content, @$errors['captcha']); $html = $captcha->form_html($qa_content, @$errors['captcha']);
...@@ -89,17 +95,19 @@ function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note=null) ...@@ -89,17 +95,19 @@ function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note=null)
$fields['captcha'] = array( $fields['captcha'] = array(
'type' => 'custom', 'type' => 'custom',
'label' => qa_lang_html('misc/captcha_label'), 'label' => qa_lang_html('misc/captcha_label'),
'html' => '<div id="qa_captcha_div_'.$count.'">'.$html.'</div>', 'html' => '<div id="qa_captcha_div_' . $count . '">' . $html . '</div>',
'error' => @array_key_exists('captcha', $errors) ? qa_lang_html('misc/captcha_error') : null, 'error' => @array_key_exists('captcha', $errors) ? qa_lang_html('misc/captcha_error') : null,
'note' => $note, 'note' => $note,
); );
return "if (!document.getElementById('qa_captcha_div_".$count."').hasChildNodes()) { recaptcha_load('qa_captcha_div_".$count."'); }"; return "if (!document.getElementById('qa_captcha_div_" . $count . "').hasChildNodes()) { recaptcha_load('qa_captcha_div_" . $count . "'); }";
} }
/** /**
* Check if captcha is submitted correctly, and if not, set $errors['captcha'] to a descriptive string. * Check if captcha is submitted correctly, and if not, set $errors['captcha'] to a descriptive string.
* @param $errors
* @return bool
*/ */
function qa_captcha_validate_post(&$errors) function qa_captcha_validate_post(&$errors)
{ {
......
...@@ -20,59 +20,56 @@ ...@@ -20,59 +20,56 @@
More about this license: http://www.question2answer.org/license.php 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: ../'); header('Location: ../');
exit; exit;
} }
function qa_cookie_get() /**
/* * Return the user identification cookie sent by the browser for this page request, or null if none
Return the user identification cookie sent by the browser for this page request, or null if none */
*/ function qa_cookie_get()
{ {
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return isset($_COOKIE['qa_id']) ? qa_gpc_to_string($_COOKIE['qa_id']) : null; return isset($_COOKIE['qa_id']) ? qa_gpc_to_string($_COOKIE['qa_id']) : null;
} }
function qa_cookie_get_create() /**
/* * Return user identification cookie sent by browser if valid, or create a new one if not.
Return user identification cookie sent by browser if valid, or create a new one if not. * Either way, extend for another year (this is used when an anonymous post is created)
Either way, extend for another year (this is used when an anonymous post is created) */
*/ function qa_cookie_get_create()
{ {
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/cookies.php';
$cookieid=qa_cookie_get(); require_once QA_INCLUDE_DIR . 'db/cookies.php';
if (isset($cookieid) && qa_db_cookie_exists($cookieid)) $cookieid = qa_cookie_get();
; // cookie is valid
else
$cookieid=qa_db_cookie_create(qa_remote_ip_address());
setcookie('qa_id', $cookieid, time()+86400*365, '/', QA_COOKIE_DOMAIN, (bool)ini_get('session.cookie_secure'), true); if (!isset($cookieid) || !qa_db_cookie_exists($cookieid)) {
$_COOKIE['qa_id']=$cookieid; // cookie is invalid
$cookieid = qa_db_cookie_create(qa_remote_ip_address());
return $cookieid;
} }
setcookie('qa_id', $cookieid, time() + 86400 * 365, '/', QA_COOKIE_DOMAIN, (bool)ini_get('session.cookie_secure'), true);
$_COOKIE['qa_id'] = $cookieid;
function qa_cookie_report_action($cookieid, $action) return $cookieid;
/* }
Called after a database write $action performed by a user identified by $cookieid,
relating to $questionid, $answerid and/or $commentid
*/
{
require_once QA_INCLUDE_DIR.'db/cookies.php';
qa_db_cookie_written($cookieid, qa_remote_ip_address());
}
/**
* Called after a database write $action performed by a user identified by $cookieid,
* relating to $questionid, $answerid and/or $commentid
* @param $cookieid
* @param $action
*/
function qa_cookie_report_action($cookieid, $action)
{
require_once QA_INCLUDE_DIR . 'db/cookies.php';
/* qa_db_cookie_written($cookieid, qa_remote_ip_address());
Omit PHP closing tag to help avoid accidental output }
*/
...@@ -20,159 +20,164 @@ ...@@ -20,159 +20,164 @@
More about this license: http://www.question2answer.org/license.php 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: ../'); header('Location: ../');
exit; exit;
} }
require_once QA_INCLUDE_DIR.'app/options.php'; require_once QA_INCLUDE_DIR . 'app/options.php';
/**
* Suspend the sending of all email notifications via qa_send_notification(...) if $suspend is true, otherwise
* reinstate it. A counter is kept to allow multiple calls.
* @param bool $suspend
*/
function qa_suspend_notifications($suspend = true)
{
global $qa_notifications_suspended;
$qa_notifications_suspended += ($suspend ? 1 : -1);
}
/**
* Send email to person with $userid and/or $email and/or $handle (null/invalid values are ignored or retrieved from
* user database as appropriate). Email uses $subject and $body, after substituting each key in $subs with its
* corresponding value, plus applying some standard substitutions such as ^site_title, ^handle and ^email.
* @param $userid
* @param $email
* @param $handle
* @param $subject
* @param $body
* @param $subs
* @param bool $html
* @return bool
*/
function qa_send_notification($userid, $email, $handle, $subject, $body, $subs, $html = false)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
global $qa_notifications_suspended;
if ($qa_notifications_suspended > 0)
return false;
require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR . 'util/string.php';
if (isset($userid)) {
$needemail = !qa_email_validate(@$email); // take from user if invalid, e.g. @ used in practice
$needhandle = empty($handle);
if ($needemail || $needhandle) {
if (QA_FINAL_EXTERNAL_USERS) {
if ($needhandle) {
$handles = qa_get_public_from_userids(array($userid));
$handle = @$handles[$userid];
}
function qa_suspend_notifications($suspend=true) if ($needemail)
/* $email = qa_get_user_email($userid);
Suspend the sending of all email notifications via qa_send_notification(...) if $suspend is true, otherwise
reinstate it. A counter is kept to allow multiple calls.
*/
{
global $qa_notifications_suspended;
$qa_notifications_suspended+=($suspend ? 1 : -1); } else {
} $useraccount = qa_db_select_with_pending(
array(
'columns' => array('email', 'handle'),
'source' => '^users WHERE userid = #',
'arguments' => array($userid),
'single' => true,
)
);
if ($needhandle)
$handle = @$useraccount['handle'];
function qa_send_notification($userid, $email, $handle, $subject, $body, $subs, $html = false) if ($needemail)
/* $email = @$useraccount['email'];
Send email to person with $userid and/or $email and/or $handle (null/invalid values are ignored or retrieved from
user database as appropriate). Email uses $subject and $body, after substituting each key in $subs with its
corresponding value, plus applying some standard substitutions such as ^site_title, ^handle and ^email.
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
global $qa_notifications_suspended;
if ($qa_notifications_suspended>0)
return false;
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR.'util/string.php';
if (isset($userid)) {
$needemail=!qa_email_validate(@$email); // take from user if invalid, e.g. @ used in practice
$needhandle=empty($handle);
if ($needemail || $needhandle) {
if (QA_FINAL_EXTERNAL_USERS) {
if ($needhandle) {
$handles=qa_get_public_from_userids(array($userid));
$handle=@$handles[$userid];
}
if ($needemail)
$email=qa_get_user_email($userid);
} else {
$useraccount=qa_db_select_with_pending(
array(
'columns' => array('email', 'handle'),
'source' => '^users WHERE userid = #',
'arguments' => array($userid),
'single' => true,
)
);
if ($needhandle)
$handle=@$useraccount['handle'];
if ($needemail)
$email=@$useraccount['email'];
}
} }
} }
if (isset($email) && qa_email_validate($email)) {
$subs['^site_title']=qa_opt('site_title');
$subs['^handle']=$handle;
$subs['^email']=$email;
$subs['^open']="\n";
$subs['^close']="\n";
return qa_send_email(array(
'fromemail' => qa_opt('from_email'),
'fromname' => qa_opt('site_title'),
'toemail' => $email,
'toname' => $handle,
'subject' => strtr($subject, $subs),
'body' => (empty($handle) ? '' : qa_lang_sub('emails/to_handle_prefix', $handle)).strtr($body, $subs),
'html' => $html,
));
} else
return false;
} }
if (isset($email) && qa_email_validate($email)) {
$subs['^site_title'] = qa_opt('site_title');
$subs['^handle'] = $handle;
$subs['^email'] = $email;
$subs['^open'] = "\n";
$subs['^close'] = "\n";
return qa_send_email(array(
'fromemail' => qa_opt('from_email'),
'fromname' => qa_opt('site_title'),
'toemail' => $email,
'toname' => $handle,
'subject' => strtr($subject, $subs),
'body' => (empty($handle) ? '' : qa_lang_sub('emails/to_handle_prefix', $handle)) . strtr($body, $subs),
'html' => $html,
));
}
function qa_send_email($params) return false;
/* }
Send the email based on the $params array - the following keys are required (some can be empty): fromemail,
fromname, toemail, toname, subject, body, html
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
// @error_log(print_r($params, true));
require_once QA_INCLUDE_DIR.'vendor/PHPMailer/PHPMailerAutoload.php';
$mailer=new PHPMailer();
$mailer->CharSet='utf-8';
$mailer->From=$params['fromemail']; /**
$mailer->Sender=$params['fromemail']; * Send the email based on the $params array - the following keys are required (some can be empty): fromemail,
$mailer->FromName=$params['fromname']; * fromname, toemail, toname, subject, body, html
$mailer->addAddress($params['toemail'], $params['toname']); * @param $params
if(!empty($params['replytoemail'])){ * @return bool
$mailer->addReplyTo($params['replytoemail'], $params['replytoname']); */
} function qa_send_email($params)
$mailer->Subject=$params['subject']; {
$mailer->Body=$params['body']; if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if ($params['html']) // @error_log(print_r($params, true));
$mailer->isHTML(true);
if (qa_opt('smtp_active')) { require_once QA_INCLUDE_DIR . 'vendor/PHPMailer/PHPMailerAutoload.php';
$mailer->isSMTP();
$mailer->Host=qa_opt('smtp_address');
$mailer->Port=qa_opt('smtp_port');
if (qa_opt('smtp_secure')){ $mailer = new PHPMailer();
$mailer->SMTPSecure=qa_opt('smtp_secure'); $mailer->CharSet = 'utf-8';
}
else {
$mailer->SMTPOptions=array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
);
}
if (qa_opt('smtp_authenticate')) { $mailer->From = $params['fromemail'];
$mailer->SMTPAuth=true; $mailer->Sender = $params['fromemail'];
$mailer->Username=qa_opt('smtp_username'); $mailer->FromName = $params['fromname'];
$mailer->Password=qa_opt('smtp_password'); $mailer->addAddress($params['toemail'], $params['toname']);
} if (!empty($params['replytoemail'])) {
$mailer->addReplyTo($params['replytoemail'], $params['replytoname']);
}
$mailer->Subject = $params['subject'];
$mailer->Body = $params['body'];
if ($params['html'])
$mailer->isHTML(true);
if (qa_opt('smtp_active')) {
$mailer->isSMTP();
$mailer->Host = qa_opt('smtp_address');
$mailer->Port = qa_opt('smtp_port');
if (qa_opt('smtp_secure')) {
$mailer->SMTPSecure = qa_opt('smtp_secure');
} else {
$mailer->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true,
),
);
} }
$send_status = $mailer->send(); if (qa_opt('smtp_authenticate')) {
if(!$send_status){ $mailer->SMTPAuth = true;
@error_log('PHP Question2Answer email send error: '.$mailer->ErrorInfo); $mailer->Username = qa_opt('smtp_username');
$mailer->Password = qa_opt('smtp_password');
} }
return $send_status;
} }
$send_status = $mailer->send();
/* if (!$send_status) {
Omit PHP closing tag to help avoid accidental output @error_log('PHP Question2Answer email send error: ' . $mailer->ErrorInfo);
*/ }
return $send_status;
}
...@@ -20,69 +20,82 @@ ...@@ -20,69 +20,82 @@
More about this license: http://www.question2answer.org/license.php 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: ../'); header('Location: ../');
exit; exit;
}
require_once QA_INCLUDE_DIR . 'db/events.php';
require_once QA_INCLUDE_DIR . 'app/updates.php';
/**
* Add appropriate events to the database for an action performed on a question. The event of type $updatetype relates
* to $lastpostid whose antecedent question is $questionid, and was caused by $lastuserid. Pass a unix $timestamp for
* the event time or leave as null to use now. This will add an event to $questionid's and $lastuserid's streams. If
* $otheruserid is set, it will also add an notification-style event for that user, unless they are the one who did it.
* @param $questionid
* @param $lastpostid
* @param $updatetype
* @param $lastuserid
* @param $otheruserid
* @param $timestamp
*/
function qa_create_event_for_q_user($questionid, $lastpostid, $updatetype, $lastuserid, $otheruserid = null, $timestamp = null)
{
qa_db_event_create_for_entity(QA_ENTITY_QUESTION, $questionid, $questionid, $lastpostid, $updatetype, $lastuserid, $timestamp); // anyone who favorited the question
if (isset($lastuserid) && !QA_FINAL_EXTERNAL_USERS)
qa_db_event_create_for_entity(QA_ENTITY_USER, $lastuserid, $questionid, $lastpostid, $updatetype, $lastuserid, $timestamp); // anyone who favorited the user who did it
if (isset($otheruserid) && ($otheruserid != $lastuserid))
qa_db_event_create_not_entity($otheruserid, $questionid, $lastpostid, $updatetype, $lastuserid, $timestamp); // possible other user to be informed
}
/**
* Add appropriate events to the database for an action performed on a set of tags in $tagstring (namely, a question
* being created with those tags or having one of those tags added afterwards). The event of type $updatetype relates
* to the question $questionid, and was caused by $lastuserid. Pass a unix $timestamp for the event time or leave as
* null to use now.
* @param $tagstring
* @param $questionid
* @param $updatetype
* @param $lastuserid
* @param $timestamp
*/
function qa_create_event_for_tags($tagstring, $questionid, $updatetype, $lastuserid, $timestamp = null)
{
require_once QA_INCLUDE_DIR . 'util/string.php';
require_once QA_INCLUDE_DIR . 'db/post-create.php';
$tagwordids = qa_db_word_mapto_ids(array_unique(qa_tagstring_to_tags($tagstring)));
foreach ($tagwordids as $wordid) {
qa_db_event_create_for_entity(QA_ENTITY_TAG, $wordid, $questionid, $questionid, $updatetype, $lastuserid, $timestamp);
} }
}
require_once QA_INCLUDE_DIR.'db/events.php';
require_once QA_INCLUDE_DIR.'app/updates.php';
/**
* Add appropriate events to the database for an action performed on $categoryid (namely, a question being created in
function qa_create_event_for_q_user($questionid, $lastpostid, $updatetype, $lastuserid, $otheruserid=null, $timestamp=null) * that category or being moved to it later on), along with all of its ancestor categories. The event of type
/* * $updatetype relates to the question $questionid, and was caused by $lastuserid. Pass a unix $timestamp for the event
Add appropriate events to the database for an action performed on a question. The event of type $updatetype relates * time or leave as null to use now.
to $lastpostid whose antecedent question is $questionid, and was caused by $lastuserid. Pass a unix $timestamp for * @param $categoryid
the event time or leave as null to use now. This will add an event to $questionid's and $lastuserid's streams. If * @param $questionid
$otheruserid is set, it will also add an notification-style event for that user, unless they are the one who did it. * @param $updatetype
*/ * @param $lastuserid
{ * @param $timestamp
qa_db_event_create_for_entity(QA_ENTITY_QUESTION, $questionid, $questionid, $lastpostid, $updatetype, $lastuserid, $timestamp); // anyone who favorited the question */
function qa_create_event_for_category($categoryid, $questionid, $updatetype, $lastuserid, $timestamp = null)
if (isset($lastuserid) && !QA_FINAL_EXTERNAL_USERS) {
qa_db_event_create_for_entity(QA_ENTITY_USER, $lastuserid, $questionid, $lastpostid, $updatetype, $lastuserid, $timestamp); // anyone who favorited the user who did it if (isset($categoryid)) {
require_once QA_INCLUDE_DIR . 'db/selects.php';
if (isset($otheruserid) && ($otheruserid!=$lastuserid)) require_once QA_INCLUDE_DIR . 'app/format.php';
qa_db_event_create_not_entity($otheruserid, $questionid, $lastpostid, $updatetype, $lastuserid, $timestamp); // possible other user to be informed
} $categories = qa_category_path(qa_db_single_select(qa_db_category_nav_selectspec($categoryid, true)), $categoryid);
foreach ($categories as $category) {
qa_db_event_create_for_entity(QA_ENTITY_CATEGORY, $category['categoryid'], $questionid, $questionid, $updatetype, $lastuserid, $timestamp);
function qa_create_event_for_tags($tagstring, $questionid, $updatetype, $lastuserid, $timestamp=null)
/*
Add appropriate events to the database for an action performed on a set of tags in $tagstring (namely, a question
being created with those tags or having one of those tags added afterwards). The event of type $updatetype relates
to the question $questionid, and was caused by $lastuserid. Pass a unix $timestamp for the event time or leave as
null to use now.
*/
{
require_once QA_INCLUDE_DIR.'util/string.php';
require_once QA_INCLUDE_DIR.'db/post-create.php';
$tagwordids=qa_db_word_mapto_ids(array_unique(qa_tagstring_to_tags($tagstring)));
foreach ($tagwordids as $wordid)
qa_db_event_create_for_entity(QA_ENTITY_TAG, $wordid, $questionid, $questionid, $updatetype, $lastuserid, $timestamp);
}
function qa_create_event_for_category($categoryid, $questionid, $updatetype, $lastuserid, $timestamp=null)
/*
Add appropriate events to the database for an action performed on $categoryid (namely, a question being created in
that category or being moved to it later on), along with all of its ancestor categories. The event of type
$updatetype relates to the question $questionid, and was caused by $lastuserid. Pass a unix $timestamp for the event
time or leave as null to use now.
*/
{
if (isset($categoryid)) {
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR.'app/format.php';
$categories=qa_category_path(qa_db_single_select(qa_db_category_nav_selectspec($categoryid, true)), $categoryid);
foreach ($categories as $category)
qa_db_event_create_for_entity(QA_ENTITY_CATEGORY, $category['categoryid'], $questionid, $questionid, $updatetype, $lastuserid, $timestamp);
} }
} }
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -20,188 +20,193 @@ ...@@ -20,188 +20,193 @@
More about this license: http://www.question2answer.org/license.php 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: ../'); header('Location: ../');
exit; exit;
}
/**
* Set an entity to be favorited or removed from favorites. Handles event reporting.
*
* @param int $userid ID of user assigned to the favorite
* @param string $handle Username of user
* @param string $cookieid Cookie ID of user
* @param string $entitytype Entity type code (one of QA_ENTITY_* constants)
* @param string $entityid ID of the entity being favorited (e.g. postid for questions)
* @param bool $favorite Whether to add favorite (true) or remove favorite (false)
*/
function qa_user_favorite_set($userid, $handle, $cookieid, $entitytype, $entityid, $favorite)
{
require_once QA_INCLUDE_DIR . 'db/favorites.php';
require_once QA_INCLUDE_DIR . 'app/limits.php';
require_once QA_INCLUDE_DIR . 'app/updates.php';
// Make sure the user is not favoriting themselves
if ($entitytype == QA_ENTITY_USER && $userid == $entityid) {
return;
} }
if ($favorite)
/** qa_db_favorite_create($userid, $entitytype, $entityid);
* Set an entity to be favorited or removed from favorites. Handles event reporting. else
* qa_db_favorite_delete($userid, $entitytype, $entityid);
* @param int $userid ID of user assigned to the favorite
* @param string $handle Username of user switch ($entitytype) {
* @param string $cookieid Cookie ID of user case QA_ENTITY_QUESTION:
* @param string $entitytype Entity type code (one of QA_ENTITY_* constants) $action = $favorite ? 'q_favorite' : 'q_unfavorite';
* @param string $entityid ID of the entity being favorited (e.g. postid for questions) $params = array('postid' => $entityid);
* @param bool $favorite Whether to add favorite (true) or remove favorite (false) break;
*/
function qa_user_favorite_set($userid, $handle, $cookieid, $entitytype, $entityid, $favorite) case QA_ENTITY_USER:
{ $action = $favorite ? 'u_favorite' : 'u_unfavorite';
require_once QA_INCLUDE_DIR.'db/favorites.php'; $params = array('userid' => $entityid);
require_once QA_INCLUDE_DIR.'app/limits.php'; break;
require_once QA_INCLUDE_DIR.'app/updates.php';
case QA_ENTITY_TAG:
// Make sure the user is not favoriting themselves $action = $favorite ? 'tag_favorite' : 'tag_unfavorite';
if ($entitytype == QA_ENTITY_USER && $userid == $entityid) { $params = array('wordid' => $entityid);
return; break;
}
case QA_ENTITY_CATEGORY:
if ($favorite) $action = $favorite ? 'cat_favorite' : 'cat_unfavorite';
qa_db_favorite_create($userid, $entitytype, $entityid); $params = array('categoryid' => $entityid);
else break;
qa_db_favorite_delete($userid, $entitytype, $entityid);
default:
switch ($entitytype) { qa_fatal_error('Favorite type not recognized');
case QA_ENTITY_QUESTION: break;
$action=$favorite ? 'q_favorite' : 'q_unfavorite';
$params=array('postid' => $entityid);
break;
case QA_ENTITY_USER:
$action=$favorite ? 'u_favorite' : 'u_unfavorite';
$params=array('userid' => $entityid);
break;
case QA_ENTITY_TAG:
$action=$favorite ? 'tag_favorite' : 'tag_unfavorite';
$params=array('wordid' => $entityid);
break;
case QA_ENTITY_CATEGORY:
$action=$favorite ? 'cat_favorite' : 'cat_unfavorite';
$params=array('categoryid' => $entityid);
break;
default:
qa_fatal_error('Favorite type not recognized');
break;
}
qa_report_event($action, $userid, $handle, $cookieid, $params);
} }
qa_report_event($action, $userid, $handle, $cookieid, $params);
}
function qa_favorite_q_list_view($questions, $usershtml)
/*
Returns content to set in $qa_content['q_list'] for a user's favorite $questions. Pre-generated
user HTML in $usershtml.
*/
{
$q_list = array(
'qs' => array(),
);
if (count($questions) === 0)
return $q_list;
$q_list['form'] = array(
'tags' => 'method="post" action="'.qa_self_html().'"',
'hidden' => array(
'code' => qa_get_form_security_code('vote'),
),
);
$defaults = qa_post_html_defaults('Q');
foreach ($questions as $question) { /**
$q_list['qs'][] = qa_post_html_fields($question, qa_get_logged_in_userid(), qa_cookie_get(), * Returns content to set in $qa_content['q_list'] for a user's favorite $questions. Pre-generated
$usershtml, null, qa_post_html_options($question, $defaults)); * user HTML in $usershtml.
} * @param $questions
* @param $usershtml
* @return array
*/
function qa_favorite_q_list_view($questions, $usershtml)
{
$q_list = array(
'qs' => array(),
);
if (count($questions) === 0)
return $q_list; return $q_list;
}
$q_list['form'] = array(
'tags' => 'method="post" action="' . qa_self_html() . '"',
'hidden' => array(
'code' => qa_get_form_security_code('vote'),
),
);
function qa_favorite_users_view($users, $usershtml) $defaults = qa_post_html_defaults('Q');
/*
Returns content to set in $qa_content['ranking_users'] for a user's favorite $users. Pre-generated
user HTML in $usershtml.
*/
{
if (QA_FINAL_EXTERNAL_USERS)
return null;
require_once QA_INCLUDE_DIR.'app/users.php'; foreach ($questions as $question) {
require_once QA_INCLUDE_DIR.'app/format.php'; $q_list['qs'][] = qa_post_html_fields($question, qa_get_logged_in_userid(), qa_cookie_get(),
$usershtml, null, qa_post_html_options($question, $defaults));
}
$ranking = array( return $q_list;
'items' => array(), }
'rows' => ceil(count($users)/qa_opt('columns_users')),
'type' => 'users',
/**
* Returns content to set in $qa_content['ranking_users'] for a user's favorite $users. Pre-generated
* user HTML in $usershtml.
* @param $users
* @param $usershtml
* @return array|null
*/
function qa_favorite_users_view($users, $usershtml)
{
if (QA_FINAL_EXTERNAL_USERS)
return null;
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/format.php';
$ranking = array(
'items' => array(),
'rows' => ceil(count($users) / qa_opt('columns_users')),
'type' => 'users',
);
foreach ($users as $user) {
$avatarhtml = qa_get_user_avatar_html($user['flags'], $user['email'], $user['handle'],
$user['avatarblobid'], $user['avatarwidth'], $user['avatarheight'], qa_opt('avatar_users_size'), true);
$ranking['items'][] = array(
'avatar' => $avatarhtml,
'label' => $usershtml[$user['userid']],
'score' => qa_html(qa_format_number($user['points'], 0, true)),
'raw' => $user,
); );
foreach ($users as $user) {
$avatarhtml = qa_get_user_avatar_html($user['flags'], $user['email'], $user['handle'],
$user['avatarblobid'], $user['avatarwidth'], $user['avatarheight'], qa_opt('avatar_users_size'), true);
$ranking['items'][] = array(
'avatar' => $avatarhtml,
'label' => $usershtml[$user['userid']],
'score' => qa_html(qa_format_number($user['points'], 0, true)),
'raw' => $user,
);
}
return $ranking;
} }
return $ranking;
function qa_favorite_tags_view($tags) }
/*
Returns content to set in $qa_content['ranking_tags'] for a user's favorite $tags.
*/ /**
{ * Returns content to set in $qa_content['ranking_tags'] for a user's favorite $tags.
require_once QA_INCLUDE_DIR.'app/format.php'; * @param $tags
* @return array
$ranking = array( */
'items' => array(), function qa_favorite_tags_view($tags)
'rows' => ceil(count($tags)/qa_opt('columns_tags')), {
'type' => 'tags' require_once QA_INCLUDE_DIR . 'app/format.php';
$ranking = array(
'items' => array(),
'rows' => ceil(count($tags) / qa_opt('columns_tags')),
'type' => 'tags',
);
foreach ($tags as $tag) {
$ranking['items'][] = array(
'label' => qa_tag_html($tag['word'], false, true),
'count' => qa_html(qa_format_number($tag['tagcount'], 0, true)),
); );
foreach ($tags as $tag) {
$ranking['items'][] = array(
'label' => qa_tag_html($tag['word'], false, true),
'count' => qa_html(qa_format_number($tag['tagcount'], 0, true)),
);
}
return $ranking;
} }
return $ranking;
function qa_favorite_categories_view($categories) }
/*
Returns content to set in $qa_content['nav_list_categories'] for a user's favorite $categories.
*/ /**
{ * Returns content to set in $qa_content['nav_list_categories'] for a user's favorite $categories.
require_once QA_INCLUDE_DIR.'app/format.php'; * @param $categories
* @return array
$nav_list_categories = array( */
'nav' => array(), function qa_favorite_categories_view($categories)
'type' => 'browse-cat', {
require_once QA_INCLUDE_DIR . 'app/format.php';
$nav_list_categories = array(
'nav' => array(),
'type' => 'browse-cat',
);
foreach ($categories as $category) {
$cat_url = qa_path_html('questions/' . implode('/', array_reverse(explode('/', $category['backpath']))));
$cat_anchor = $category['qcount'] == 1
? qa_lang_html_sub('main/1_question', '1', '1')
: qa_lang_html_sub('main/x_questions', qa_format_number($category['qcount'], 0, true));
$cat_descr = strlen($category['content']) ? qa_html(' - ' . $category['content']) : '';
$nav_list_categories['nav'][$category['categoryid']] = array(
'label' => qa_html($category['title']),
'state' => 'open',
'favorited' => true,
'note' => ' - <a href="' . $cat_url . '">' . $cat_anchor . '</a>' . $cat_descr,
); );
foreach ($categories as $category) {
$cat_url = qa_path_html( 'questions/' . implode( '/', array_reverse(explode('/', $category['backpath'])) ) );
$cat_anchor = $category['qcount'] == 1
? qa_lang_html_sub('main/1_question', '1', '1')
: qa_lang_html_sub('main/x_questions', qa_format_number($category['qcount'], 0, true));
$cat_descr = strlen($category['content']) ? qa_html(' - '.$category['content']) : '';
$nav_list_categories['nav'][$category['categoryid']] = array(
'label' => qa_html($category['title']),
'state' => 'open',
'favorited' => true,
'note' => ' - <a href="'.$cat_url.'">'.$cat_anchor.'</a>'.$cat_descr,
);
}
return $nav_list_categories;
} }
return $nav_list_categories;
/* }
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -133,8 +133,8 @@ function qa_limits_calc_remaining($action, $userlimits, $iplimits) ...@@ -133,8 +133,8 @@ function qa_limits_calc_remaining($action, $userlimits, $iplimits)
$period = (int)(qa_opt('db_time') / 3600); $period = (int)(qa_opt('db_time') / 3600);
return max(0, min( return max(0, min(
$usermax - ((@$userlimits['period'] == $period) ? $userlimits['count'] : 0), $usermax - (@$userlimits['period'] == $period ? $userlimits['count'] : 0),
$ipmax - ((@$iplimits['period'] == $period) ? $iplimits['count'] : 0) $ipmax - (@$iplimits['period'] == $period ? $iplimits['count'] : 0)
)); ));
} }
...@@ -229,7 +229,7 @@ function qa_ip_between($ip, $startip, $endip) ...@@ -229,7 +229,7 @@ function qa_ip_between($ip, $startip, $endip)
if (count($uip) != count($ustartip) || count($uip) != count($uendip)) if (count($uip) != count($ustartip) || count($uip) != count($uendip))
return false; return false;
foreach ($uip as $i=>$byte) { foreach ($uip as $i => $byte) {
if ($byte < $ustartip[$i] || $byte > $uendip[$i]) { if ($byte < $ustartip[$i] || $byte > $uendip[$i]) {
return false; return false;
} }
......
...@@ -20,135 +20,138 @@ ...@@ -20,135 +20,138 @@
More about this license: http://www.question2answer.org/license.php 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: ../'); header('Location: ../');
exit; exit;
}
/**
* Start a mailing to all users, unless one has already been started
*/
function qa_mailing_start()
{
require_once QA_INCLUDE_DIR . 'db/admin.php';
if (strlen(qa_opt('mailing_last_userid')) == 0) {
qa_opt('mailing_last_timestamp', time());
qa_opt('mailing_last_userid', '0');
qa_opt('mailing_total_users', qa_db_count_users());
qa_opt('mailing_done_users', 0);
} }
}
function qa_mailing_start() /**
/* * Stop a mailing to all users
Start a mailing to all users, unless one has already been started */
*/ function qa_mailing_stop()
{ {
require_once QA_INCLUDE_DIR.'db/admin.php'; qa_opt('mailing_last_timestamp', '');
qa_opt('mailing_last_userid', '');
if (strlen(qa_opt('mailing_last_userid'))==0) { qa_opt('mailing_done_users', '');
qa_opt('mailing_last_timestamp', time()); qa_opt('mailing_total_users', '');
qa_opt('mailing_last_userid', '0'); }
qa_opt('mailing_total_users', qa_db_count_users());
qa_opt('mailing_done_users', 0);
}
}
function qa_mailing_stop() /**
/* * Allow the mailing to proceed forwards, for the appropriate amount of time and users, based on the options
Stop a mailing to all users */
*/ function qa_mailing_perform_step()
{ {
qa_opt('mailing_last_timestamp', ''); require_once QA_INCLUDE_DIR . 'db/users.php';
qa_opt('mailing_last_userid', '');
qa_opt('mailing_done_users', '');
qa_opt('mailing_total_users', '');
}
$lastuserid = qa_opt('mailing_last_userid');
function qa_mailing_perform_step() if (strlen($lastuserid)) {
/* $thistime = time();
Allow the mailing to proceed forwards, for the appropriate amount of time and users, based on the options $lasttime = qa_opt('mailing_last_timestamp');
*/ $perminute = qa_opt('mailing_per_minute');
{
require_once QA_INCLUDE_DIR.'db/users.php';
$lastuserid=qa_opt('mailing_last_userid');
if (strlen($lastuserid)) { if (($lasttime - $thistime) > 60) // if it's been a while, we assume there hasn't been continuous mailing...
$thistime=time(); $lasttime = $thistime - 1; // ... so only do 1 second's worth
$lasttime=qa_opt('mailing_last_timestamp'); else // otherwise...
$perminute=qa_opt('mailing_per_minute'); $lasttime = max($lasttime, $thistime - 6); // ... don't do more than 6 seconds' worth
if (($lasttime-$thistime)>60) // if it's been a while, we assume there hasn't been continuous mailing... $count = min(floor(($thistime - $lasttime) * $perminute / 60), 100); // don't do more than 100 messages at a time
$lasttime=$thistime-1; // ... so only do 1 second's worth
else // otherwise...
$lasttime=max($lasttime, $thistime-6); // ... don't do more than 6 seconds' worth
$count=min(floor(($thistime-$lasttime)*$perminute/60), 100); // don't do more than 100 messages at a time if ($count > 0) {
qa_opt('mailing_last_timestamp', $thistime + 30);
// prevents a parallel call to qa_mailing_perform_step() from sending messages, unless we're very unlucky with timing (poor man's mutex)
if ($count>0) { $sentusers = 0;
qa_opt('mailing_last_timestamp', $thistime+30); $users = qa_db_users_get_mailing_next($lastuserid, $count);
// prevents a parallel call to qa_mailing_perform_step() from sending messages, unless we're very unlucky with timing (poor man's mutex)
$sentusers=0; if (count($users)) {
$users=qa_db_users_get_mailing_next($lastuserid, $count); foreach ($users as $user) {
$lastuserid = max($lastuserid, $user['userid']);
}
if (count($users)) { qa_opt('mailing_last_userid', $lastuserid);
foreach ($users as $user) qa_opt('mailing_done_users', qa_opt('mailing_done_users') + count($users));
$lastuserid=max($lastuserid, $user['userid']);
qa_opt('mailing_last_userid', $lastuserid); foreach ($users as $user) {
qa_opt('mailing_done_users', qa_opt('mailing_done_users')+count($users)); if (!($user['flags'] & QA_USER_FLAGS_NO_MAILINGS)) {
qa_mailing_send_one($user['userid'], $user['handle'], $user['email'], $user['emailcode']);
$sentusers++;
}
}
foreach ($users as $user) qa_opt('mailing_last_timestamp', $lasttime + $sentusers * 60 / $perminute); // can be floating point result, based on number of mails actually sent
if (!($user['flags'] & QA_USER_FLAGS_NO_MAILINGS)) {
qa_mailing_send_one($user['userid'], $user['handle'], $user['email'], $user['emailcode']);
$sentusers++;
}
qa_opt('mailing_last_timestamp', $lasttime+$sentusers*60/$perminute); // can be floating point result, based on number of mails actually sent } else
qa_mailing_stop();
} else
qa_mailing_stop();
}
} }
} }
}
function qa_mailing_send_one($userid, $handle, $email, $emailcode)
/* /**
Send a single message from the mailing, to $userid with $handle and $email. * Send a single message from the mailing, to $userid with $handle and $email.
Pass the user's existing $emailcode if there is one, otherwise a new one will be set up * Pass the user's existing $emailcode if there is one, otherwise a new one will be set up
*/ * @param $userid
{ * @param $handle
require_once QA_INCLUDE_DIR.'app/emails.php'; * @param $email
require_once QA_INCLUDE_DIR.'db/users.php'; * @param $emailcode
* @return bool
if (!strlen(trim($emailcode))) { */
$emailcode=qa_db_user_rand_emailcode(); function qa_mailing_send_one($userid, $handle, $email, $emailcode)
qa_db_user_set($userid, 'emailcode', $emailcode); {
} require_once QA_INCLUDE_DIR . 'app/emails.php';
require_once QA_INCLUDE_DIR . 'db/users.php';
$unsubscribeurl=qa_path_absolute('unsubscribe', array('c' => $emailcode, 'u' => $handle));
if (!strlen(trim($emailcode))) {
return qa_send_email(array( $emailcode = qa_db_user_rand_emailcode();
'fromemail' => qa_opt('mailing_from_email'), qa_db_user_set($userid, 'emailcode', $emailcode);
'fromname' => qa_opt('mailing_from_name'),
'toemail' => $email,
'toname' => $handle,
'subject' => qa_opt('mailing_subject'),
'body' => trim(qa_opt('mailing_body'))."\n\n\n".qa_lang('users/unsubscribe').' '.$unsubscribeurl,
'html' => false,
));
} }
$unsubscribeurl = qa_path_absolute('unsubscribe', array('c' => $emailcode, 'u' => $handle));
function qa_mailing_progress_message()
/* return qa_send_email(array(
Return a message describing current progress in the mailing 'fromemail' => qa_opt('mailing_from_email'),
*/ 'fromname' => qa_opt('mailing_from_name'),
{ 'toemail' => $email,
require_once QA_INCLUDE_DIR . 'app/format.php'; 'toname' => $handle,
'subject' => qa_opt('mailing_subject'),
if (strlen(qa_opt('mailing_last_userid'))) 'body' => trim(qa_opt('mailing_body')) . "\n\n\n" . qa_lang('users/unsubscribe') . ' ' . $unsubscribeurl,
return strtr(qa_lang('admin/mailing_progress'), array( 'html' => false,
'^1' => qa_format_number(qa_opt('mailing_done_users')), ));
'^2' => qa_format_number(qa_opt('mailing_total_users')), }
));
else
return null; /**
* Return a message describing current progress in the mailing
*/
function qa_mailing_progress_message()
{
require_once QA_INCLUDE_DIR . 'app/format.php';
if (strlen(qa_opt('mailing_last_userid'))) {
return strtr(qa_lang('admin/mailing_progress'), array(
'^1' => qa_format_number(qa_opt('mailing_done_users')),
'^2' => qa_format_number(qa_opt('mailing_total_users')),
));
} }
return null;
/* }
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -20,184 +20,208 @@ ...@@ -20,184 +20,208 @@
More about this license: http://www.question2answer.org/license.php 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: ../'); header('Location: ../');
exit; exit;
} }
function qa_wall_error_html($fromuserid, $touserid, $touserflags) /**
/* * Returns an HTML string describing the reason why user $fromuserid cannot post on the wall of $touserid who has
Returns an HTML string describing the reason why user $fromuserid cannot post on the wall of $touserid who has * user flags $touserflags. If there is no such reason the function returns false.
user flags $touserflags. If there is no such reason the function returns false. * @param $fromuserid
*/ * @param $touserid
{ * @param $touserflags
require_once QA_INCLUDE_DIR.'app/limits.php'; * @return bool|mixed|string
*/
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } function qa_wall_error_html($fromuserid, $touserid, $touserflags)
{
if (!QA_FINAL_EXTERNAL_USERS && qa_opt('allow_user_walls')) { require_once QA_INCLUDE_DIR . 'app/limits.php';
if ( ($touserflags & QA_USER_FLAGS_NO_WALL_POSTS) && !(isset($fromuserid) && $fromuserid == $touserid) )
return qa_lang_html('profile/post_wall_blocked'); if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
else { if (!QA_FINAL_EXTERNAL_USERS && qa_opt('allow_user_walls')) {
switch (qa_user_permit_error('permit_post_wall', QA_LIMIT_WALL_POSTS)) { if (($touserflags & QA_USER_FLAGS_NO_WALL_POSTS) && !(isset($fromuserid) && $fromuserid == $touserid))
case 'limit': return qa_lang_html('profile/post_wall_blocked');
return qa_lang_html('profile/post_wall_limit');
break; else {
switch (qa_user_permit_error('permit_post_wall', QA_LIMIT_WALL_POSTS)) {
case 'login': case 'limit':
return qa_insert_login_links(qa_lang_html('profile/post_wall_must_login'), qa_request()); return qa_lang_html('profile/post_wall_limit');
break; break;
case 'confirm': case 'login':
return qa_insert_login_links(qa_lang_html('profile/post_wall_must_confirm'), qa_request()); return qa_insert_login_links(qa_lang_html('profile/post_wall_must_login'), qa_request());
break; break;
case 'approve': case 'confirm':
return qa_lang_html('profile/post_wall_must_be_approved'); return qa_insert_login_links(qa_lang_html('profile/post_wall_must_confirm'), qa_request());
break; break;
case false: case 'approve':
return false; return qa_lang_html('profile/post_wall_must_be_approved');
break; break;
}
case false:
return false;
break;
} }
} }
return qa_lang_html('users/no_permission');
} }
return qa_lang_html('users/no_permission');
function qa_wall_add_post($userid, $handle, $cookieid, $touserid, $tohandle, $content, $format) }
/*
Adds a post to the wall of user $touserid with handle $tohandle, containing $content in $format (e.g. '' for text or 'html')
The post is by user $userid with handle $handle, and $cookieid is the user's current cookie (used for reporting the event). /**
*/ * Adds a post to the wall of user $touserid with handle $tohandle, containing $content in $format (e.g. '' for text or 'html')
{ * The post is by user $userid with handle $handle, and $cookieid is the user's current cookie (used for reporting the event).
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } * @param $userid
* @param $handle
require_once QA_INCLUDE_DIR.'app/format.php'; * @param $cookieid
require_once QA_INCLUDE_DIR.'db/messages.php'; * @param $touserid
* @param $tohandle
$messageid = qa_db_message_create($userid, $touserid, $content, $format, true); * @param $content
qa_db_user_recount_posts($touserid); * @param $format
* @return mixed
qa_report_event('u_wall_post', $userid, $handle, $cookieid, array( */
'userid' => $touserid, function qa_wall_add_post($userid, $handle, $cookieid, $touserid, $tohandle, $content, $format)
'handle' => $tohandle, {
'messageid' => $messageid, if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
'content' => $content,
'format' => $format, require_once QA_INCLUDE_DIR . 'app/format.php';
'text' => qa_viewer_text($content, $format), require_once QA_INCLUDE_DIR . 'db/messages.php';
));
$messageid = qa_db_message_create($userid, $touserid, $content, $format, true);
return $messageid; qa_db_user_recount_posts($touserid);
}
qa_report_event('u_wall_post', $userid, $handle, $cookieid, array(
'userid' => $touserid,
function qa_wall_delete_post($userid, $handle, $cookieid, $message) 'handle' => $tohandle,
/* 'messageid' => $messageid,
Deletes the wall post described in $message (as obtained via qa_db_recent_messages_selectspec()). The deletion was performed 'content' => $content,
by user $userid with handle $handle, and $cookieid is the user's current cookie (all used for reporting the event). 'format' => $format,
*/ 'text' => qa_viewer_text($content, $format),
{ ));
require_once QA_INCLUDE_DIR.'db/messages.php';
return $messageid;
qa_db_message_delete($message['messageid']); }
qa_db_user_recount_posts($message['touserid']);
qa_report_event('u_wall_delete', $userid, $handle, $cookieid, array( /**
'messageid' => $message['messageid'], * Deletes the wall post described in $message (as obtained via qa_db_recent_messages_selectspec()). The deletion was performed
'oldmessage' => $message, * by user $userid with handle $handle, and $cookieid is the user's current cookie (all used for reporting the event).
)); * @param $userid
* @param $handle
* @param $cookieid
* @param $message
*/
function qa_wall_delete_post($userid, $handle, $cookieid, $message)
{
require_once QA_INCLUDE_DIR . 'db/messages.php';
qa_db_message_delete($message['messageid']);
qa_db_user_recount_posts($message['touserid']);
qa_report_event('u_wall_delete', $userid, $handle, $cookieid, array(
'messageid' => $message['messageid'],
'oldmessage' => $message,
));
}
/**
* Return the list of messages in $usermessages (as obtained via qa_db_recent_messages_selectspec()) with additional
* fields indicating what actions can be performed on them by the current user. The messages were retrieved beginning
* at offset $start in the database. Currently only 'deleteable' is relevant.
* @param $usermessages
* @param $start
* @return mixed
*/
function qa_wall_posts_add_rules($usermessages, $start)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$userid = qa_get_logged_in_userid();
// reuse "Hiding or showing any post" and "Deleting hidden posts" permissions
$userdeleteall = !(qa_user_permit_error('permit_hide_show') || qa_user_permit_error('permit_delete_hidden'));
$userrecent = $start == 0 && isset($userid); // User can delete all of the recent messages they wrote on someone's wall...
foreach ($usermessages as $key => $message) {
if ($message['fromuserid'] != $userid)
$userrecent = false; // ... until we come across one that they didn't write (which could be a reply)
$usermessages[$key]['deleteable'] =
$message['touserid'] == $userid || // if it's this user's wall
($userrecent && $message['fromuserid'] == $userid) || // if it's one the user wrote that no one replied to yet
$userdeleteall; // if the user has enough permissions to delete from any wall
} }
return $usermessages;
}
function qa_wall_posts_add_rules($usermessages, $start)
/*
Return the list of messages in $usermessages (as obtained via qa_db_recent_messages_selectspec()) with additional
fields indicating what actions can be performed on them by the current user. The messages were retrieved beginning
at offset $start in the database. Currently only 'deleteable' is relevant.
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$userid = qa_get_logged_in_userid();
$userdeleteall = !(qa_user_permit_error('permit_hide_show') || qa_user_permit_error('permit_delete_hidden'));
// reuse "Hiding or showing any post" and "Deleting hidden posts" permissions
$userrecent = $start == 0 && isset($userid); // User can delete all of the recent messages they wrote on someone's wall...
foreach ($usermessages as $key => $message) {
if ($message['fromuserid'] != $userid)
$userrecent = false; // ... until we come across one that they didn't write (which could be a reply)
$usermessages[$key]['deleteable'] =
$message['touserid'] == $userid || // if it's this user's wall
($userrecent && $message['fromuserid'] == $userid) || // if it's one the user wrote that no one replied to yet
$userdeleteall; // if the user has enough permissions to delete from any wall
}
return $usermessages; /**
} * Returns an element to add to $qa_content['message_list']['messages'] for $message (as obtained via
* qa_db_recent_messages_selectspec() and then qa_wall_posts_add_rules()).
* @param $message
* @return array
*/
function qa_wall_post_view($message)
{
require_once QA_INCLUDE_DIR . 'app/format.php';
$options = qa_message_html_defaults();
function qa_wall_post_view($message) $htmlfields = qa_message_html_fields($message, $options);
/*
Returns an element to add to $qa_content['message_list']['messages'] for $message (as obtained via
qa_db_recent_messages_selectspec() and then qa_wall_posts_add_rules()).
*/
{
require_once QA_INCLUDE_DIR.'app/format.php';
$options = qa_message_html_defaults();
$htmlfields = qa_message_html_fields($message, $options);
if ($message['deleteable']) { if ($message['deleteable']) {
$htmlfields['form'] = array( $htmlfields['form'] = array(
'style' => 'light', 'style' => 'light',
'buttons' => array( 'buttons' => array(
'delete' => array( 'delete' => array(
'tags' => 'name="m'.qa_html($message['messageid']).'_dodelete" onclick="return qa_wall_post_click('.qa_js($message['messageid']).', this);"', 'tags' => 'name="m' . qa_html($message['messageid']) . '_dodelete" onclick="return qa_wall_post_click(' . qa_js($message['messageid']) . ', this);"',
'label' => qa_lang_html('question/delete_button'), 'label' => qa_lang_html('question/delete_button'),
'popup' => qa_lang_html('profile/delete_wall_post_popup'), 'popup' => qa_lang_html('profile/delete_wall_post_popup'),
),
), ),
); ),
}
return $htmlfields;
}
function qa_wall_view_more_link($handle, $start)
/*
Returns an element to add to $qa_content['message_list']['messages'] with a link to view all wall posts
*/
{
$url = qa_path_html( 'user/'.$handle.'/wall', array('start' => $start) );
return array(
'content' => '<a href="'.$url.'">'.qa_lang_html('profile/wall_view_more').'</a>',
); );
} }
return $htmlfields;
function qa_pm_delete($userid, $handle, $cookieid, $message, $box) }
/*
Hides the private message described in $message (as obtained via qa_db_messages_inbox_selectspec() or qa_db_messages_outbox_selectspec()).
If both sender and receiver have hidden the message, it gets deleted from the database. /**
Note: currently no event is reported here, so $handle/$cookieid are unused. * Returns an element to add to $qa_content['message_list']['messages'] with a link to view all wall posts
*/ * @param $handle
{ * @param $start
require_once QA_INCLUDE_DIR.'db/messages.php'; * @return array
*/
qa_db_message_user_hide($message['messageid'], $box); function qa_wall_view_more_link($handle, $start)
qa_db_message_delete($message['messageid'], false); {
} $url = qa_path_html('user/' . $handle . '/wall', array('start' => $start));
return array(
'content' => '<a href="' . $url . '">' . qa_lang_html('profile/wall_view_more') . '</a>',
/* );
Omit PHP closing tag to help avoid accidental output }
*/
\ No newline at end of file
/**
* Hides the private message described in $message (as obtained via qa_db_messages_inbox_selectspec() or qa_db_messages_outbox_selectspec()).
* If both sender and receiver have hidden the message, it gets deleted from the database.
* Note: currently no event is reported here, so $handle/$cookieid are unused.
* @param $userid
* @param $handle
* @param $cookieid
* @param $message
* @param $box
*/
function qa_pm_delete($userid, $handle, $cookieid, $message, $box)
{
require_once QA_INCLUDE_DIR . 'db/messages.php';
qa_db_message_user_hide($message['messageid'], $box);
qa_db_message_delete($message['messageid'], false);
}
...@@ -20,782 +20,809 @@ ...@@ -20,782 +20,809 @@
More about this license: http://www.question2answer.org/license.php 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: ../'); header('Location: ../');
exit; exit;
}
require_once QA_INCLUDE_DIR . 'db/options.php';
define('QA_PERMIT_ALL', 150);
define('QA_PERMIT_USERS', 120);
define('QA_PERMIT_CONFIRMED', 110);
define('QA_PERMIT_POINTS', 106);
define('QA_PERMIT_POINTS_CONFIRMED', 104);
define('QA_PERMIT_APPROVED', 103);
define('QA_PERMIT_APPROVED_POINTS', 102);
define('QA_PERMIT_EXPERTS', 100);
define('QA_PERMIT_EDITORS', 70);
define('QA_PERMIT_MODERATORS', 40);
define('QA_PERMIT_ADMINS', 20);
define('QA_PERMIT_SUPERS', 0);
/**
* Return an array [name] => [value] of settings for each option in $names.
* If any options are missing from the database, set them to their defaults
* @param $names
* @return array
*/
function qa_get_options($names)
{
global $qa_options_cache, $qa_options_loaded;
// If any options not cached, retrieve them from database via standard pending mechanism
if (!$qa_options_loaded)
qa_preload_options();
if (!$qa_options_loaded) {
require_once QA_INCLUDE_DIR . 'db/selects.php';
qa_load_options_results(array(
qa_db_get_pending_result('options'),
qa_db_get_pending_result('time'),
));
} }
require_once QA_INCLUDE_DIR.'db/options.php'; // Pull out the options specifically requested here, and assign defaults
define('QA_PERMIT_ALL', 150); $options = array();
define('QA_PERMIT_USERS', 120); foreach ($names as $name) {
define('QA_PERMIT_CONFIRMED', 110); if (!isset($qa_options_cache[$name])) {
define('QA_PERMIT_POINTS', 106); $todatabase = true;
define('QA_PERMIT_POINTS_CONFIRMED', 104);
define('QA_PERMIT_APPROVED', 103);
define('QA_PERMIT_APPROVED_POINTS', 102);
define('QA_PERMIT_EXPERTS', 100);
define('QA_PERMIT_EDITORS', 70);
define('QA_PERMIT_MODERATORS', 40);
define('QA_PERMIT_ADMINS', 20);
define('QA_PERMIT_SUPERS', 0);
switch ($name) { // don't write default to database if option was deprecated, or depends on site language (which could be changed)
function qa_get_options($names) case 'custom_sidebar':
/* case 'site_title':
Return an array [name] => [value] of settings for each option in $names. case 'email_privacy':
If any options are missing from the database, set them to their defaults case 'answer_needs_login':
*/ case 'ask_needs_login':
{ case 'comment_needs_login':
global $qa_options_cache, $qa_options_loaded; case 'db_time':
$todatabase = false;
// If any options not cached, retrieve them from database via standard pending mechanism break;
if (!$qa_options_loaded)
qa_preload_options();
if (!$qa_options_loaded) {
require_once QA_INCLUDE_DIR.'db/selects.php';
qa_load_options_results(array(
qa_db_get_pending_result('options'),
qa_db_get_pending_result('time'),
));
}
// Pull out the options specifically requested here, and assign defaults
$options=array();
foreach ($names as $name) {
if (!isset($qa_options_cache[$name])) {
$todatabase=true;
switch ($name) { // don't write default to database if option was deprecated, or depends on site language (which could be changed)
case 'custom_sidebar':
case 'site_title':
case 'email_privacy':
case 'answer_needs_login':
case 'ask_needs_login':
case 'comment_needs_login':
case 'db_time':
$todatabase=false;
break;
}
qa_set_option($name, qa_default_option($name), $todatabase);
} }
$options[$name]=$qa_options_cache[$name]; qa_set_option($name, qa_default_option($name), $todatabase);
} }
return $options; $options[$name] = $qa_options_cache[$name];
} }
return $options;
}
/**
* Return the value of option $name if it has already been loaded, otherwise return null
* (used to prevent a database query if it's not essential for us to know the option value)
* @param $name
* @return
*/
function qa_opt_if_loaded($name)
{
global $qa_options_cache;
return @$qa_options_cache[$name];
}
/**
* @deprecated Deprecated since Q2A 1.3 now that all options are retrieved together.
* @param $names
*/
function qa_options_set_pending($names)
{
}
/**
* Load all of the Q2A options from the database, unless QA_OPTIMIZE_DISTANT_DB is set in qa-config.php,
* in which case queue the options for later retrieval
*/
function qa_preload_options()
{
global $qa_options_loaded;
if (!@$qa_options_loaded) {
$selectspecs = array(
'options' => array(
'columns' => array('title', 'content'),
'source' => '^options',
'arraykey' => 'title',
'arrayvalue' => 'content',
),
'time' => array(
'columns' => array('title' => "'db_time'", 'content' => 'UNIX_TIMESTAMP(NOW())'),
'arraykey' => 'title',
'arrayvalue' => 'content',
),
);
function qa_opt_if_loaded($name) // fetch options in a separate query before everything else
/* qa_load_options_results(qa_db_multi_select($selectspecs));
Return the value of option $name if it has already been loaded, otherwise return null
(used to prevent a database query if it's not essential for us to know the option value)
*/
{
global $qa_options_cache;
return @$qa_options_cache[$name];
} }
}
/** /**
* @deprecated Deprecated since Q2A 1.3 now that all options are retrieved together. * Load the options from the $results of the database selectspecs defined in qa_preload_options()
*/ * @param $results
function qa_options_set_pending($names) * @return mixed
{ */
} function qa_load_options_results($results)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
global $qa_options_cache, $qa_options_loaded;
function qa_preload_options() foreach ($results as $result) {
/* foreach ($result as $name => $value) {
Load all of the Q2A options from the database, unless QA_OPTIMIZE_DISTANT_DB is set in qa-config.php, $qa_options_cache[$name] = $value;
in which case queue the options for later retrieval
*/
{
global $qa_options_loaded;
if (!@$qa_options_loaded) {
$selectspecs=array(
'options' => array(
'columns' => array('title', 'content'),
'source' => '^options',
'arraykey' => 'title',
'arrayvalue' => 'content',
),
'time' => array(
'columns' => array('title' => "'db_time'", 'content' => 'UNIX_TIMESTAMP(NOW())'),
'arraykey' => 'title',
'arrayvalue' => 'content',
),
);
// fetch options in a separate query before everything else
qa_load_options_results(qa_db_multi_select($selectspecs));
} }
} }
$qa_options_loaded = true;
}
function qa_load_options_results($results)
/*
Load the options from the $results of the database selectspecs defined in qa_preload_options()
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
global $qa_options_cache, $qa_options_loaded; /**
* Set an option $name to $value (application level) in both cache and database, unless
* $todatabase=false, in which case set it in the cache only
* @param $name
* @param $value
* @param bool $todatabase
* @return mixed
*/
function qa_set_option($name, $value, $todatabase = true)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
foreach ($results as $result) global $qa_options_cache;
foreach ($result as $name => $value)
$qa_options_cache[$name]=$value;
$qa_options_loaded=true;
}
if ($todatabase && isset($value))
qa_db_set_option($name, $value);
function qa_set_option($name, $value, $todatabase=true) $qa_options_cache[$name] = $value;
/* }
Set an option $name to $value (application level) in both cache and database, unless
$todatabase=false, in which case set it in the cache only
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
global $qa_options_cache;
if ($todatabase && isset($value)) /**
qa_db_set_option($name, $value); * Reset the options in $names to their defaults
* @param $names
* @return mixed
*/
function qa_reset_options($names)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$qa_options_cache[$name]=$value; foreach ($names as $name) {
qa_set_option($name, qa_default_option($name));
} }
}
function qa_reset_options($names)
/* /**
Reset the options in $names to their defaults * Return the default value for option $name
*/ * @param $name
{ * @return bool|mixed|string
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } */
function qa_default_option($name)
foreach ($names as $name) {
qa_set_option($name, qa_default_option($name)); if (qa_to_override(__FUNCTION__)) {
$args = func_get_args();
return qa_call_override(__FUNCTION__, $args);
} }
$fixed_defaults = array(
'allow_change_usernames' => 1,
'allow_close_questions' => 1,
'allow_multi_answers' => 1,
'allow_private_messages' => 1,
'allow_user_walls' => 1,
'allow_self_answer' => 1,
'allow_view_q_bots' => 1,
'avatar_allow_gravatar' => 1,
'avatar_allow_upload' => 1,
'avatar_message_list_size' => 20,
'avatar_profile_size' => 200,
'avatar_q_list_size' => 0,
'avatar_q_page_a_size' => 40,
'avatar_q_page_c_size' => 20,
'avatar_q_page_q_size' => 50,
'avatar_store_size' => 400,
'avatar_users_size' => 30,
'caching_catwidget_time' => 30,
'caching_enabled' => 0,
'caching_q_start' => 7,
'caching_q_time' => 30,
'caching_qlist_time' => 5,
'captcha_on_anon_post' => 1,
'captcha_on_feedback' => 1,
'captcha_on_register' => 1,
'captcha_on_reset_password' => 1,
'captcha_on_unconfirmed' => 0,
'columns_tags' => 3,
'columns_users' => 2,
'comment_on_as' => 1,
'comment_on_qs' => 0,
'confirm_user_emails' => 1,
'do_ask_check_qs' => 0,
'do_complete_tags' => 1,
'do_count_q_views' => 1,
'do_example_tags' => 1,
'feed_for_activity' => 1,
'feed_for_qa' => 1,
'feed_for_questions' => 1,
'feed_for_unanswered' => 1,
'feed_full_text' => 1,
'feed_number_items' => 50,
'feed_per_category' => 1,
'feedback_enabled' => 1,
'flagging_hide_after' => 5,
'flagging_notify_every' => 2,
'flagging_notify_first' => 1,
'flagging_of_posts' => 1,
'follow_on_as' => 1,
'hot_weight_a_age' => 100,
'hot_weight_answers' => 100,
'hot_weight_q_age' => 100,
'hot_weight_views' => 100,
'hot_weight_votes' => 100,
'mailing_per_minute' => 500,
'match_ask_check_qs' => 3,
'match_example_tags' => 3,
'match_related_qs' => 3,
'max_copy_user_updates' => 10,
'max_len_q_title' => 120,
'max_num_q_tags' => 5,
'max_rate_ip_as' => 50,
'max_rate_ip_cs' => 40,
'max_rate_ip_flags' => 10,
'max_rate_ip_logins' => 20,
'max_rate_ip_messages' => 10,
'max_rate_ip_qs' => 20,
'max_rate_ip_registers' => 5,
'max_rate_ip_uploads' => 20,
'max_rate_ip_votes' => 600,
'max_rate_user_as' => 25,
'max_rate_user_cs' => 20,
'max_rate_user_flags' => 5,
'max_rate_user_messages' => 5,
'max_rate_user_qs' => 10,
'max_rate_user_uploads' => 10,
'max_rate_user_votes' => 300,
'max_store_user_updates' => 50,
'min_len_a_content' => 12,
'min_len_c_content' => 12,
'min_len_q_content' => 0,
'min_len_q_title' => 12,
'min_num_q_tags' => 0,
'minify_html' => 1,
'moderate_notify_admin' => 1,
'moderate_points_limit' => 150,
'moderate_update_time' => 1,
'nav_ask' => 1,
'nav_qa_not_home' => 1,
'nav_questions' => 1,
'nav_tags' => 1,
'nav_unanswered' => 1,
'nav_users' => 1,
'neat_urls' => QA_URL_FORMAT_SAFEST,
'notify_users_default' => 1,
'page_size_activity' => 20,
'page_size_ask_check_qs' => 5,
'page_size_ask_tags' => 5,
'page_size_home' => 20,
'page_size_hot_qs' => 20,
'page_size_pms' => 10,
'page_size_q_as' => 10,
'page_size_qs' => 20,
'page_size_related_qs' => 5,
'page_size_search' => 10,
'page_size_tag_qs' => 20,
'page_size_tags' => 30,
'page_size_una_qs' => 20,
'page_size_users' => 30,
'page_size_wall' => 10,
'pages_prev_next' => 3,
'permit_anon_view_ips' => QA_PERMIT_EDITORS,
'permit_close_q' => QA_PERMIT_EDITORS,
'permit_delete_hidden' => QA_PERMIT_MODERATORS,
'permit_edit_a' => QA_PERMIT_EXPERTS,
'permit_edit_c' => QA_PERMIT_EDITORS,
'permit_edit_q' => QA_PERMIT_EDITORS,
'permit_edit_silent' => QA_PERMIT_MODERATORS,
'permit_flag' => QA_PERMIT_CONFIRMED,
'permit_hide_show' => QA_PERMIT_EDITORS,
'permit_moderate' => QA_PERMIT_EXPERTS,
'permit_post_wall' => QA_PERMIT_CONFIRMED,
'permit_select_a' => QA_PERMIT_EXPERTS,
'permit_view_q_page' => QA_PERMIT_ALL,
'permit_view_new_users_page' => QA_PERMIT_EDITORS,
'permit_view_special_users_page' => QA_PERMIT_MODERATORS,
'permit_view_voters_flaggers' => QA_PERMIT_ADMINS,
'permit_vote_a' => QA_PERMIT_USERS,
'permit_vote_down' => QA_PERMIT_USERS,
'permit_vote_q' => QA_PERMIT_USERS,
'points_a_selected' => 30,
'points_a_voted_max_gain' => 20,
'points_a_voted_max_loss' => 5,
'points_base' => 100,
'points_multiple' => 10,
'points_post_a' => 4,
'points_post_q' => 2,
'points_q_voted_max_gain' => 10,
'points_q_voted_max_loss' => 3,
'points_select_a' => 3,
'q_urls_title_length' => 50,
'show_a_c_links' => 1,
'show_a_form_immediate' => 'if_no_as',
'show_c_reply_buttons' => 1,
'show_compact_numbers' => 1,
'show_custom_welcome' => 0,
'show_post_update_meta' => 1,
'show_fewer_cs_count' => 5,
'show_fewer_cs_from' => 10,
'show_full_date_days' => 7,
'show_message_history' => 1,
'show_register_terms' => 0,
'show_selected_first' => 1,
'show_url_links' => 1,
'show_user_points' => 1,
'show_user_titles' => 1,
'show_when_created' => 1,
'site_text_direction' => 'ltr',
'site_theme' => 'Snow',
'smtp_port' => 25,
'sort_answers_by' => 'created',
'tags_or_categories' => 'tc',
'use_microdata' => 1,
'voting_on_as' => 1,
'voting_on_qs' => 1,
);
if (isset($fixed_defaults[$name])) {
return $fixed_defaults[$name];
}
function qa_default_option($name) switch ($name) {
/* case 'site_url':
Return the default value for option $name $value = 'http://' . @$_SERVER['HTTP_HOST'] . strtr(rtrim(dirname($_SERVER['SCRIPT_NAME']), '/'), '\\', '/') . '/';
*/ break;
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } case 'site_title':
$value = qa_default_site_title();
$fixed_defaults=array( break;
'allow_change_usernames' => 1,
'allow_close_questions' => 1, case 'site_theme_mobile':
'allow_multi_answers' => 1, $value = qa_opt('site_theme');
'allow_private_messages' => 1, break;
'allow_user_walls' => 1,
'allow_self_answer' => 1, case 'from_email': // heuristic to remove short prefix (e.g. www. or qa.)
'allow_view_q_bots' => 1, $parts = explode('.', @$_SERVER['HTTP_HOST']);
'avatar_allow_gravatar' => 1,
'avatar_allow_upload' => 1, if ((count($parts) > 2) && (strlen($parts[0]) < 5) && !is_numeric($parts[0]))
'avatar_message_list_size' => 20, unset($parts[0]);
'avatar_profile_size' => 200,
'avatar_q_list_size' => 0, $value = 'no-reply@' . ((count($parts) > 1) ? implode('.', $parts) : 'example.com');
'avatar_q_page_a_size' => 40, break;
'avatar_q_page_c_size' => 20,
'avatar_q_page_q_size' => 50, case 'email_privacy':
'avatar_store_size' => 400, $value = qa_lang_html('options/default_privacy');
'avatar_users_size' => 30, break;
'caching_catwidget_time' => 30,
'caching_enabled' => 0, case 'show_custom_sidebar':
'caching_q_start' => 7, $value = strlen(qa_opt('custom_sidebar')) > 0;
'caching_q_time' => 30, break;
'caching_qlist_time' => 5,
'captcha_on_anon_post' => 1, case 'show_custom_header':
'captcha_on_feedback' => 1, $value = strlen(qa_opt('custom_header')) > 0;
'captcha_on_register' => 1, break;
'captcha_on_reset_password' => 1,
'captcha_on_unconfirmed' => 0, case 'show_custom_footer':
'columns_tags' => 3, $value = strlen(qa_opt('custom_footer')) > 0;
'columns_users' => 2, break;
'comment_on_as' => 1,
'comment_on_qs' => 0, case 'show_custom_in_head':
'confirm_user_emails' => 1, $value = strlen(qa_opt('custom_in_head')) > 0;
'do_ask_check_qs' => 0, break;
'do_complete_tags' => 1,
'do_count_q_views' => 1, case 'register_terms':
'do_example_tags' => 1, $value = qa_lang_html_sub('options/default_terms', qa_html(qa_opt('site_title')));
'feed_for_activity' => 1, break;
'feed_for_qa' => 1,
'feed_for_questions' => 1, case 'custom_sidebar':
'feed_for_unanswered' => 1, $value = qa_lang_html_sub('options/default_sidebar', qa_html(qa_opt('site_title')));
'feed_full_text' => 1, break;
'feed_number_items' => 50,
'feed_per_category' => 1, case 'editor_for_qs':
'feedback_enabled' => 1, case 'editor_for_as':
'flagging_hide_after' => 5, require_once QA_INCLUDE_DIR . 'app/format.php';
'flagging_notify_every' => 2,
'flagging_notify_first' => 1, $value = '-'; // to match none by default, i.e. choose based on who is best at editing HTML
'flagging_of_posts' => 1, qa_load_editor('', 'html', $value);
'follow_on_as' => 1, break;
'hot_weight_a_age' => 100,
'hot_weight_answers' => 100, case 'permit_post_q': // convert from deprecated option if available
'hot_weight_q_age' => 100, $value = qa_opt('ask_needs_login') ? QA_PERMIT_USERS : QA_PERMIT_ALL;
'hot_weight_views' => 100, break;
'hot_weight_votes' => 100,
'mailing_per_minute' => 500, case 'permit_post_a': // convert from deprecated option if available
'match_ask_check_qs' => 3, $value = qa_opt('answer_needs_login') ? QA_PERMIT_USERS : QA_PERMIT_ALL;
'match_example_tags' => 3, break;
'match_related_qs' => 3,
'max_copy_user_updates' => 10, case 'permit_post_c': // convert from deprecated option if available
'max_len_q_title' => 120, $value = qa_opt('comment_needs_login') ? QA_PERMIT_USERS : QA_PERMIT_ALL;
'max_num_q_tags' => 5, break;
'max_rate_ip_as' => 50,
'max_rate_ip_cs' => 40, case 'permit_retag_cat': // convert from previous option that used to contain it too
'max_rate_ip_flags' => 10, $value = qa_opt('permit_edit_q');
'max_rate_ip_logins' => 20, break;
'max_rate_ip_messages' => 10,
'max_rate_ip_qs' => 20, case 'points_vote_up_q':
'max_rate_ip_registers' => 5, case 'points_vote_down_q':
'max_rate_ip_uploads' => 20, $oldvalue = qa_opt('points_vote_on_q');
'max_rate_ip_votes' => 600, $value = is_numeric($oldvalue) ? $oldvalue : 1;
'max_rate_user_as' => 25, break;
'max_rate_user_cs' => 20,
'max_rate_user_flags' => 5, case 'points_vote_up_a':
'max_rate_user_messages' => 5, case 'points_vote_down_a':
'max_rate_user_qs' => 10, $oldvalue = qa_opt('points_vote_on_a');
'max_rate_user_uploads' => 10, $value = is_numeric($oldvalue) ? $oldvalue : 1;
'max_rate_user_votes' => 300, break;
'max_store_user_updates' => 50,
'min_len_a_content' => 12, case 'points_per_q_voted_up':
'min_len_c_content' => 12, case 'points_per_q_voted_down':
'min_len_q_content' => 0, $oldvalue = qa_opt('points_per_q_voted');
'min_len_q_title' => 12, $value = is_numeric($oldvalue) ? $oldvalue : 1;
'min_num_q_tags' => 0, break;
'minify_html' => 1,
'moderate_notify_admin' => 1, case 'points_per_a_voted_up':
'moderate_points_limit' => 150, case 'points_per_a_voted_down':
'moderate_update_time' => 1, $oldvalue = qa_opt('points_per_a_voted');
'nav_ask' => 1, $value = is_numeric($oldvalue) ? $oldvalue : 2;
'nav_qa_not_home' => 1, break;
'nav_questions' => 1,
'nav_tags' => 1, case 'captcha_module':
'nav_unanswered' => 1, $captchamodules = qa_list_modules('captcha');
'nav_users' => 1, if (count($captchamodules))
'neat_urls' => QA_URL_FORMAT_SAFEST, $value = reset($captchamodules);
'notify_users_default' => 1, else
'page_size_activity' => 20, $value = '';
'page_size_ask_check_qs' => 5, break;
'page_size_ask_tags' => 5,
'page_size_home' => 20, case 'mailing_from_name':
'page_size_hot_qs' => 20, $value = qa_opt('site_title');
'page_size_pms' => 10, break;
'page_size_q_as' => 10,
'page_size_qs' => 20, case 'mailing_from_email':
'page_size_related_qs' => 5, $value = qa_opt('from_email');
'page_size_search' => 10, break;
'page_size_tag_qs' => 20,
'page_size_tags' => 30, case 'mailing_subject':
'page_size_una_qs' => 20, $value = qa_lang_sub('options/default_subject', qa_opt('site_title'));
'page_size_users' => 30, break;
'page_size_wall' => 10,
'pages_prev_next' => 3, case 'mailing_body':
'permit_anon_view_ips' => QA_PERMIT_EDITORS, $value = "\n\n\n--\n" . qa_opt('site_title') . "\n" . qa_opt('site_url');
'permit_close_q' => QA_PERMIT_EDITORS, break;
'permit_delete_hidden' => QA_PERMIT_MODERATORS,
'permit_edit_a' => QA_PERMIT_EXPERTS, case 'form_security_salt':
'permit_edit_c' => QA_PERMIT_EDITORS, require_once QA_INCLUDE_DIR . 'util/string.php';
'permit_edit_q' => QA_PERMIT_EDITORS, $value = qa_random_alphanum(32);
'permit_edit_silent' => QA_PERMIT_MODERATORS, break;
'permit_flag' => QA_PERMIT_CONFIRMED,
'permit_hide_show' => QA_PERMIT_EDITORS, default: // call option_default method in any registered modules
'permit_moderate' => QA_PERMIT_EXPERTS, $modules = qa_load_all_modules_with('option_default'); // Loads all modules with the 'option_default' method
'permit_post_wall' => QA_PERMIT_CONFIRMED,
'permit_select_a' => QA_PERMIT_EXPERTS, foreach ($modules as $module) {
'permit_view_q_page' => QA_PERMIT_ALL, $value = $module->option_default($name);
'permit_view_new_users_page' => QA_PERMIT_EDITORS, if (strlen($value))
'permit_view_special_users_page' => QA_PERMIT_MODERATORS, return $value;
'permit_view_voters_flaggers' => QA_PERMIT_ADMINS,
'permit_vote_a' => QA_PERMIT_USERS,
'permit_vote_down' => QA_PERMIT_USERS,
'permit_vote_q' => QA_PERMIT_USERS,
'points_a_selected' => 30,
'points_a_voted_max_gain' => 20,
'points_a_voted_max_loss' => 5,
'points_base' => 100,
'points_multiple' => 10,
'points_post_a' => 4,
'points_post_q' => 2,
'points_q_voted_max_gain' => 10,
'points_q_voted_max_loss' => 3,
'points_select_a' => 3,
'q_urls_title_length' => 50,
'show_a_c_links' => 1,
'show_a_form_immediate' => 'if_no_as',
'show_c_reply_buttons' => 1,
'show_compact_numbers' => 1,
'show_custom_welcome' => 0,
'show_post_update_meta' => 1,
'show_fewer_cs_count' => 5,
'show_fewer_cs_from' => 10,
'show_full_date_days' => 7,
'show_message_history' => 1,
'show_register_terms' => 0,
'show_selected_first' => 1,
'show_url_links' => 1,
'show_user_points' => 1,
'show_user_titles' => 1,
'show_when_created' => 1,
'site_text_direction' => 'ltr',
'site_theme' => 'Snow',
'smtp_port' => 25,
'sort_answers_by' => 'created',
'tags_or_categories' => 'tc',
'use_microdata' => 1,
'voting_on_as' => 1,
'voting_on_qs' => 1,
);
if (isset($fixed_defaults[$name]))
$value=$fixed_defaults[$name];
else
switch ($name) {
case 'site_url':
$value='http://'.@$_SERVER['HTTP_HOST'].strtr(rtrim(dirname($_SERVER['SCRIPT_NAME']), '/'), '\\', '/').'/';
break;
case 'site_title':
$value=qa_default_site_title();
break;
case 'site_theme_mobile':
$value=qa_opt('site_theme');
break;
case 'from_email': // heuristic to remove short prefix (e.g. www. or qa.)
$parts=explode('.', @$_SERVER['HTTP_HOST']);
if ( (count($parts)>2) && (strlen($parts[0])<5) && !is_numeric($parts[0]) )
unset($parts[0]);
$value='no-reply@'.((count($parts)>1) ? implode('.', $parts) : 'example.com');
break;
case 'email_privacy':
$value=qa_lang_html('options/default_privacy');
break;
case 'show_custom_sidebar':
$value = strlen(qa_opt('custom_sidebar')) > 0;
break;
case 'show_custom_header':
$value = strlen(qa_opt('custom_header')) > 0;
break;
case 'show_custom_footer':
$value = strlen(qa_opt('custom_footer')) > 0;
break;
case 'show_custom_in_head':
$value = strlen(qa_opt('custom_in_head')) > 0;
break;
case 'register_terms':
$value = qa_lang_html_sub('options/default_terms', qa_html(qa_opt('site_title')));
break;
case 'custom_sidebar':
$value = qa_lang_html_sub('options/default_sidebar', qa_html(qa_opt('site_title')));
break;
case 'editor_for_qs':
case 'editor_for_as':
require_once QA_INCLUDE_DIR.'app/format.php';
$value='-'; // to match none by default, i.e. choose based on who is best at editing HTML
qa_load_editor('', 'html', $value);
break;
case 'permit_post_q': // convert from deprecated option if available
$value=qa_opt('ask_needs_login') ? QA_PERMIT_USERS : QA_PERMIT_ALL;
break;
case 'permit_post_a': // convert from deprecated option if available
$value=qa_opt('answer_needs_login') ? QA_PERMIT_USERS : QA_PERMIT_ALL;
break;
case 'permit_post_c': // convert from deprecated option if available
$value=qa_opt('comment_needs_login') ? QA_PERMIT_USERS : QA_PERMIT_ALL;
break;
case 'permit_retag_cat': // convert from previous option that used to contain it too
$value=qa_opt('permit_edit_q');
break;
case 'points_vote_up_q':
case 'points_vote_down_q':
$oldvalue=qa_opt('points_vote_on_q');
$value=is_numeric($oldvalue) ? $oldvalue : 1;
break;
case 'points_vote_up_a':
case 'points_vote_down_a':
$oldvalue=qa_opt('points_vote_on_a');
$value=is_numeric($oldvalue) ? $oldvalue : 1;
break;
case 'points_per_q_voted_up':
case 'points_per_q_voted_down':
$oldvalue=qa_opt('points_per_q_voted');
$value=is_numeric($oldvalue) ? $oldvalue : 1;
break;
case 'points_per_a_voted_up':
case 'points_per_a_voted_down':
$oldvalue=qa_opt('points_per_a_voted');
$value=is_numeric($oldvalue) ? $oldvalue : 2;
break;
case 'captcha_module':
$captchamodules=qa_list_modules('captcha');
if (count($captchamodules))
$value=reset($captchamodules);
else
$value='';
break;
case 'mailing_from_name':
$value=qa_opt('site_title');
break;
case 'mailing_from_email':
$value=qa_opt('from_email');
break;
case 'mailing_subject':
$value=qa_lang_sub('options/default_subject', qa_opt('site_title'));
break;
case 'mailing_body':
$value="\n\n\n--\n".qa_opt('site_title')."\n".qa_opt('site_url');
break;
case 'form_security_salt':
require_once QA_INCLUDE_DIR.'util/string.php';
$value=qa_random_alphanum(32);
break;
default: // call option_default method in any registered modules
$modules = qa_load_all_modules_with('option_default'); // Loads all modules with the 'option_default' method
foreach ($modules as $module) {
$value = $module->option_default($name);
if (strlen($value))
return $value;
}
$value='';
break;
} }
return $value; $value = '';
break;
} }
return $value;
}
function qa_default_site_title()
/*
Return a heuristic guess at the name of the site from the HTTP HOST
*/
{
$parts=explode('.', @$_SERVER['HTTP_HOST']);
$longestpart=''; /**
foreach ($parts as $part) * Return a heuristic guess at the name of the site from the HTTP HOST
if (strlen($part)>strlen($longestpart)) */
$longestpart=$part; function qa_default_site_title()
{
$parts = explode('.', @$_SERVER['HTTP_HOST']);
return ((strlen($longestpart)>3) ? (ucfirst($longestpart).' ') : '').qa_lang('options/default_suffix'); $longestpart = '';
foreach ($parts as $part) {
if (strlen($part) > strlen($longestpart))
$longestpart = $part;
} }
return ((strlen($longestpart) > 3) ? (ucfirst($longestpart) . ' ') : '') . qa_lang('options/default_suffix');
function qa_post_html_defaults($basetype, $full=false) }
/*
Return an array of defaults for the $options parameter passed to qa_post_html_fields() and its ilk for posts of $basetype='Q'/'A'/'C'
Set $full to true if these posts will be viewed in full, i.e. on a question page rather than a question listing /**
*/ * Return an array of defaults for the $options parameter passed to qa_post_html_fields() and its ilk for posts of $basetype='Q'/'A'/'C'
{ * Set $full to true if these posts will be viewed in full, i.e. on a question page rather than a question listing
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } * @param $basetype
* @param bool $full
require_once QA_INCLUDE_DIR.'app/users.php'; * @return array|mixed
*/
return array( function qa_post_html_defaults($basetype, $full = false)
'tagsview' => ($basetype=='Q') && qa_using_tags(), {
'categoryview' => ($basetype=='Q') && qa_using_categories(), if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
'contentview' => $full,
'voteview' => qa_get_vote_view($basetype, $full), require_once QA_INCLUDE_DIR . 'app/users.php';
'flagsview' => qa_opt('flagging_of_posts') && $full,
'favoritedview' => true, return array(
'answersview' => $basetype=='Q', 'tagsview' => $basetype == 'Q' && qa_using_tags(),
'viewsview' => ($basetype=='Q') && qa_opt('do_count_q_views') && ($full ? qa_opt('show_view_count_q_page') : qa_opt('show_view_counts')), 'categoryview' => $basetype == 'Q' && qa_using_categories(),
'whatview' => true, 'contentview' => $full,
'whatlink' => qa_opt('show_a_c_links'), 'voteview' => qa_get_vote_view($basetype, $full),
'whenview' => qa_opt('show_when_created'), 'flagsview' => qa_opt('flagging_of_posts') && $full,
'ipview' => !qa_user_permit_error('permit_anon_view_ips'), 'favoritedview' => true,
'whoview' => true, 'answersview' => $basetype == 'Q',
'avatarsize' => qa_opt('avatar_q_list_size'), 'viewsview' => $basetype == 'Q' && qa_opt('do_count_q_views') && ($full ? qa_opt('show_view_count_q_page') : qa_opt('show_view_counts')),
'pointsview' => qa_opt('show_user_points'), 'whatview' => true,
'pointstitle' => qa_opt('show_user_titles') ? qa_get_points_to_titles() : array(), 'whatlink' => qa_opt('show_a_c_links'),
'updateview' => qa_opt('show_post_update_meta'), 'whenview' => qa_opt('show_when_created'),
'blockwordspreg' => qa_get_block_words_preg(), 'ipview' => !qa_user_permit_error('permit_anon_view_ips'),
'showurllinks' => qa_opt('show_url_links'), 'whoview' => true,
'linksnewwindow' => qa_opt('links_in_new_window'), 'avatarsize' => qa_opt('avatar_q_list_size'),
'microformats' => $full, 'pointsview' => qa_opt('show_user_points'),
'fulldatedays' => qa_opt('show_full_date_days'), 'pointstitle' => qa_opt('show_user_titles') ? qa_get_points_to_titles() : array(),
); 'updateview' => qa_opt('show_post_update_meta'),
'blockwordspreg' => qa_get_block_words_preg(),
'showurllinks' => qa_opt('show_url_links'),
'linksnewwindow' => qa_opt('links_in_new_window'),
'microformats' => $full,
'fulldatedays' => qa_opt('show_full_date_days'),
);
}
/**
* Return an array of options for post $post to pass in the $options parameter to qa_post_html_fields() and its ilk. Preferably,
* call qa_post_html_defaults() previously and pass its output in $defaults, to save excessive recalculation for each item in a
* list. Set $full to true if these posts will be viewed in full, i.e. on a question page rather than a question listing.
* @param $post
* @param $defaults
* @param bool $full
* @return array|mixed|null
*/
function qa_post_html_options($post, $defaults = null, $full = false)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if (!isset($defaults))
$defaults = qa_post_html_defaults($post['basetype'], $full);
$defaults['voteview'] = qa_get_vote_view($post, $full);
$defaults['ipview'] = !qa_user_post_permit_error('permit_anon_view_ips', $post);
return $defaults;
}
/**
* Return an array of defaults for the $options parameter passed to qa_message_html_fields()
*/
function qa_message_html_defaults()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return array(
'whenview' => qa_opt('show_when_created'),
'whoview' => true,
'avatarsize' => qa_opt('avatar_message_list_size'),
'blockwordspreg' => qa_get_block_words_preg(),
'showurllinks' => qa_opt('show_url_links'),
'linksnewwindow' => qa_opt('links_in_new_window'),
'fulldatedays' => qa_opt('show_full_date_days'),
);
}
/**
* Return $voteview parameter to pass to qa_post_html_fields() in qa-app-format.php for the post in $postorbasetype
* with buttons enabled if appropriate (based on whether $full post shown) unless $enabledif is false.
* For compatibility $postorbasetype can also just be a basetype, i.e. 'Q', 'A' or 'C'
* @param $postorbasetype
* @param bool $full
* @param bool $enabledif
* @return bool|string
*/
function qa_get_vote_view($postorbasetype, $full = false, $enabledif = true)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
// The 'level' and 'approve' permission errors are taken care of by disabling the voting buttons.
// Others are reported to the user after they click, in qa_vote_error_html(...)
if (is_array($postorbasetype)) { // deal with dual-use parameter
$basetype = $postorbasetype['basetype'];
$post = $postorbasetype;
} else {
$basetype = $postorbasetype;
$post = null;
} }
$disabledsuffix = '';
function qa_post_html_options($post, $defaults=null, $full=false) if ($basetype == 'Q' || $basetype == 'A') {
/* $view = $basetype == 'A' ? qa_opt('voting_on_as') : qa_opt('voting_on_qs');
Return an array of options for post $post to pass in the $options parameter to qa_post_html_fields() and its ilk. Preferably,
call qa_post_html_defaults() previously and pass its output in $defaults, to save excessive recalculation for each item in a
list. Set $full to true if these posts will be viewed in full, i.e. on a question page rather than a question listing.
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if (!isset($defaults))
$defaults=qa_post_html_defaults($post['basetype'], $full);
$defaults['voteview']=qa_get_vote_view($post, $full); if (!($enabledif && ($basetype == 'A' || $full || !qa_opt('voting_on_q_page_only'))))
$defaults['ipview']=!qa_user_post_permit_error('permit_anon_view_ips', $post); $disabledsuffix = '-disabled-page';
return $defaults;
}
else {
if ($basetype == 'A')
$permiterror = isset($post) ? qa_user_post_permit_error('permit_vote_a', $post) : qa_user_permit_error('permit_vote_a');
else
$permiterror = isset($post) ? qa_user_post_permit_error('permit_vote_q', $post) : qa_user_permit_error('permit_vote_q');
function qa_message_html_defaults() if ($permiterror == 'level')
/* $disabledsuffix = '-disabled-level';
Return an array of defaults for the $options parameter passed to qa_message_html_fields() elseif ($permiterror == 'approve')
*/ $disabledsuffix = '-disabled-approve';
{ else {
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } $permiterrordown = isset($post) ? qa_user_post_permit_error('permit_vote_down', $post) : qa_user_permit_error('permit_vote_down');
return array(
'whenview' => qa_opt('show_when_created'),
'whoview' => true,
'avatarsize' => qa_opt('avatar_message_list_size'),
'blockwordspreg' => qa_get_block_words_preg(),
'showurllinks' => qa_opt('show_url_links'),
'linksnewwindow' => qa_opt('links_in_new_window'),
'fulldatedays' => qa_opt('show_full_date_days'),
);
}
function qa_get_vote_view($postorbasetype, $full=false, $enabledif=true)
/*
Return $voteview parameter to pass to qa_post_html_fields() in qa-app-format.php for the post in $postorbasetype
with buttons enabled if appropriate (based on whether $full post shown) unless $enabledif is false.
For compatibility $postorbasetype can also just be a basetype, i.e. 'Q', 'A' or 'C'
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
// The 'level' and 'approve' permission errors are taken care of by disabling the voting buttons.
// Others are reported to the user after they click, in qa_vote_error_html(...)
if (is_array($postorbasetype)) { // deal with dual-use parameter
$basetype=$postorbasetype['basetype'];
$post=$postorbasetype;
} else { if ($permiterrordown == 'level')
$basetype=$postorbasetype; $disabledsuffix = '-uponly-level';
$post=null; elseif ($permiterrordown == 'approve')
$disabledsuffix = '-uponly-approve';
}
} }
$disabledsuffix=''; } else
$view = false;
if (($basetype=='Q') || ($basetype=='A')) { return $view ? ((qa_opt('votes_separated') ? 'updown' : 'net') . $disabledsuffix) : false;
$view=($basetype=='A') ? qa_opt('voting_on_as') : qa_opt('voting_on_qs'); }
if (!($enabledif && (($basetype=='A') || $full || !qa_opt('voting_on_q_page_only'))))
$disabledsuffix='-disabled-page';
else { /**
if ($basetype=='A') * Returns true if the home page has been customized, either due to admin setting, or $QA_CONST_PATH_MAP
$permiterror=isset($post) ? qa_user_post_permit_error('permit_vote_a', $post) : qa_user_permit_error('permit_vote_a'); */
else function qa_has_custom_home()
$permiterror=isset($post) ? qa_user_post_permit_error('permit_vote_q', $post) : qa_user_permit_error('permit_vote_q'); {
return qa_opt('show_custom_home') || (array_search('', qa_get_request_map()) !== false);
if ($permiterror=='level') }
$disabledsuffix='-disabled-level';
elseif ($permiterror=='approve')
$disabledsuffix='-disabled-approve';
else {
$permiterrordown=isset($post) ? qa_user_post_permit_error('permit_vote_down', $post) : qa_user_permit_error('permit_vote_down');
if ($permiterrordown=='level')
$disabledsuffix='-uponly-level';
elseif ($permiterrordown=='approve')
$disabledsuffix='-uponly-approve';
}
}
} else
$view=false;
return $view ? ( (qa_opt('votes_separated') ? 'updown' : 'net').$disabledsuffix ) : false; /**
} * Return whether the option is set to classify questions by tags
*/
function qa_using_tags()
{
return strpos(qa_opt('tags_or_categories'), 't') !== false;
}
function qa_has_custom_home() /**
/* * Return whether the option is set to classify questions by categories
Returns true if the home page has been customized, either due to admin setting, or $QA_CONST_PATH_MAP */
*/ function qa_using_categories()
{ {
return qa_opt('show_custom_home') || (array_search('', qa_get_request_map())!==false); return strpos(qa_opt('tags_or_categories'), 'c') !== false;
} }
function qa_using_tags() /**
/* * Return the regular expression fragment to match the blocked words options set in the database
Return whether the option is set to classify questions by tags */
*/ function qa_get_block_words_preg()
{ {
return strpos(qa_opt('tags_or_categories'), 't')!==false; if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
}
global $qa_blockwordspreg, $qa_blockwordspreg_set;
function qa_using_categories() if (!@$qa_blockwordspreg_set) {
/* $blockwordstring = qa_opt('block_bad_words');
Return whether the option is set to classify questions by categories
*/
{
return strpos(qa_opt('tags_or_categories'), 'c')!==false;
}
function qa_get_block_words_preg() if (strlen($blockwordstring)) {
/* require_once QA_INCLUDE_DIR . 'util/string.php';
Return the regular expression fragment to match the blocked words options set in the database $qa_blockwordspreg = qa_block_words_to_preg($blockwordstring);
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
global $qa_blockwordspreg, $qa_blockwordspreg_set; } else
$qa_blockwordspreg = null;
if (!@$qa_blockwordspreg_set) { $qa_blockwordspreg_set = true;
$blockwordstring=qa_opt('block_bad_words'); }
if (strlen($blockwordstring)) { return $qa_blockwordspreg;
require_once QA_INCLUDE_DIR.'util/string.php'; }
$qa_blockwordspreg=qa_block_words_to_preg($blockwordstring);
} else
$qa_blockwordspreg=null;
$qa_blockwordspreg_set=true; /**
} * Return an array of [points] => [user title] from the 'points_to_titles' option, to pass to qa_get_points_title_html()
*/
function qa_get_points_to_titles()
{
global $qa_points_title_cache;
return $qa_blockwordspreg; if (!is_array($qa_points_title_cache)) {
} $qa_points_title_cache = array();
$pairs = explode(',', qa_opt('points_to_titles'));
foreach ($pairs as $pair) {
$spacepos = strpos($pair, ' ');
if (is_numeric($spacepos)) {
$points = trim(substr($pair, 0, $spacepos));
$title = trim(substr($pair, $spacepos));
function qa_get_points_to_titles() if (is_numeric($points) && strlen($title))
/* $qa_points_title_cache[(int)$points] = $title;
Return an array of [points] => [user title] from the 'points_to_titles' option, to pass to qa_get_points_title_html()
*/
{
global $qa_points_title_cache;
if (!is_array($qa_points_title_cache)) {
$qa_points_title_cache=array();
$pairs=explode(',', qa_opt('points_to_titles'));
foreach ($pairs as $pair) {
$spacepos=strpos($pair, ' ');
if (is_numeric($spacepos)) {
$points=trim(substr($pair, 0, $spacepos));
$title=trim(substr($pair, $spacepos));
if (is_numeric($points) && strlen($title))
$qa_points_title_cache[(int)$points]=$title;
}
} }
krsort($qa_points_title_cache, SORT_NUMERIC);
} }
return $qa_points_title_cache; krsort($qa_points_title_cache, SORT_NUMERIC);
} }
return $qa_points_title_cache;
}
function qa_get_permit_options()
/*
Return an array of relevant permissions settings, based on other options
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$permits=array('permit_view_q_page', 'permit_post_q', 'permit_post_a'); /**
* Return an array of relevant permissions settings, based on other options
*/
function qa_get_permit_options()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if (qa_opt('comment_on_qs') || qa_opt('comment_on_as')) $permits = array('permit_view_q_page', 'permit_post_q', 'permit_post_a');
$permits[]='permit_post_c';
if (qa_opt('voting_on_qs')) if (qa_opt('comment_on_qs') || qa_opt('comment_on_as'))
$permits[]='permit_vote_q'; $permits[] = 'permit_post_c';
if (qa_opt('voting_on_as')) if (qa_opt('voting_on_qs'))
$permits[]='permit_vote_a'; $permits[] = 'permit_vote_q';
if (qa_opt('voting_on_qs') || qa_opt('voting_on_as')) if (qa_opt('voting_on_as'))
$permits[]='permit_vote_down'; $permits[] = 'permit_vote_a';
if (qa_using_tags() || qa_using_categories()) if (qa_opt('voting_on_qs') || qa_opt('voting_on_as'))
$permits[]='permit_retag_cat'; $permits[] = 'permit_vote_down';
array_push($permits, 'permit_edit_q', 'permit_edit_a'); if (qa_using_tags() || qa_using_categories())
$permits[] = 'permit_retag_cat';
if (qa_opt('comment_on_qs') || qa_opt('comment_on_as')) array_push($permits, 'permit_edit_q', 'permit_edit_a');
$permits[]='permit_edit_c';
$permits[]='permit_edit_silent'; if (qa_opt('comment_on_qs') || qa_opt('comment_on_as'))
$permits[] = 'permit_edit_c';
if (qa_opt('allow_close_questions')) $permits[] = 'permit_edit_silent';
$permits[]='permit_close_q';
array_push($permits, 'permit_select_a', 'permit_anon_view_ips'); if (qa_opt('allow_close_questions'))
$permits[] = 'permit_close_q';
if (qa_opt('voting_on_qs') || qa_opt('voting_on_as') || qa_opt('flagging_of_posts')) array_push($permits, 'permit_select_a', 'permit_anon_view_ips');
$permits[]='permit_view_voters_flaggers';
if (qa_opt('flagging_of_posts')) if (qa_opt('voting_on_qs') || qa_opt('voting_on_as') || qa_opt('flagging_of_posts'))
$permits[]='permit_flag'; $permits[] = 'permit_view_voters_flaggers';
$permits[]='permit_moderate'; if (qa_opt('flagging_of_posts'))
$permits[] = 'permit_flag';
array_push($permits, 'permit_hide_show', 'permit_delete_hidden'); $permits[] = 'permit_moderate';
if (qa_opt('allow_user_walls')) array_push($permits, 'permit_hide_show', 'permit_delete_hidden');
$permits[]='permit_post_wall';
array_push($permits, 'permit_view_new_users_page', 'permit_view_special_users_page'); if (qa_opt('allow_user_walls'))
$permits[] = 'permit_post_wall';
return $permits;
}
array_push($permits, 'permit_view_new_users_page', 'permit_view_special_users_page');
/* return $permits;
Omit PHP closing tag to help avoid accidental output }
*/
...@@ -20,428 +20,491 @@ ...@@ -20,428 +20,491 @@
More about this license: http://www.question2answer.org/license.php 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: ../'); header('Location: ../');
exit; exit;
}
require_once QA_INCLUDE_DIR . 'qa-db.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR . 'app/format.php';
require_once QA_INCLUDE_DIR . 'app/post-create.php';
require_once QA_INCLUDE_DIR . 'app/post-update.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'util/string.php';
/**
* Create a new post in the database, and return its postid.
*
* Set $type to 'Q' for a new question, 'A' for an answer, or 'C' for a comment. You can also use 'Q_QUEUED',
* 'A_QUEUED' or 'C_QUEUED' to create a post which is queued for moderator approval. For questions, set $parentid to
* the postid of the answer to which the question is related, or null if (as in most cases) the question is not related
* to an answer. For answers, set $parentid to the postid of the question being answered. For comments, set $parentid
* to the postid of the question or answer to which the comment relates. The $content and $format parameters go
* together - if $format is '' then $content should be in plain UTF-8 text, and if $format is 'html' then $content
* should be in UTF-8 HTML. Other values of $format may be allowed if an appropriate viewer module is installed. The
* $title, $categoryid and $tags parameters are only relevant when creating a question - $tags can either be an array
* of tags, or a string of tags separated by commas. The new post will be assigned to $userid if it is not null,
* otherwise it will be by a non-user. If $notify is true then the author will be sent notifications relating to the
* post - either to $email if it is specified and valid, or to the current email address of $userid if $email is '@'.
* If you're creating a question, the $extravalue parameter will be set as the custom extra field, if not null. For all
* post types you can specify the $name of the post's author, which is relevant if the $userid is null.
* @param $type
* @param $parentid
* @param $title
* @param $content
* @param string $format
* @param $categoryid
* @param $tags
* @param $userid
* @param $notify
* @param $email
* @param $extravalue
* @param $name
* @return mixed
*/
function qa_post_create($type, $parentid, $title, $content, $format = '', $categoryid = null, $tags = null, $userid = null,
$notify = null, $email = null, $extravalue = null, $name = null)
{
$handle = qa_userid_to_handle($userid);
$text = qa_post_content_to_text($content, $format);
switch ($type) {
case 'Q':
case 'Q_QUEUED':
$followanswer = isset($parentid) ? qa_post_get_full($parentid, 'A') : null;
$tagstring = qa_post_tags_to_tagstring($tags);
$postid = qa_question_create($followanswer, $userid, $handle, null, $title, $content, $format, $text, $tagstring,
$notify, $email, $categoryid, $extravalue, $type == 'Q_QUEUED', $name);
break;
case 'A':
case 'A_QUEUED':
$question = qa_post_get_full($parentid, 'Q');
$postid = qa_answer_create($userid, $handle, null, $content, $format, $text, $notify, $email, $question, $type == 'A_QUEUED', $name);
break;
case 'C':
case 'C_QUEUED':
$parent = qa_post_get_full($parentid, 'QA');
$commentsfollows = qa_db_single_select(qa_db_full_child_posts_selectspec(null, $parentid));
$question = qa_post_parent_to_question($parent);
$postid = qa_comment_create($userid, $handle, null, $content, $format, $text, $notify, $email, $question, $parent, $commentsfollows, $type == 'C_QUEUED', $name);
break;
default:
qa_fatal_error('Post type not recognized: ' . $type);
break;
} }
require_once QA_INCLUDE_DIR.'qa-db.php'; return $postid;
require_once QA_INCLUDE_DIR.'db/selects.php'; }
require_once QA_INCLUDE_DIR.'app/format.php';
require_once QA_INCLUDE_DIR.'app/post-create.php';
require_once QA_INCLUDE_DIR.'app/post-update.php'; /**
require_once QA_INCLUDE_DIR.'app/users.php'; * Change the data stored for post $postid based on any of the $title, $content, $format, $tags, $notify, $email,
require_once QA_INCLUDE_DIR.'util/string.php'; * $extravalue and $name parameters passed which are not null. The meaning of these parameters is the same as for
* qa_post_create() above. Pass the identify of the user making this change in $byuserid (or null for silent).
* @param $postid
function qa_post_create($type, $parentid, $title, $content, $format='', $categoryid=null, $tags=null, $userid=null, $notify=null, $email=null, $extravalue=null, $name=null) * @param $title
/* * @param $content
Create a new post in the database, and return its postid. * @param $format
* @param $tags
Set $type to 'Q' for a new question, 'A' for an answer, or 'C' for a comment. You can also use 'Q_QUEUED', * @param $notify
'A_QUEUED' or 'C_QUEUED' to create a post which is queued for moderator approval. For questions, set $parentid to * @param $email
the postid of the answer to which the question is related, or null if (as in most cases) the question is not related * @param $byuserid
to an answer. For answers, set $parentid to the postid of the question being answered. For comments, set $parentid * @param $extravalue
to the postid of the question or answer to which the comment relates. The $content and $format parameters go * @param $name
together - if $format is '' then $content should be in plain UTF-8 text, and if $format is 'html' then $content */
should be in UTF-8 HTML. Other values of $format may be allowed if an appropriate viewer module is installed. The function qa_post_set_content($postid, $title, $content, $format = null, $tags = null, $notify = null, $email = null, $byuserid = null, $extravalue = null, $name = null)
$title, $categoryid and $tags parameters are only relevant when creating a question - $tags can either be an array {
of tags, or a string of tags separated by commas. The new post will be assigned to $userid if it is not null, $oldpost = qa_post_get_full($postid, 'QAC');
otherwise it will be by a non-user. If $notify is true then the author will be sent notifications relating to the
post - either to $email if it is specified and valid, or to the current email address of $userid if $email is '@'. if (!isset($title))
If you're creating a question, the $extravalue parameter will be set as the custom extra field, if not null. For all $title = $oldpost['title'];
post types you can specify the $name of the post's author, which is relevant if the $userid is null.
*/ if (!isset($content))
{ $content = $oldpost['content'];
$handle=qa_userid_to_handle($userid);
$text=qa_post_content_to_text($content, $format); if (!isset($format))
$format = $oldpost['format'];
switch ($type) {
case 'Q': if (!isset($tags))
case 'Q_QUEUED': $tags = qa_tagstring_to_tags($oldpost['tags']);
$followanswer=isset($parentid) ? qa_post_get_full($parentid, 'A') : null;
$tagstring=qa_post_tags_to_tagstring($tags); if (isset($notify) || isset($email))
$postid=qa_question_create($followanswer, $userid, $handle, null, $title, $content, $format, $text, $tagstring, $setnotify = qa_combine_notify_email($oldpost['userid'], isset($notify) ? $notify : isset($oldpost['notify']),
$notify, $email, $categoryid, $extravalue, $type=='Q_QUEUED', $name); isset($email) ? $email : $oldpost['notify']);
break; else
$setnotify = $oldpost['notify'];
case 'A':
case 'A_QUEUED': $byhandle = qa_userid_to_handle($byuserid);
$question=qa_post_get_full($parentid, 'Q');
$postid=qa_answer_create($userid, $handle, null, $content, $format, $text, $notify, $email, $question, $type=='A_QUEUED', $name); $text = qa_post_content_to_text($content, $format);
break;
switch ($oldpost['basetype']) {
case 'C': case 'Q':
case 'C_QUEUED': $tagstring = qa_post_tags_to_tagstring($tags);
$parent=qa_post_get_full($parentid, 'QA'); qa_question_set_content($oldpost, $title, $content, $format, $text, $tagstring, $setnotify, $byuserid, $byhandle, null, $extravalue, $name);
$commentsfollows=qa_db_single_select(qa_db_full_child_posts_selectspec(null, $parentid)); break;
$question=qa_post_parent_to_question($parent);
$postid=qa_comment_create($userid, $handle, null, $content, $format, $text, $notify, $email, $question, $parent, $commentsfollows, $type=='C_QUEUED', $name); case 'A':
break; $question = qa_post_get_full($oldpost['parentid'], 'Q');
qa_answer_set_content($oldpost, $content, $format, $text, $setnotify, $byuserid, $byhandle, null, $question, $name);
default: break;
qa_fatal_error('Post type not recognized: '.$type);
break; case 'C':
} $parent = qa_post_get_full($oldpost['parentid'], 'QA');
$question = qa_post_parent_to_question($parent);
return $postid; qa_comment_set_content($oldpost, $content, $format, $text, $setnotify, $byuserid, $byhandle, null, $question, $parent, $name);
break;
} }
}
function qa_post_set_content($postid, $title, $content, $format=null, $tags=null, $notify=null, $email=null, $byuserid=null, $extravalue=null, $name=null)
/* /**
Change the data stored for post $postid based on any of the $title, $content, $format, $tags, $notify, $email, * Change the category of $postid to $categoryid. The category of all related posts (shown together on the same
$extravalue and $name parameters passed which are not null. The meaning of these parameters is the same as for * question page) will also be changed. Pass the identify of the user making this change in $byuserid (or null for an
qa_post_create() above. Pass the identify of the user making this change in $byuserid (or null for silent). * anonymous change).
*/ * @param $postid
{ * @param $categoryid
$oldpost=qa_post_get_full($postid, 'QAC'); * @param $byuserid
*/
if (!isset($title)) function qa_post_set_category($postid, $categoryid, $byuserid = null)
$title=$oldpost['title']; {
$oldpost = qa_post_get_full($postid, 'QAC');
if (!isset($content))
$content=$oldpost['content']; if ($oldpost['basetype'] == 'Q') {
$byhandle = qa_userid_to_handle($byuserid);
if (!isset($format)) $answers = qa_post_get_question_answers($postid);
$format=$oldpost['format']; $commentsfollows = qa_post_get_question_commentsfollows($postid);
$closepost = qa_post_get_question_closepost($postid);
if (!isset($tags)) qa_question_set_category($oldpost, $categoryid, $byuserid, $byhandle, null, $answers, $commentsfollows, $closepost);
$tags=qa_tagstring_to_tags($oldpost['tags']);
} else
if (isset($notify) || isset($email)) qa_post_set_category($oldpost['parentid'], $categoryid, $byuserid); // keep looking until we find the parent question
$setnotify=qa_combine_notify_email($oldpost['userid'], isset($notify) ? $notify : isset($oldpost['notify']), }
isset($email) ? $email : $oldpost['notify']);
/**
* Set the selected best answer of $questionid to $answerid (or to none if $answerid is null). Pass the identify of the
* user in $byuserid (or null for an anonymous change).
* @param $questionid
* @param $answerid
* @param $byuserid
*/
function qa_post_set_selchildid($questionid, $answerid, $byuserid = null)
{
$oldquestion = qa_post_get_full($questionid, 'Q');
$byhandle = qa_userid_to_handle($byuserid);
$answers = qa_post_get_question_answers($questionid);
if (isset($answerid) && !isset($answers[$answerid]))
qa_fatal_error('Answer ID could not be found: ' . $answerid);
qa_question_set_selchildid($byuserid, $byhandle, null, $oldquestion, $answerid, $answers);
}
/**
* Closed $questionid if $closed is true, otherwise reopen it. If $closed is true, pass either the $originalpostid of
* the question that it is a duplicate of, or a $note to explain why it's closed. Pass the identify of the user in
* $byuserid (or null for an anonymous change).
* @param $questionid
* @param bool $closed
* @param $originalpostid
* @param $note
* @param $byuserid
*/
function qa_post_set_closed($questionid, $closed = true, $originalpostid = null, $note = null, $byuserid = null)
{
$oldquestion = qa_post_get_full($questionid, 'Q');
$oldclosepost = qa_post_get_question_closepost($questionid);
$byhandle = qa_userid_to_handle($byuserid);
if ($closed) {
if (isset($originalpostid))
qa_question_close_duplicate($oldquestion, $oldclosepost, $originalpostid, $byuserid, $byhandle, null);
elseif (isset($note))
qa_question_close_other($oldquestion, $oldclosepost, $note, $byuserid, $byhandle, null);
else else
$setnotify=$oldpost['notify']; qa_fatal_error('Question must be closed as a duplicate or with a note');
$byhandle=qa_userid_to_handle($byuserid); } else
qa_question_close_clear($oldquestion, $oldclosepost, $byuserid, $byhandle, null);
$text=qa_post_content_to_text($content, $format); }
switch ($oldpost['basetype']) {
case 'Q': /**
$tagstring=qa_post_tags_to_tagstring($tags); * Hide $postid if $hidden is true, otherwise show the post. Pass the identify of the user making this change in
qa_question_set_content($oldpost, $title, $content, $format, $text, $tagstring, $setnotify, $byuserid, $byhandle, null, $extravalue, $name); * $byuserid (or null for a silent change). This function is included mainly for backwards compatibility.
break; * @param $postid
* @param bool $hidden
case 'A': * @param $byuserid
$question=qa_post_get_full($oldpost['parentid'], 'Q'); */
qa_answer_set_content($oldpost, $content, $format, $text, $setnotify, $byuserid, $byhandle, null, $question, $name); function qa_post_set_hidden($postid, $hidden = true, $byuserid = null)
break; {
qa_post_set_status($postid, $hidden ? QA_POST_STATUS_HIDDEN : QA_POST_STATUS_NORMAL, $byuserid);
case 'C': }
$parent=qa_post_get_full($oldpost['parentid'], 'QA');
$question=qa_post_parent_to_question($parent);
qa_comment_set_content($oldpost, $content, $format, $text, $setnotify, $byuserid, $byhandle, null, $question, $parent, $name); /**
break; * Change the status of $postid to $status, which should be one of the QA_POST_STATUS_* constants defined in
} * qa-app-post-update.php. Pass the identify of the user making this change in $byuserid (or null for a silent change).
* @param $postid
* @param $status
* @param $byuserid
*/
function qa_post_set_status($postid, $status, $byuserid = null)
{
$oldpost = qa_post_get_full($postid, 'QAC');
$byhandle = qa_userid_to_handle($byuserid);
switch ($oldpost['basetype']) {
case 'Q':
$answers = qa_post_get_question_answers($postid);
$commentsfollows = qa_post_get_question_commentsfollows($postid);
$closepost = qa_post_get_question_closepost($postid);
qa_question_set_status($oldpost, $status, $byuserid, $byhandle, null, $answers, $commentsfollows, $closepost);
break;
case 'A':
$question = qa_post_get_full($oldpost['parentid'], 'Q');
$commentsfollows = qa_post_get_answer_commentsfollows($postid);
qa_answer_set_status($oldpost, $status, $byuserid, $byhandle, null, $question, $commentsfollows);
break;
case 'C':
$parent = qa_post_get_full($oldpost['parentid'], 'QA');
$question = qa_post_parent_to_question($parent);
qa_comment_set_status($oldpost, $status, $byuserid, $byhandle, null, $question, $parent);
break;
} }
}
function qa_post_set_category($postid, $categoryid, $byuserid=null) /**
/* * Set the created date of $postid to $created, which is a unix timestamp.
Change the category of $postid to $categoryid. The category of all related posts (shown together on the same * @param $postid
question page) will also be changed. Pass the identify of the user making this change in $byuserid (or null for an * @param $created
anonymous change). */
*/ function qa_post_set_created($postid, $created)
{ {
$oldpost=qa_post_get_full($postid, 'QAC'); $oldpost = qa_post_get_full($postid);
if ($oldpost['basetype']=='Q') {
$byhandle=qa_userid_to_handle($byuserid);
$answers=qa_post_get_question_answers($postid);
$commentsfollows=qa_post_get_question_commentsfollows($postid);
$closepost=qa_post_get_question_closepost($postid);
qa_question_set_category($oldpost, $categoryid, $byuserid, $byhandle, null, $answers, $commentsfollows, $closepost);
} else
qa_post_set_category($oldpost['parentid'], $categoryid, $byuserid); // keep looking until we find the parent question
}
function qa_post_set_selchildid($questionid, $answerid, $byuserid=null) qa_db_post_set_created($postid, $created);
/*
Set the selected best answer of $questionid to $answerid (or to none if $answerid is null). Pass the identify of the
user in $byuserid (or null for an anonymous change).
*/
{
$oldquestion=qa_post_get_full($questionid, 'Q');
$byhandle=qa_userid_to_handle($byuserid);
$answers=qa_post_get_question_answers($questionid);
if (isset($answerid) && !isset($answers[$answerid])) switch ($oldpost['basetype']) {
qa_fatal_error('Answer ID could not be found: '.$answerid); case 'Q':
qa_db_hotness_update($postid);
break;
qa_question_set_selchildid($byuserid, $byhandle, null, $oldquestion, $answerid, $answers); case 'A':
qa_db_hotness_update($oldpost['parentid']);
break;
} }
}
function qa_post_set_closed($questionid, $closed=true, $originalpostid=null, $note=null, $byuserid=null) /**
/* * Delete $postid from the database, hiding it first if appropriate.
Closed $questionid if $closed is true, otherwise reopen it. If $closed is true, pass either the $originalpostid of * @param $postid
the question that it is a duplicate of, or a $note to explain why it's closed. Pass the identify of the user in */
$byuserid (or null for an anonymous change). function qa_post_delete($postid)
*/ {
{ $oldpost = qa_post_get_full($postid, 'QAC');
$oldquestion=qa_post_get_full($questionid, 'Q');
$oldclosepost=qa_post_get_question_closepost($questionid);
$byhandle=qa_userid_to_handle($byuserid);
if ($closed) {
if (isset($originalpostid))
qa_question_close_duplicate($oldquestion, $oldclosepost, $originalpostid, $byuserid, $byhandle, null);
elseif (isset($note))
qa_question_close_other($oldquestion, $oldclosepost, $note, $byuserid, $byhandle, null);
else
qa_fatal_error('Question must be closed as a duplicate or with a note');
} else
qa_question_close_clear($oldquestion, $oldclosepost, $byuserid, $byhandle, null);
}
if (!$oldpost['hidden']) {
function qa_post_set_hidden($postid, $hidden=true, $byuserid=null) qa_post_set_hidden($postid, true, null);
/* $oldpost = qa_post_get_full($postid, 'QAC');
Hide $postid if $hidden is true, otherwise show the post. Pass the identify of the user making this change in
$byuserid (or null for a silent change). This function is included mainly for backwards compatibility.
*/
{
qa_post_set_status($postid, $hidden ? QA_POST_STATUS_HIDDEN : QA_POST_STATUS_NORMAL, $byuserid);
} }
switch ($oldpost['basetype']) {
case 'Q':
$answers = qa_post_get_question_answers($postid);
$commentsfollows = qa_post_get_question_commentsfollows($postid);
$closepost = qa_post_get_question_closepost($postid);
function qa_post_set_status($postid, $status, $byuserid=null) if (count($answers) || count($commentsfollows))
/* qa_fatal_error('Could not delete question ID due to dependents: ' . $postid);
Change the status of $postid to $status, which should be one of the QA_POST_STATUS_* constants defined in
qa-app-post-update.php. Pass the identify of the user making this change in $byuserid (or null for a silent change).
*/
{
$oldpost=qa_post_get_full($postid, 'QAC');
$byhandle=qa_userid_to_handle($byuserid);
switch ($oldpost['basetype']) {
case 'Q':
$answers=qa_post_get_question_answers($postid);
$commentsfollows=qa_post_get_question_commentsfollows($postid);
$closepost=qa_post_get_question_closepost($postid);
qa_question_set_status($oldpost, $status, $byuserid, $byhandle, null, $answers, $commentsfollows, $closepost);
break;
case 'A':
$question=qa_post_get_full($oldpost['parentid'], 'Q');
$commentsfollows=qa_post_get_answer_commentsfollows($postid);
qa_answer_set_status($oldpost, $status, $byuserid, $byhandle, null, $question, $commentsfollows);
break;
case 'C':
$parent=qa_post_get_full($oldpost['parentid'], 'QA');
$question=qa_post_parent_to_question($parent);
qa_comment_set_status($oldpost, $status, $byuserid, $byhandle, null, $question, $parent);
break;
}
}
qa_question_delete($oldpost, null, null, null, $closepost);
break;
function qa_post_set_created($postid, $created) case 'A':
/* $question = qa_post_get_full($oldpost['parentid'], 'Q');
Set the created date of $postid to $created, which is a unix timestamp. $commentsfollows = qa_post_get_answer_commentsfollows($postid);
*/
{
$oldpost=qa_post_get_full($postid);
qa_db_post_set_created($postid, $created); if (count($commentsfollows))
qa_fatal_error('Could not delete answer ID due to dependents: ' . $postid);
switch ($oldpost['basetype']) { qa_answer_delete($oldpost, $question, null, null, null);
case 'Q': break;
qa_db_hotness_update($postid);
break;
case 'A': case 'C':
qa_db_hotness_update($oldpost['parentid']); $parent = qa_post_get_full($oldpost['parentid'], 'QA');
break; $question = qa_post_parent_to_question($parent);
} qa_comment_delete($oldpost, $question, $parent, null, null, null);
break;
} }
}
function qa_post_delete($postid)
/* /**
Delete $postid from the database, hiding it first if appropriate. * Return the full information from the database for $postid in an array.
*/ * @param $postid
{ * @param $requiredbasetypes
$oldpost=qa_post_get_full($postid, 'QAC'); * @return array|mixed
*/
if (!$oldpost['hidden']) { function qa_post_get_full($postid, $requiredbasetypes = null)
qa_post_set_hidden($postid, true, null); {
$oldpost=qa_post_get_full($postid, 'QAC'); $post = qa_db_single_select(qa_db_full_post_selectspec(null, $postid));
}
if (!is_array($post))
switch ($oldpost['basetype']) { qa_fatal_error('Post ID could not be found: ' . $postid);
case 'Q':
$answers=qa_post_get_question_answers($postid); if (isset($requiredbasetypes) && !is_numeric(strpos($requiredbasetypes, $post['basetype'])))
$commentsfollows=qa_post_get_question_commentsfollows($postid); qa_fatal_error('Post of wrong type: ' . $post['basetype']);
$closepost=qa_post_get_question_closepost($postid);
return $post;
if (count($answers) || count($commentsfollows)) }
qa_fatal_error('Could not delete question ID due to dependents: '.$postid);
qa_question_delete($oldpost, null, null, null, $closepost); /**
break; * Return the handle corresponding to $userid, unless it is null in which case return null.
*
case 'A': * @deprecated Deprecated from 1.7; use `qa_userid_to_handle($userid)` instead.
$question=qa_post_get_full($oldpost['parentid'], 'Q'); * @param $userid
$commentsfollows=qa_post_get_answer_commentsfollows($postid); * @return mixed|null
*/
if (count($commentsfollows)) function qa_post_userid_to_handle($userid)
qa_fatal_error('Could not delete answer ID due to dependents: '.$postid); {
return qa_userid_to_handle($userid);
qa_answer_delete($oldpost, $question, null, null, null); }
break;
case 'C': /**
$parent=qa_post_get_full($oldpost['parentid'], 'QA'); * Return the textual rendition of $content in $format (used for indexing).
$question=qa_post_parent_to_question($parent); * @param $content
qa_comment_delete($oldpost, $question, $parent, null, null, null); * @param $format
break; * @return
} */
function qa_post_content_to_text($content, $format)
{
$viewer = qa_load_viewer($content, $format);
if (!isset($viewer))
qa_fatal_error('Content could not be parsed in format: ' . $format);
return $viewer->get_text($content, $format, array());
}
/**
* Return tagstring to store in the database based on $tags as an array or a comma-separated string.
* @param $tags
* @return mixed|string
*/
function qa_post_tags_to_tagstring($tags)
{
if (is_array($tags))
$tags = implode(',', $tags);
return qa_tags_to_tagstring(array_unique(preg_split('/\s*,\s*/', qa_strtolower(strtr($tags, '/', ' ')), -1, PREG_SPLIT_NO_EMPTY)));
}
/**
* Return the full database records for all answers to question $questionid
* @param $questionid
* @return array
*/
function qa_post_get_question_answers($questionid)
{
$answers = array();
$childposts = qa_db_single_select(qa_db_full_child_posts_selectspec(null, $questionid));
foreach ($childposts as $postid => $post) {
if ($post['basetype'] == 'A')
$answers[$postid] = $post;
} }
return $answers;
}
function qa_post_get_full($postid, $requiredbasetypes=null)
/*
Return the full information from the database for $postid in an array.
*/
{
$post=qa_db_single_select(qa_db_full_post_selectspec(null, $postid));
if (!is_array($post)) /**
qa_fatal_error('Post ID could not be found: '.$postid); * Return the full database records for all comments or follow-on questions for question $questionid or its answers
* @param $questionid
* @return array
*/
function qa_post_get_question_commentsfollows($questionid)
{
$commentsfollows = array();
if (isset($requiredbasetypes) && !is_numeric(strpos($requiredbasetypes, $post['basetype']))) list($childposts, $achildposts) = qa_db_multi_select(array(
qa_fatal_error('Post of wrong type: '.$post['basetype']); qa_db_full_child_posts_selectspec(null, $questionid),
qa_db_full_a_child_posts_selectspec(null, $questionid),
));
return $post; foreach ($childposts as $postid => $post) {
if ($post['basetype'] == 'C')
$commentsfollows[$postid] = $post;
} }
foreach ($achildposts as $postid => $post) {
/** if (($post['basetype'] == 'Q') || ($post['basetype'] == 'C'))
* Return the handle corresponding to $userid, unless it is null in which case return null. $commentsfollows[$postid] = $post;
*
* @deprecated Deprecated from 1.7; use `qa_userid_to_handle($userid)` instead.
*/
function qa_post_userid_to_handle($userid)
{
return qa_userid_to_handle($userid);
} }
return $commentsfollows;
}
function qa_post_content_to_text($content, $format)
/*
Return the textual rendition of $content in $format (used for indexing).
*/
{
$viewer=qa_load_viewer($content, $format);
if (!isset($viewer)) /**
qa_fatal_error('Content could not be parsed in format: '.$format); * Return the full database record for the post which closed $questionid, if there is any
* @param $questionid
* @return array|mixed
*/
function qa_post_get_question_closepost($questionid)
{
return qa_db_single_select(qa_db_post_close_post_selectspec($questionid));
}
return $viewer->get_text($content, $format, array());
}
/**
* Return the full database records for all comments or follow-on questions for answer $answerid
* @param $answerid
* @return array
*/
function qa_post_get_answer_commentsfollows($answerid)
{
$commentsfollows = array();
function qa_post_tags_to_tagstring($tags) $childposts = qa_db_single_select(qa_db_full_child_posts_selectspec(null, $answerid));
/*
Return tagstring to store in the database based on $tags as an array or a comma-separated string.
*/
{
if (is_array($tags))
$tags=implode(',', $tags);
return qa_tags_to_tagstring(array_unique(preg_split('/\s*,\s*/', qa_strtolower(strtr($tags, '/', ' ')), -1, PREG_SPLIT_NO_EMPTY))); foreach ($childposts as $postid => $post) {
if (($post['basetype'] == 'Q') || ($post['basetype'] == 'C'))
$commentsfollows[$postid] = $post;
} }
return $commentsfollows;
}
function qa_post_get_question_answers($questionid)
/*
Return the full database records for all answers to question $questionid
*/
{
$answers=array();
$childposts=qa_db_single_select(qa_db_full_child_posts_selectspec(null, $questionid));
foreach ($childposts as $postid => $post)
if ($post['basetype']=='A')
$answers[$postid]=$post;
return $answers;
}
/**
* Return $parent if it's the database record for a question, otherwise return the database record for its parent
* @param $parent
* @return array|mixed
*/
function qa_post_parent_to_question($parent)
{
if ($parent['basetype'] == 'Q')
$question = $parent;
else
$question = qa_post_get_full($parent['parentid'], 'Q');
function qa_post_get_question_commentsfollows($questionid) return $question;
/* }
Return the full database records for all comments or follow-on questions for question $questionid or its answers
*/
{
$commentsfollows=array();
list($childposts, $achildposts)=qa_db_multi_select(array(
qa_db_full_child_posts_selectspec(null, $questionid),
qa_db_full_a_child_posts_selectspec(null, $questionid),
));
foreach ($childposts as $postid => $post)
if ($post['basetype']=='C')
$commentsfollows[$postid]=$post;
foreach ($achildposts as $postid => $post)
if ( ($post['basetype']=='Q') || ($post['basetype']=='C') )
$commentsfollows[$postid]=$post;
return $commentsfollows;
}
function qa_post_get_question_closepost($questionid)
/*
Return the full database record for the post which closed $questionid, if there is any
*/
{
return qa_db_single_select(qa_db_post_close_post_selectspec($questionid));
}
function qa_post_get_answer_commentsfollows($answerid)
/*
Return the full database records for all comments or follow-on questions for answer $answerid
*/
{
$commentsfollows=array();
$childposts=qa_db_single_select(qa_db_full_child_posts_selectspec(null, $answerid));
foreach ($childposts as $postid => $post)
if ( ($post['basetype']=='Q') || ($post['basetype']=='C') )
$commentsfollows[$postid]=$post;
return $commentsfollows;
}
function qa_post_parent_to_question($parent)
/*
Return $parent if it's the database record for a question, otherwise return the database record for its parent
*/
{
if ($parent['basetype']=='Q')
$question=$parent;
else
$question=qa_post_get_full($parent['parentid'], 'Q');
return $question;
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -20,199 +20,219 @@ ...@@ -20,199 +20,219 @@
More about this license: http://www.question2answer.org/license.php 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: ../'); header('Location: ../');
exit; exit;
} }
function qa_q_list_page_content($questions, $pagesize, $start, $count, $sometitle, $nonetitle, /**
$navcategories, $categoryid, $categoryqcount, $categorypathprefix, $feedpathprefix, $suggest, * Returns the $qa_content structure for a question list page showing $questions retrieved from the
$pagelinkparams=null, $categoryparams=null, $dummy=null) * database. If $pagesize is not null, it sets the max number of questions to display. If $count is
/* * not null, pagination is determined by $start and $count. The page title is $sometitle unless
Returns the $qa_content structure for a question list page showing $questions retrieved from the * there are no questions shown, in which case it's $nonetitle. $navcategories should contain the
database. If $pagesize is not null, it sets the max number of questions to display. If $count is * categories retrived from the database using qa_db_category_nav_selectspec(...) for $categoryid,
not null, pagination is determined by $start and $count. The page title is $sometitle unless * which is the current category shown. If $categorypathprefix is set, category navigation will be
there are no questions shown, in which case it's $nonetitle. $navcategories should contain the * shown, with per-category question counts if $categoryqcount is true. The nav links will have the
categories retrived from the database using qa_db_category_nav_selectspec(...) for $categoryid, * prefix $categorypathprefix and possible extra $categoryparams. If $feedpathprefix is set, the
which is the current category shown. If $categorypathprefix is set, category navigation will be * page has an RSS feed whose URL uses that prefix. If there are no links to other pages, $suggest
shown, with per-category question counts if $categoryqcount is true. The nav links will have the * is used to suggest what the user should do. The $pagelinkparams are passed through to
prefix $categorypathprefix and possible extra $categoryparams. If $feedpathprefix is set, the * qa_html_page_links(...) which creates links for page 2, 3, etc..
page has an RSS feed whose URL uses that prefix. If there are no links to other pages, $suggest * @param $questions
is used to suggest what the user should do. The $pagelinkparams are passed through to * @param $pagesize
qa_html_page_links(...) which creates links for page 2, 3, etc.. * @param $start
*/ * @param $count
{ * @param $sometitle
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } * @param $nonetitle
* @param $navcategories
require_once QA_INCLUDE_DIR.'app/format.php'; * @param $categoryid
require_once QA_INCLUDE_DIR.'app/updates.php'; * @param $categoryqcount
* @param $categorypathprefix
$userid=qa_get_logged_in_userid(); * @param $feedpathprefix
* @param $suggest
* @param $pagelinkparams
// Chop down to size, get user information for display * @param $categoryparams
* @param $dummy
if (isset($pagesize)) * @return array
$questions=array_slice($questions, 0, $pagesize); */
function qa_q_list_page_content($questions, $pagesize, $start, $count, $sometitle, $nonetitle,
$usershtml=qa_userids_handles_html(qa_any_get_userids_handles($questions)); $navcategories, $categoryid, $categoryqcount, $categorypathprefix, $feedpathprefix, $suggest,
$pagelinkparams = null, $categoryparams = null, $dummy = null)
{
// Prepare content for theme if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$qa_content=qa_content_prepare(true, array_keys(qa_category_path($navcategories, $categoryid))); require_once QA_INCLUDE_DIR . 'app/format.php';
require_once QA_INCLUDE_DIR . 'app/updates.php';
$qa_content['q_list']['form']=array(
'tags' => 'method="post" action="'.qa_self_html().'"', $userid = qa_get_logged_in_userid();
'hidden' => array(
'code' => qa_get_form_security_code('vote'), // Chop down to size, get user information for display
),
); if (isset($pagesize))
$questions = array_slice($questions, 0, $pagesize);
$qa_content['q_list']['qs'] = array();
$usershtml = qa_userids_handles_html(qa_any_get_userids_handles($questions));
if (count($questions)) {
$qa_content['title'] = $sometitle;
// Prepare content for theme
$defaults = qa_post_html_defaults('Q');
if (isset($categorypathprefix)) $qa_content = qa_content_prepare(true, array_keys(qa_category_path($navcategories, $categoryid)));
$defaults['categorypathprefix'] = $categorypathprefix;
$qa_content['q_list']['form'] = array(
foreach ($questions as $question) { 'tags' => 'method="post" action="' . qa_self_html() . '"',
$fields = qa_any_to_q_html_fields($question, $userid, qa_cookie_get(), $usershtml, null, qa_post_html_options($question, $defaults));
'hidden' => array(
if (!empty($fields['raw']['closedbyid'])) { 'code' => qa_get_form_security_code('vote'),
$fields['closed'] = array( ),
'state' => qa_lang_html('main/closed'), );
);
} $qa_content['q_list']['qs'] = array();
$qa_content['q_list']['qs'][] = $fields; if (count($questions)) {
$qa_content['title'] = $sometitle;
$defaults = qa_post_html_defaults('Q');
if (isset($categorypathprefix))
$defaults['categorypathprefix'] = $categorypathprefix;
foreach ($questions as $question) {
$fields = qa_any_to_q_html_fields($question, $userid, qa_cookie_get(), $usershtml, null, qa_post_html_options($question, $defaults));
if (!empty($fields['raw']['closedbyid'])) {
$fields['closed'] = array(
'state' => qa_lang_html('main/closed'),
);
} }
$qa_content['q_list']['qs'][] = $fields;
} }
else
$qa_content['title'] = $nonetitle;
if (isset($userid) && isset($categoryid)) {
$favoritemap=qa_get_favorite_non_qs_map();
$categoryisfavorite = @$favoritemap['category'][$navcategories[$categoryid]['backpath']];
$qa_content['favorite']=qa_favorite_form(QA_ENTITY_CATEGORY, $categoryid, $categoryisfavorite,
qa_lang_sub($categoryisfavorite ? 'main/remove_x_favorites' : 'main/add_category_x_favorites', $navcategories[$categoryid]['title']));
}
if (isset($count) && isset($pagesize))
$qa_content['page_links']=qa_html_page_links(qa_request(), $start, $pagesize, $count, qa_opt('pages_prev_next'), $pagelinkparams);
if (empty($qa_content['page_links'])) } else
$qa_content['suggest_next']=$suggest; $qa_content['title'] = $nonetitle;
if (qa_using_categories() && count($navcategories) && isset($categorypathprefix)) if (isset($userid) && isset($categoryid)) {
$qa_content['navigation']['cat']=qa_category_navigation($navcategories, $categoryid, $categorypathprefix, $categoryqcount, $categoryparams); $favoritemap = qa_get_favorite_non_qs_map();
$categoryisfavorite = @$favoritemap['category'][$navcategories[$categoryid]['backpath']];
if (isset($feedpathprefix) && (qa_opt('feed_per_category') || !isset($categoryid)) ) $qa_content['favorite'] = qa_favorite_form(QA_ENTITY_CATEGORY, $categoryid, $categoryisfavorite,
$qa_content['feed']=array( qa_lang_sub($categoryisfavorite ? 'main/remove_x_favorites' : 'main/add_category_x_favorites', $navcategories[$categoryid]['title']));
'url' => qa_path_html(qa_feed_request($feedpathprefix.(isset($categoryid) ? ('/'.qa_category_path_request($navcategories, $categoryid)) : ''))),
'label' => strip_tags($sometitle),
);
return $qa_content;
} }
if (isset($count) && isset($pagesize))
$qa_content['page_links'] = qa_html_page_links(qa_request(), $start, $pagesize, $count, qa_opt('pages_prev_next'), $pagelinkparams);
function qa_qs_sub_navigation($sort, $categoryslugs) if (empty($qa_content['page_links']))
/* $qa_content['suggest_next'] = $suggest;
Return the sub navigation structure common to question listing pages
*/
{
$request='questions';
if (isset($categoryslugs))
foreach ($categoryslugs as $slug)
$request.='/'.$slug;
$navigation=array(
'recent' => array(
'label' => qa_lang('main/nav_most_recent'),
'url' => qa_path_html($request),
),
'hot' => array(
'label' => qa_lang('main/nav_hot'),
'url' => qa_path_html($request, array('sort' => 'hot')),
),
'votes' => array(
'label' => qa_lang('main/nav_most_votes'),
'url' => qa_path_html($request, array('sort' => 'votes')),
),
'answers' => array(
'label' => qa_lang('main/nav_most_answers'),
'url' => qa_path_html($request, array('sort' => 'answers')),
),
'views' => array(
'label' => qa_lang('main/nav_most_views'),
'url' => qa_path_html($request, array('sort' => 'views')),
),
);
if (isset($navigation[$sort]))
$navigation[$sort]['selected']=true;
else
$navigation['recent']['selected']=true;
if (!qa_opt('do_count_q_views')) if (qa_using_categories() && count($navcategories) && isset($categorypathprefix))
unset($navigation['views']); $qa_content['navigation']['cat'] = qa_category_navigation($navcategories, $categoryid, $categorypathprefix, $categoryqcount, $categoryparams);
return $navigation; if (isset($feedpathprefix) && (qa_opt('feed_per_category') || !isset($categoryid)))
} $qa_content['feed'] = array(
'url' => qa_path_html(qa_feed_request($feedpathprefix . (isset($categoryid) ? ('/' . qa_category_path_request($navcategories, $categoryid)) : ''))),
'label' => strip_tags($sometitle),
function qa_unanswered_sub_navigation($by, $categoryslugs)
/*
Return the sub navigation structure common to unanswered pages
*/
{
$request='unanswered';
if (isset($categoryslugs))
foreach ($categoryslugs as $slug)
$request.='/'.$slug;
$navigation=array(
'by-answers' => array(
'label' => qa_lang('main/nav_no_answer'),
'url' => qa_path_html($request),
),
'by-selected' => array(
'label' => qa_lang('main/nav_no_selected_answer'),
'url' => qa_path_html($request, array('by' => 'selected')),
),
'by-upvotes' => array(
'label' => qa_lang('main/nav_no_upvoted_answer'),
'url' => qa_path_html($request, array('by' => 'upvotes')),
),
); );
if (isset($navigation['by-'.$by])) return $qa_content;
$navigation['by-'.$by]['selected']=true; }
else
$navigation['by-answers']['selected']=true;
if (!qa_opt('voting_on_as'))
unset($navigation['by-upvotes']);
return $navigation; /**
* Return the sub navigation structure common to question listing pages
* @param $sort
* @param $categoryslugs
* @return array
*/
function qa_qs_sub_navigation($sort, $categoryslugs)
{
$request = 'questions';
if (isset($categoryslugs)) {
foreach ($categoryslugs as $slug) {
$request .= '/' . $slug;
}
} }
$navigation = array(
'recent' => array(
'label' => qa_lang('main/nav_most_recent'),
'url' => qa_path_html($request),
),
'hot' => array(
'label' => qa_lang('main/nav_hot'),
'url' => qa_path_html($request, array('sort' => 'hot')),
),
'votes' => array(
'label' => qa_lang('main/nav_most_votes'),
'url' => qa_path_html($request, array('sort' => 'votes')),
),
'answers' => array(
'label' => qa_lang('main/nav_most_answers'),
'url' => qa_path_html($request, array('sort' => 'answers')),
),
'views' => array(
'label' => qa_lang('main/nav_most_views'),
'url' => qa_path_html($request, array('sort' => 'views')),
),
);
if (isset($navigation[$sort]))
$navigation[$sort]['selected'] = true;
else
$navigation['recent']['selected'] = true;
if (!qa_opt('do_count_q_views'))
unset($navigation['views']);
return $navigation;
}
/**
* Return the sub navigation structure common to unanswered pages
* @param $by
* @param $categoryslugs
* @return array
*/
function qa_unanswered_sub_navigation($by, $categoryslugs)
{
$request = 'unanswered';
if (isset($categoryslugs)) {
foreach ($categoryslugs as $slug) {
$request .= '/' . $slug;
}
}
/* $navigation = array(
Omit PHP closing tag to help avoid accidental output 'by-answers' => array(
*/ 'label' => qa_lang('main/nav_no_answer'),
\ No newline at end of file 'url' => qa_path_html($request),
),
'by-selected' => array(
'label' => qa_lang('main/nav_no_selected_answer'),
'url' => qa_path_html($request, array('by' => 'selected')),
),
'by-upvotes' => array(
'label' => qa_lang('main/nav_no_upvoted_answer'),
'url' => qa_path_html($request, array('by' => 'upvotes')),
),
);
if (isset($navigation['by-' . $by]))
$navigation['by-' . $by]['selected'] = true;
else
$navigation['by-answers']['selected'] = true;
if (!qa_opt('voting_on_as'))
unset($navigation['by-upvotes']);
return $navigation;
}
...@@ -61,26 +61,28 @@ if (!defined('QA_VERSION')) { // don't allow this page to be requested directly ...@@ -61,26 +61,28 @@ if (!defined('QA_VERSION')) { // don't allow this page to be requested directly
exit; exit;
} }
require_once QA_INCLUDE_DIR.'db/recalc.php'; require_once QA_INCLUDE_DIR . 'db/recalc.php';
require_once QA_INCLUDE_DIR.'db/post-create.php'; require_once QA_INCLUDE_DIR . 'db/post-create.php';
require_once QA_INCLUDE_DIR.'db/points.php'; require_once QA_INCLUDE_DIR . 'db/points.php';
require_once QA_INCLUDE_DIR.'db/selects.php'; require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR.'db/admin.php'; require_once QA_INCLUDE_DIR . 'db/admin.php';
require_once QA_INCLUDE_DIR.'db/users.php'; require_once QA_INCLUDE_DIR . 'db/users.php';
require_once QA_INCLUDE_DIR.'app/options.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-create.php';
require_once QA_INCLUDE_DIR.'app/post-update.php'; require_once QA_INCLUDE_DIR . 'app/post-update.php';
/** /**
* Advance the recalculation operation represented by $state by a single step. * Advance the recalculation operation represented by $state by a single step.
* $state can also be the name of a recalculation operation on its own. * $state can also be the name of a recalculation operation on its own.
* @param $state
* @return bool
*/ */
function qa_recalc_perform_step(&$state) function qa_recalc_perform_step(&$state)
{ {
$continue=false; $continue = false;
@list($operation, $length, $next, $done)=explode("\t", $state); @list($operation, $length, $next, $done) = explode("\t", $state);
switch ($operation) { switch ($operation) {
case 'doreindexcontent': case 'doreindexcontent':
...@@ -88,31 +90,32 @@ function qa_recalc_perform_step(&$state) ...@@ -88,31 +90,32 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'doreindexcontent_pagereindex': case 'doreindexcontent_pagereindex':
$pages=qa_db_pages_get_for_reindexing($next, 10); $pages = qa_db_pages_get_for_reindexing($next, 10);
if (count($pages)) { if (count($pages)) {
require_once QA_INCLUDE_DIR.'app/format.php'; require_once QA_INCLUDE_DIR . 'app/format.php';
$lastpageid=max(array_keys($pages)); $lastpageid = max(array_keys($pages));
foreach ($pages as $pageid => $page) foreach ($pages as $pageid => $page) {
if (!($page['flags'] & QA_PAGE_FLAGS_EXTERNAL)) { if (!($page['flags'] & QA_PAGE_FLAGS_EXTERNAL)) {
$searchmodules=qa_load_modules_with('search', 'unindex_page'); $searchmodules = qa_load_modules_with('search', 'unindex_page');
foreach ($searchmodules as $searchmodule) foreach ($searchmodules as $searchmodule)
$searchmodule->unindex_page($pageid); $searchmodule->unindex_page($pageid);
$searchmodules=qa_load_modules_with('search', 'index_page'); $searchmodules = qa_load_modules_with('search', 'index_page');
if (count($searchmodules)) { if (count($searchmodules)) {
$indextext=qa_viewer_text($page['content'], 'html'); $indextext = qa_viewer_text($page['content'], 'html');
foreach ($searchmodules as $searchmodule) foreach ($searchmodules as $searchmodule)
$searchmodule->index_page($pageid, $page['tags'], $page['heading'], $page['content'], 'html', $indextext); $searchmodule->index_page($pageid, $page['tags'], $page['heading'], $page['content'], 'html', $indextext);
} }
} }
}
$next=1+$lastpageid; $next = 1 + $lastpageid;
$done+=count($pages); $done += count($pages);
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'doreindexcontent_postcount'); qa_recalc_transition($state, 'doreindexcontent_postcount');
...@@ -127,12 +130,12 @@ function qa_recalc_perform_step(&$state) ...@@ -127,12 +130,12 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'doreindexcontent_postreindex': case 'doreindexcontent_postreindex':
$posts=qa_db_posts_get_for_reindexing($next, 10); $posts = qa_db_posts_get_for_reindexing($next, 10);
if (count($posts)) { if (count($posts)) {
require_once QA_INCLUDE_DIR.'app/format.php'; require_once QA_INCLUDE_DIR . 'app/format.php';
$lastpostid=max(array_keys($posts)); $lastpostid = max(array_keys($posts));
qa_db_prepare_for_reindexing($next, $lastpostid); qa_db_prepare_for_reindexing($next, $lastpostid);
qa_suspend_update_counts(); qa_suspend_update_counts();
...@@ -143,9 +146,9 @@ function qa_recalc_perform_step(&$state) ...@@ -143,9 +146,9 @@ function qa_recalc_perform_step(&$state)
$post['format'], qa_viewer_text($post['content'], $post['format']), $post['tags'], $post['categoryid']); $post['format'], qa_viewer_text($post['content'], $post['format']), $post['tags'], $post['categoryid']);
} }
$next=1+$lastpostid; $next = 1 + $lastpostid;
$done+=count($posts); $done += count($posts);
$continue=true; $continue = true;
} else { } else {
qa_db_truncate_indexes($next); qa_db_truncate_indexes($next);
...@@ -154,16 +157,16 @@ function qa_recalc_perform_step(&$state) ...@@ -154,16 +157,16 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'doreindexposts_wordcount': case 'doreindexposts_wordcount':
$wordids=qa_db_words_prepare_for_recounting($next, 1000); $wordids = qa_db_words_prepare_for_recounting($next, 1000);
if (count($wordids)) { if (count($wordids)) {
$lastwordid=max($wordids); $lastwordid = max($wordids);
qa_db_words_recount($next, $lastwordid); qa_db_words_recount($next, $lastwordid);
$next=1+$lastwordid; $next = 1 + $lastwordid;
$done+=count($wordids); $done += count($wordids);
$continue=true; $continue = true;
} else { } else {
qa_db_tagcount_update(); // this is quick so just do it here qa_db_tagcount_update(); // this is quick so just do it here
...@@ -186,32 +189,32 @@ function qa_recalc_perform_step(&$state) ...@@ -186,32 +189,32 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'dorecountposts_votecount': case 'dorecountposts_votecount':
$postids=qa_db_posts_get_for_recounting($next, 1000); $postids = qa_db_posts_get_for_recounting($next, 1000);
if (count($postids)) { if (count($postids)) {
$lastpostid=max($postids); $lastpostid = max($postids);
qa_db_posts_votes_recount($next, $lastpostid); qa_db_posts_votes_recount($next, $lastpostid);
$next=1+$lastpostid; $next = 1 + $lastpostid;
$done+=count($postids); $done += count($postids);
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'dorecountposts_acount'); qa_recalc_transition($state, 'dorecountposts_acount');
break; break;
case 'dorecountposts_acount': case 'dorecountposts_acount':
$postids=qa_db_posts_get_for_recounting($next, 1000); $postids = qa_db_posts_get_for_recounting($next, 1000);
if (count($postids)) { if (count($postids)) {
$lastpostid=max($postids); $lastpostid = max($postids);
qa_db_posts_answers_recount($next, $lastpostid); qa_db_posts_answers_recount($next, $lastpostid);
$next=1+$lastpostid; $next = 1 + $lastpostid;
$done+=count($postids); $done += count($postids);
$continue=true; $continue = true;
} else { } else {
qa_db_unupaqcount_update(); qa_db_unupaqcount_update();
...@@ -230,22 +233,22 @@ function qa_recalc_perform_step(&$state) ...@@ -230,22 +233,22 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'dorecalcpoints_recalc': case 'dorecalcpoints_recalc':
$recalccount=10; $recalccount = 10;
$userids=qa_db_users_get_for_recalc_points($next, $recalccount+1); // get one extra so we know where to start from next $userids = qa_db_users_get_for_recalc_points($next, $recalccount + 1); // get one extra so we know where to start from next
$gotcount=count($userids); $gotcount = count($userids);
$recalccount=min($recalccount, $gotcount); // can't recalc more than we got $recalccount = min($recalccount, $gotcount); // can't recalc more than we got
if ($recalccount>0) { if ($recalccount > 0) {
$lastuserid=$userids[$recalccount-1]; $lastuserid = $userids[$recalccount - 1];
qa_db_users_recalc_points($next, $lastuserid); qa_db_users_recalc_points($next, $lastuserid);
$done+=$recalccount; $done += $recalccount;
} else } else
$lastuserid=$next; // for truncation $lastuserid = $next; // for truncation
if ($gotcount>$recalccount) { // more left to do if ($gotcount > $recalccount) { // more left to do
$next=$userids[$recalccount]; // start next round at first one not recalculated $next = $userids[$recalccount]; // start next round at first one not recalculated
$continue=true; $continue = true;
} else { } else {
qa_db_truncate_userpoints($lastuserid); qa_db_truncate_userpoints($lastuserid);
...@@ -264,20 +267,20 @@ function qa_recalc_perform_step(&$state) ...@@ -264,20 +267,20 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'dorefillevents_refill': case 'dorefillevents_refill':
$questionids=qa_db_qs_get_for_event_refilling($next, 1); $questionids = qa_db_qs_get_for_event_refilling($next, 1);
if (count($questionids)) { if (count($questionids)) {
require_once QA_INCLUDE_DIR.'app/events.php'; require_once QA_INCLUDE_DIR . 'app/events.php';
require_once QA_INCLUDE_DIR.'app/updates.php'; require_once QA_INCLUDE_DIR . 'app/updates.php';
require_once QA_INCLUDE_DIR.'util/sort.php'; require_once QA_INCLUDE_DIR . 'util/sort.php';
$lastquestionid=max($questionids); $lastquestionid = max($questionids);
foreach ($questionids as $questionid) { foreach ($questionids as $questionid) {
// Retrieve all posts relating to this question // Retrieve all posts relating to this question
list($question, $childposts, $achildposts)=qa_db_select_with_pending( list($question, $childposts, $achildposts) = qa_db_select_with_pending(
qa_db_full_post_selectspec(null, $questionid), qa_db_full_post_selectspec(null, $questionid),
qa_db_full_child_posts_selectspec(null, $questionid), qa_db_full_child_posts_selectspec(null, $questionid),
qa_db_full_a_child_posts_selectspec(null, $questionid) qa_db_full_a_child_posts_selectspec(null, $questionid)
...@@ -285,27 +288,27 @@ function qa_recalc_perform_step(&$state) ...@@ -285,27 +288,27 @@ function qa_recalc_perform_step(&$state)
// Merge all posts while preserving keys as postids // Merge all posts while preserving keys as postids
$posts=array($questionid => $question); $posts = array($questionid => $question);
foreach ($childposts as $postid => $post) foreach ($childposts as $postid => $post)
$posts[$postid]=$post; $posts[$postid] = $post;
foreach ($achildposts as $postid => $post) foreach ($achildposts as $postid => $post)
$posts[$postid]=$post; $posts[$postid] = $post;
// Creation and editing of each post // Creation and editing of each post
foreach ($posts as $postid => $post) { foreach ($posts as $postid => $post) {
$followonq=($post['basetype']=='Q') && ($postid!=$questionid); $followonq = ($post['basetype'] == 'Q') && ($postid != $questionid);
if ($followonq) if ($followonq)
$updatetype=QA_UPDATE_FOLLOWS; $updatetype = QA_UPDATE_FOLLOWS;
elseif ( ($post['basetype']=='C') && (@$posts[$post['parentid']]['basetype']=='Q') ) elseif (($post['basetype'] == 'C') && (@$posts[$post['parentid']]['basetype'] == 'Q'))
$updatetype=QA_UPDATE_C_FOR_Q; $updatetype = QA_UPDATE_C_FOR_Q;
elseif ( ($post['basetype']=='C') && (@$posts[$post['parentid']]['basetype']=='A') ) elseif (($post['basetype'] == 'C') && (@$posts[$post['parentid']]['basetype'] == 'A'))
$updatetype=QA_UPDATE_C_FOR_A; $updatetype = QA_UPDATE_C_FOR_A;
else else
$updatetype=null; $updatetype = null;
qa_create_event_for_q_user($questionid, $postid, $updatetype, $post['userid'], @$posts[$post['parentid']]['userid'], $post['created']); qa_create_event_for_q_user($questionid, $postid, $updatetype, $post['userid'], @$posts[$post['parentid']]['userid'], $post['created']);
...@@ -320,33 +323,33 @@ function qa_recalc_perform_step(&$state) ...@@ -320,33 +323,33 @@ function qa_recalc_perform_step(&$state)
// Collect comment threads // Collect comment threads
$parentidcomments=array(); $parentidcomments = array();
foreach ($posts as $postid => $post) foreach ($posts as $postid => $post)
if ($post['basetype']=='C') if ($post['basetype'] == 'C')
$parentidcomments[$post['parentid']][$postid]=$post; $parentidcomments[$post['parentid']][$postid] = $post;
// For each comment thread, notify all previous comment authors of each comment in the thread (could get slow) // For each comment thread, notify all previous comment authors of each comment in the thread (could get slow)
foreach ($parentidcomments as $parentid => $comments) { foreach ($parentidcomments as $parentid => $comments) {
$keyuserids=array(); $keyuserids = array();
qa_sort_by($comments, 'created'); qa_sort_by($comments, 'created');
foreach ($comments as $comment) { foreach ($comments as $comment) {
foreach ($keyuserids as $keyuserid => $dummy) foreach ($keyuserids as $keyuserid => $dummy)
if ( ($keyuserid != $comment['userid']) && ($keyuserid != @$posts[$parentid]['userid']) ) if (($keyuserid != $comment['userid']) && ($keyuserid != @$posts[$parentid]['userid']))
qa_db_event_create_not_entity($keyuserid, $questionid, $comment['postid'], QA_UPDATE_FOLLOWS, $comment['userid'], $comment['created']); qa_db_event_create_not_entity($keyuserid, $questionid, $comment['postid'], QA_UPDATE_FOLLOWS, $comment['userid'], $comment['created']);
if (isset($comment['userid'])) if (isset($comment['userid']))
$keyuserids[$comment['userid']]=true; $keyuserids[$comment['userid']] = true;
} }
} }
} }
$next=1+$lastquestionid; $next = 1 + $lastquestionid;
$done+=count($questionids); $done += count($questionids);
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'dorefillevents_complete'); qa_recalc_transition($state, 'dorefillevents_complete');
...@@ -364,17 +367,17 @@ function qa_recalc_perform_step(&$state) ...@@ -364,17 +367,17 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'dorecalccategories_postupdate': case 'dorecalccategories_postupdate':
$postids=qa_db_posts_get_for_recategorizing($next, 100); $postids = qa_db_posts_get_for_recategorizing($next, 100);
if (count($postids)) { if (count($postids)) {
$lastpostid=max($postids); $lastpostid = max($postids);
qa_db_posts_recalc_categoryid($next, $lastpostid); qa_db_posts_recalc_categoryid($next, $lastpostid);
qa_db_posts_calc_category_path($next, $lastpostid); qa_db_posts_calc_category_path($next, $lastpostid);
$next=1+$lastpostid; $next = 1 + $lastpostid;
$done+=count($postids); $done += count($postids);
$continue=true; $continue = true;
} else { } else {
qa_recalc_transition($state, 'dorecalccategories_recount'); qa_recalc_transition($state, 'dorecalccategories_recount');
...@@ -382,17 +385,17 @@ function qa_recalc_perform_step(&$state) ...@@ -382,17 +385,17 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'dorecalccategories_recount': case 'dorecalccategories_recount':
$categoryids=qa_db_categories_get_for_recalcs($next, 10); $categoryids = qa_db_categories_get_for_recalcs($next, 10);
if (count($categoryids)) { if (count($categoryids)) {
$lastcategoryid=max($categoryids); $lastcategoryid = max($categoryids);
foreach ($categoryids as $categoryid) foreach ($categoryids as $categoryid)
qa_db_ifcategory_qcount_update($categoryid); qa_db_ifcategory_qcount_update($categoryid);
$next=1+$lastcategoryid; $next = 1 + $lastcategoryid;
$done+=count($categoryids); $done += count($categoryids);
$continue=true; $continue = true;
} else { } else {
qa_recalc_transition($state, 'dorecalccategories_backpaths'); qa_recalc_transition($state, 'dorecalccategories_backpaths');
...@@ -400,16 +403,16 @@ function qa_recalc_perform_step(&$state) ...@@ -400,16 +403,16 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'dorecalccategories_backpaths': case 'dorecalccategories_backpaths':
$categoryids=qa_db_categories_get_for_recalcs($next, 10); $categoryids = qa_db_categories_get_for_recalcs($next, 10);
if (count($categoryids)) { if (count($categoryids)) {
$lastcategoryid=max($categoryids); $lastcategoryid = max($categoryids);
qa_db_categories_recalc_backpaths($next, $lastcategoryid); qa_db_categories_recalc_backpaths($next, $lastcategoryid);
$next=1+$lastcategoryid; $next = 1 + $lastcategoryid;
$done+=count($categoryids); $done += count($categoryids);
$continue=true; $continue = true;
} else { } else {
qa_recalc_transition($state, 'dorecalccategories_complete'); qa_recalc_transition($state, 'dorecalccategories_complete');
...@@ -421,54 +424,54 @@ function qa_recalc_perform_step(&$state) ...@@ -421,54 +424,54 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'dodeletehidden_comments': case 'dodeletehidden_comments':
$posts=qa_db_posts_get_for_deleting('C', $next, 1); $posts = qa_db_posts_get_for_deleting('C', $next, 1);
if (count($posts)) { if (count($posts)) {
require_once QA_INCLUDE_DIR.'app/posts.php'; require_once QA_INCLUDE_DIR . 'app/posts.php';
$postid=$posts[0]; $postid = $posts[0];
qa_post_delete($postid); qa_post_delete($postid);
$next=1+$postid; $next = 1 + $postid;
$done++; $done++;
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'dodeletehidden_answers'); qa_recalc_transition($state, 'dodeletehidden_answers');
break; break;
case 'dodeletehidden_answers': case 'dodeletehidden_answers':
$posts=qa_db_posts_get_for_deleting('A', $next, 1); $posts = qa_db_posts_get_for_deleting('A', $next, 1);
if (count($posts)) { if (count($posts)) {
require_once QA_INCLUDE_DIR.'app/posts.php'; require_once QA_INCLUDE_DIR . 'app/posts.php';
$postid=$posts[0]; $postid = $posts[0];
qa_post_delete($postid); qa_post_delete($postid);
$next=1+$postid; $next = 1 + $postid;
$done++; $done++;
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'dodeletehidden_questions'); qa_recalc_transition($state, 'dodeletehidden_questions');
break; break;
case 'dodeletehidden_questions': case 'dodeletehidden_questions':
$posts=qa_db_posts_get_for_deleting('Q', $next, 1); $posts = qa_db_posts_get_for_deleting('Q', $next, 1);
if (count($posts)) { if (count($posts)) {
require_once QA_INCLUDE_DIR.'app/posts.php'; require_once QA_INCLUDE_DIR . 'app/posts.php';
$postid=$posts[0]; $postid = $posts[0];
qa_post_delete($postid); qa_post_delete($postid);
$next=1+$postid; $next = 1 + $postid;
$done++; $done++;
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'dodeletehidden_complete'); qa_recalc_transition($state, 'dodeletehidden_complete');
...@@ -479,18 +482,18 @@ function qa_recalc_perform_step(&$state) ...@@ -479,18 +482,18 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'doblobstodisk_move': case 'doblobstodisk_move':
$blob=qa_db_get_next_blob_in_db($next); $blob = qa_db_get_next_blob_in_db($next);
if (isset($blob)) { if (isset($blob)) {
require_once QA_INCLUDE_DIR.'app/blobs.php'; require_once QA_INCLUDE_DIR . 'app/blobs.php';
require_once QA_INCLUDE_DIR.'db/blobs.php'; require_once QA_INCLUDE_DIR . 'db/blobs.php';
if (qa_write_blob_file($blob['blobid'], $blob['content'], $blob['format'])) if (qa_write_blob_file($blob['blobid'], $blob['content'], $blob['format']))
qa_db_blob_set_content($blob['blobid'], null); qa_db_blob_set_content($blob['blobid'], null);
$next=1+$blob['blobid']; $next = 1 + $blob['blobid'];
$done++; $done++;
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'doblobstodisk_complete'); qa_recalc_transition($state, 'doblobstodisk_complete');
...@@ -501,108 +504,112 @@ function qa_recalc_perform_step(&$state) ...@@ -501,108 +504,112 @@ function qa_recalc_perform_step(&$state)
break; break;
case 'doblobstodb_move': case 'doblobstodb_move':
$blob=qa_db_get_next_blob_on_disk($next); $blob = qa_db_get_next_blob_on_disk($next);
if (isset($blob)) { if (isset($blob)) {
require_once QA_INCLUDE_DIR.'app/blobs.php'; require_once QA_INCLUDE_DIR . 'app/blobs.php';
require_once QA_INCLUDE_DIR.'db/blobs.php'; require_once QA_INCLUDE_DIR . 'db/blobs.php';
$content=qa_read_blob_file($blob['blobid'], $blob['format']); $content = qa_read_blob_file($blob['blobid'], $blob['format']);
qa_db_blob_set_content($blob['blobid'], $content); qa_db_blob_set_content($blob['blobid'], $content);
qa_delete_blob_file($blob['blobid'], $blob['format']); qa_delete_blob_file($blob['blobid'], $blob['format']);
$next=1+$blob['blobid']; $next = 1 + $blob['blobid'];
$done++; $done++;
$continue=true; $continue = true;
} else } else
qa_recalc_transition($state, 'doblobstodb_complete'); qa_recalc_transition($state, 'doblobstodb_complete');
break; break;
default: default:
$state=''; $state = '';
break; break;
} }
if ($continue) if ($continue)
$state=$operation."\t".$length."\t".$next."\t".$done; $state = $operation . "\t" . $length . "\t" . $next . "\t" . $done;
return $continue && ($done<$length); return $continue && ($done < $length);
} }
/** /**
* Change the $state to represent the beginning of a new $operation * Change the $state to represent the beginning of a new $operation
* @param $state
* @param $operation
*/ */
function qa_recalc_transition(&$state, $operation) function qa_recalc_transition(&$state, $operation)
{ {
$length=qa_recalc_stage_length($operation); $length = qa_recalc_stage_length($operation);
$next=(QA_FINAL_EXTERNAL_USERS && ($operation=='dorecalcpoints_recalc')) ? '' : 0; $next = (QA_FINAL_EXTERNAL_USERS && ($operation == 'dorecalcpoints_recalc')) ? '' : 0;
$done=0; $done = 0;
$state=$operation."\t".$length."\t".$next."\t".$done; $state = $operation . "\t" . $length . "\t" . $next . "\t" . $done;
} }
/** /**
* Return how many steps there will be in recalculation $operation * Return how many steps there will be in recalculation $operation
* @param $operation
* @return int
*/ */
function qa_recalc_stage_length($operation) function qa_recalc_stage_length($operation)
{ {
switch ($operation) { switch ($operation) {
case 'doreindexcontent_pagereindex': case 'doreindexcontent_pagereindex':
$length=qa_db_count_pages(); $length = qa_db_count_pages();
break; break;
case 'doreindexcontent_postreindex': case 'doreindexcontent_postreindex':
$length=qa_opt('cache_qcount')+qa_opt('cache_acount')+qa_opt('cache_ccount'); $length = qa_opt('cache_qcount') + qa_opt('cache_acount') + qa_opt('cache_ccount');
break; break;
case 'doreindexposts_wordcount': case 'doreindexposts_wordcount':
$length=qa_db_count_words(); $length = qa_db_count_words();
break; break;
case 'dorecalcpoints_recalc': case 'dorecalcpoints_recalc':
$length=qa_opt('cache_userpointscount'); $length = qa_opt('cache_userpointscount');
break; break;
case 'dorecountposts_votecount': case 'dorecountposts_votecount':
case 'dorecountposts_acount': case 'dorecountposts_acount':
case 'dorecalccategories_postupdate': case 'dorecalccategories_postupdate':
$length=qa_db_count_posts(); $length = qa_db_count_posts();
break; break;
case 'dorefillevents_refill': case 'dorefillevents_refill':
$length=qa_opt('cache_qcount')+qa_db_count_posts('Q_HIDDEN'); $length = qa_opt('cache_qcount') + qa_db_count_posts('Q_HIDDEN');
break; break;
case 'dorecalccategories_recount': case 'dorecalccategories_recount':
case 'dorecalccategories_backpaths': case 'dorecalccategories_backpaths':
$length=qa_db_count_categories(); $length = qa_db_count_categories();
break; break;
case 'dodeletehidden_comments': case 'dodeletehidden_comments':
$length=count(qa_db_posts_get_for_deleting('C')); $length = count(qa_db_posts_get_for_deleting('C'));
break; break;
case 'dodeletehidden_answers': case 'dodeletehidden_answers':
$length=count(qa_db_posts_get_for_deleting('A')); $length = count(qa_db_posts_get_for_deleting('A'));
break; break;
case 'dodeletehidden_questions': case 'dodeletehidden_questions':
$length=count(qa_db_posts_get_for_deleting('Q')); $length = count(qa_db_posts_get_for_deleting('Q'));
break; break;
case 'doblobstodisk_move': case 'doblobstodisk_move':
$length=qa_db_count_blobs_in_db(); $length = qa_db_count_blobs_in_db();
break; break;
case 'doblobstodb_move': case 'doblobstodb_move':
$length=qa_db_count_blobs_on_disk(); $length = qa_db_count_blobs_on_disk();
break; break;
default: default:
$length=0; $length = 0;
break; break;
} }
...@@ -624,13 +631,15 @@ function qa_recalc_progress_lang($langId, $progress, $total) ...@@ -624,13 +631,15 @@ function qa_recalc_progress_lang($langId, $progress, $total)
{ {
return strtr(qa_lang($langId), array( return strtr(qa_lang($langId), array(
'^1' => qa_format_number($progress), '^1' => qa_format_number($progress),
'^2' => qa_format_number($total) '^2' => qa_format_number($total),
)); ));
} }
/** /**
* Return a string which gives a user-viewable version of $state * Return a string which gives a user-viewable version of $state
* @param $state
* @return string
*/ */
function qa_recalc_get_message($state) function qa_recalc_get_message($state)
{ {
...@@ -638,8 +647,8 @@ function qa_recalc_get_message($state) ...@@ -638,8 +647,8 @@ function qa_recalc_get_message($state)
@list($operation, $length, $next, $done) = explode("\t", $state); @list($operation, $length, $next, $done) = explode("\t", $state);
$done = (int) $done; $done = (int)$done;
$length = (int) $length; $length = (int)$length;
switch ($operation) { switch ($operation) {
case 'doreindexcontent_postcount': case 'doreindexcontent_postcount':
......
...@@ -20,121 +20,122 @@ ...@@ -20,121 +20,122 @@
More about this license: http://www.question2answer.org/license.php 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: ../'); header('Location: ../');
exit; exit;
}
/**
* Returns $count search results for $query performed by $userid, starting at offset $start. Set $absoluteurls to true
* to get absolute URLs for the results and $fullcontent if the results should include full post content. This calls
* through to the chosen search module, and performs all the necessary post-processing to supplement the results for
* display online or in an RSS feed.
* @param $query
* @param $start
* @param $count
* @param $userid
* @param $absoluteurls
* @param $fullcontent
* @return
*/
function qa_get_search_results($query, $start, $count, $userid, $absoluteurls, $fullcontent)
{
// Identify which search module should be used
$searchmodules = qa_load_modules_with('search', 'process_search');
if (!count($searchmodules))
qa_fatal_error('No search engine is available');
$module = reset($searchmodules); // use first one by default
if (count($searchmodules) > 1) {
$tryname = qa_opt('search_module'); // use chosen one if it's available
if (isset($searchmodules[$tryname]))
$module = $searchmodules[$tryname];
} }
// Get the results
function qa_get_search_results($query, $start, $count, $userid, $absoluteurls, $fullcontent) $results = $module->process_search($query, $start, $count, $userid, $absoluteurls, $fullcontent);
/*
Returns $count search results for $query performed by $userid, starting at offset $start. Set $absoluteurls to true
to get absolute URLs for the results and $fullcontent if the results should include full post content. This calls
through to the chosen search module, and performs all the necessary post-processing to supplement the results for
display online or in an RSS feed.
*/
{
// Identify which search module should be used // Work out what additional information (if any) we need to retrieve for the results
$searchmodules=qa_load_modules_with('search', 'process_search'); $keypostidgetfull = array();
$keypostidgettype = array();
$keypostidgetquestion = array();
$keypageidgetpage = array();
if (!count($searchmodules)) foreach ($results as $result) {
qa_fatal_error('No search engine is available'); if (isset($result['question_postid']) && !isset($result['question']))
$keypostidgetfull[$result['question_postid']] = true;
$module=reset($searchmodules); // use first one by default if (isset($result['match_postid'])) {
if (!((isset($result['question_postid'])) || (isset($result['question']))))
$keypostidgetquestion[$result['match_postid']] = true; // we can also get $result['match_type'] from this
if (count($searchmodules)>1) { elseif (!isset($result['match_type']))
$tryname=qa_opt('search_module'); // use chosen one if it's available $keypostidgettype[$result['match_postid']] = true;
if (isset($searchmodules[$tryname]))
$module=$searchmodules[$tryname];
} }
// Get the results if (isset($result['page_pageid']) && !isset($result['page']))
$keypageidgetpage[$result['page_pageid']] = true;
}
$results=$module->process_search($query, $start, $count, $userid, $absoluteurls, $fullcontent); // Perform the appropriate database queries
// Work out what additional information (if any) we need to retrieve for the results list($postidfull, $postidtype, $postidquestion, $pageidpage) = qa_db_select_with_pending(
count($keypostidgetfull) ? qa_db_posts_selectspec($userid, array_keys($keypostidgetfull), $fullcontent) : null,
count($keypostidgettype) ? qa_db_posts_basetype_selectspec(array_keys($keypostidgettype)) : null,
count($keypostidgetquestion) ? qa_db_posts_to_qs_selectspec($userid, array_keys($keypostidgetquestion), $fullcontent) : null,
count($keypageidgetpage) ? qa_db_pages_selectspec(null, array_keys($keypageidgetpage)) : null
);
$keypostidgetfull=array(); // Supplement the results as appropriate
$keypostidgettype=array();
$keypostidgetquestion=array();
$keypageidgetpage=array();
foreach ($results as $result) { foreach ($results as $key => $result) {
if (isset($result['question_postid']) && !isset($result['question'])) if (isset($result['question_postid']) && !isset($result['question']))
$keypostidgetfull[$result['question_postid']]=true; if (@$postidfull[$result['question_postid']]['basetype'] == 'Q')
$result['question'] = @$postidfull[$result['question_postid']];
if (isset($result['match_postid'])) { if (isset($result['match_postid'])) {
if (!( (isset($result['question_postid'])) || (isset($result['question'])) )) if (!(isset($result['question_postid']) || isset($result['question']))) {
$keypostidgetquestion[$result['match_postid']]=true; // we can also get $result['match_type'] from this $result['question'] = @$postidquestion[$result['match_postid']];
elseif (!isset($result['match_type'])) if (!isset($result['match_type']))
$keypostidgettype[$result['match_postid']]=true; $result['match_type'] = @$result['question']['obasetype'];
}
if (isset($result['page_pageid']) && !isset($result['page'])) } elseif (!isset($result['match_type']))
$keypageidgetpage[$result['page_pageid']]=true; $result['match_type'] = @$postidtype[$result['match_postid']];
} }
// Perform the appropriate database queries if (isset($result['question']) && !isset($result['question_postid']))
$result['question_postid'] = $result['question']['postid'];
list($postidfull, $postidtype, $postidquestion, $pageidpage)=qa_db_select_with_pending(
count($keypostidgetfull) ? qa_db_posts_selectspec($userid, array_keys($keypostidgetfull), $fullcontent) : null,
count($keypostidgettype) ? qa_db_posts_basetype_selectspec(array_keys($keypostidgettype)) : null,
count($keypostidgetquestion) ? qa_db_posts_to_qs_selectspec($userid, array_keys($keypostidgetquestion), $fullcontent) : null,
count($keypageidgetpage) ? qa_db_pages_selectspec(null, array_keys($keypageidgetpage)) : null
);
// Supplement the results as appropriate
foreach ($results as $key => $result) {
if (isset($result['question_postid']) && !isset($result['question']))
if (@$postidfull[$result['question_postid']]['basetype']=='Q')
$result['question']=@$postidfull[$result['question_postid']];
if (isset($result['match_postid'])) {
if (!( (isset($result['question_postid'])) || (isset($result['question'])) )) {
$result['question']=@$postidquestion[$result['match_postid']];
if (!isset($result['match_type'])) if (isset($result['page_pageid']) && !isset($result['page']))
$result['match_type']=@$result['question']['obasetype']; $result['page'] = @$pageidpage[$result['page_pageid']];
} elseif (!isset($result['match_type'])) if (!isset($result['title'])) {
$result['match_type']=@$postidtype[$result['match_postid']]; if (isset($result['question']))
} $result['title'] = $result['question']['title'];
elseif (isset($result['page']))
if (isset($result['question']) && !isset($result['question_postid'])) $result['title'] = $result['page']['heading'];
$result['question_postid']=$result['question']['postid'];
if (isset($result['page_pageid']) && !isset($result['page']))
$result['page']=@$pageidpage[$result['page_pageid']];
if (!isset($result['title'])) {
if (isset($result['question']))
$result['title']=$result['question']['title'];
elseif (isset($result['page']))
$result['title']=$result['page']['heading'];
}
if (!isset($result['url'])) {
if (isset($result['question']))
$result['url']=qa_q_path($result['question']['postid'], $result['question']['title'],
$absoluteurls, @$result['match_type'], @$result['match_postid']);
elseif (isset($result['page']))
$result['url']=qa_path($result['page']['tags'], null, qa_opt('site_url'));
}
$results[$key]=$result;
} }
// Return the results if (!isset($result['url'])) {
if (isset($result['question']))
$result['url'] = qa_q_path($result['question']['postid'], $result['question']['title'],
$absoluteurls, @$result['match_type'], @$result['match_postid']);
elseif (isset($result['page']))
$result['url'] = qa_path($result['page']['tags'], null, qa_opt('site_url'));
}
return $results; $results[$key] = $result;
} }
// Return the results
/* return $results;
Omit PHP closing tag to help avoid accidental output }
*/
\ No newline at end of file
...@@ -20,39 +20,35 @@ ...@@ -20,39 +20,35 @@
More about this license: http://www.question2answer.org/license.php 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: ../'); header('Location: ../');
exit; exit;
} }
// Character codes for the different types of entity that can be followed (entitytype columns) // Character codes for the different types of entity that can be followed (entitytype columns)
define('QA_ENTITY_QUESTION', 'Q'); define('QA_ENTITY_QUESTION', 'Q');
define('QA_ENTITY_USER', 'U'); define('QA_ENTITY_USER', 'U');
define('QA_ENTITY_TAG', 'T'); define('QA_ENTITY_TAG', 'T');
define('QA_ENTITY_CATEGORY', 'C'); define('QA_ENTITY_CATEGORY', 'C');
define('QA_ENTITY_NONE', '-'); define('QA_ENTITY_NONE', '-');
// Character codes for the different types of updates on a post (updatetype columns) // Character codes for the different types of updates on a post (updatetype columns)
define('QA_UPDATE_CATEGORY', 'A'); // questions only, category changed define('QA_UPDATE_CATEGORY', 'A'); // questions only, category changed
define('QA_UPDATE_CLOSED', 'C'); // questions only, closed or reopened define('QA_UPDATE_CLOSED', 'C'); // questions only, closed or reopened
define('QA_UPDATE_CONTENT', 'E'); // title or content edited define('QA_UPDATE_CONTENT', 'E'); // title or content edited
define('QA_UPDATE_PARENT', 'M'); // e.g. comment moved when converting its parent answer to a comment define('QA_UPDATE_PARENT', 'M'); // e.g. comment moved when converting its parent answer to a comment
define('QA_UPDATE_SELECTED', 'S'); // answers only, removed if unselected define('QA_UPDATE_SELECTED', 'S'); // answers only, removed if unselected
define('QA_UPDATE_TAGS', 'T'); // questions only define('QA_UPDATE_TAGS', 'T'); // questions only
define('QA_UPDATE_TYPE', 'Y'); // e.g. answer to comment define('QA_UPDATE_TYPE', 'Y'); // e.g. answer to comment
define('QA_UPDATE_VISIBLE', 'H'); // hidden or reshown define('QA_UPDATE_VISIBLE', 'H'); // hidden or reshown
// Character codes for types of update that only appear in the streams tables, not on the posts themselves // Character codes for types of update that only appear in the streams tables, not on the posts themselves
define('QA_UPDATE_FOLLOWS', 'F'); // if a new question was asked related to one of its answers, or for a comment that follows another define('QA_UPDATE_FOLLOWS', 'F'); // if a new question was asked related to one of its answers, or for a comment that follows another
define('QA_UPDATE_C_FOR_Q', 'U'); // if comment created was on a question of the user whose stream this appears in define('QA_UPDATE_C_FOR_Q', 'U'); // if comment created was on a question of the user whose stream this appears in
define('QA_UPDATE_C_FOR_A', 'N'); // if comment created was on an answer of the user whose stream this appears in define('QA_UPDATE_C_FOR_A', 'N'); // if comment created was on an answer of the user whose stream this appears in
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -20,185 +20,193 @@ ...@@ -20,185 +20,193 @@
More about this license: http://www.question2answer.org/license.php 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: ../'); header('Location: ../');
exit; exit;
} }
/**
* Return the maximum size of file that can be uploaded, based on database and PHP limits
*/
function qa_get_max_upload_size()
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$mindb = 16777215; // from MEDIUMBLOB column type
$minphp = trim(ini_get('upload_max_filesize'));
$minphp = convert_to_bytes(substr($minphp, -1), $minphp);
return min($mindb, $minphp);
}
/**
* Move an uploaded image or other file into blob storage. Pass the $localfilename where the file is currently stored
* (temporarily) and the $sourcefilename of the file on the user's computer (if using PHP's usual file upload
* mechanism, these are obtained from $_FILES[..]['tmp_name'] and $_FILES[..]['name'] fields respectively). To apply a
* maximum file size (in bytes) beyond the general one, use $maxfilesize, otherwise set it to null. Set $onlyimage to
* true if only image uploads (PNG, GIF, JPEG) are allowed. To apply a maximum width or height (in pixels) to uploaded
* images, set $imagemaxwidth and $imagemaxheight. The function returns an array which may contain the following elements:
*
* 'error' => a string containing an error, if one occurred
* 'format' => the format (file extension) of the blob created (all scaled images end up as 'jpeg')
* 'width' => if an image, the width in pixels of the blob created (after possible scaling)
* 'height' => if an image, the height in pixels of the blob created (after possible scaling)
* 'blobid' => the blobid that was created (if there was no error)
* 'bloburl' => the url that can be used to view/download the created blob (if there was no error)
* @param $localfilename
* @param $sourcefilename
* @param $maxfilesize
* @param bool $onlyimage
* @param $imagemaxwidth
* @param $imagemaxheight
* @return array
*/
function qa_upload_file($localfilename, $sourcefilename, $maxfilesize = null, $onlyimage = false, $imagemaxwidth = null, $imagemaxheight = null)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$result = array();
// Check per-user upload limits
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/limits.php';
switch (qa_user_permit_error(null, QA_LIMIT_UPLOADS)) {
case 'limit':
$result['error'] = qa_lang('main/upload_limit');
return $result;
case false:
qa_limits_increment(qa_get_logged_in_userid(), QA_LIMIT_UPLOADS);
break;
function qa_get_max_upload_size() default:
/* $result['error'] = qa_lang('users/no_permission');
Return the maximum size of file that can be uploaded, based on database and PHP limits return $result;
*/ }
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$mindb = 16777215; // from MEDIUMBLOB column type // Check the uploaded file is not too large
$minphp = trim(ini_get('upload_max_filesize')); $filesize = filesize($localfilename);
$minphp = convert_to_bytes(substr($minphp, -1), $minphp); if (isset($maxfilesize))
$maxfilesize = min($maxfilesize, qa_get_max_upload_size());
else
$maxfilesize = qa_get_max_upload_size();
return min($mindb, $minphp); if (($filesize <= 0) || ($filesize > $maxfilesize)) { // if file was too big for PHP, $filesize will be zero
$result['error'] = qa_lang_sub('main/max_upload_size_x', qa_format_number($maxfilesize / 1048576, 1) . 'MB');
return $result;
} }
// Find out what type of source file was uploaded and if appropriate, check it's an image and get preliminary size measure
function qa_upload_file($localfilename, $sourcefilename, $maxfilesize=null, $onlyimage=false, $imagemaxwidth=null, $imagemaxheight=null) $pathinfo = pathinfo($sourcefilename);
/* $format = strtolower(@$pathinfo['extension']);
Move an uploaded image or other file into blob storage. Pass the $localfilename where the file is currently stored $isimage = ($format == 'png') || ($format == 'gif') || ($format == 'jpeg') || ($format == 'jpg'); // allowed image extensions
(temporarily) and the $sourcefilename of the file on the user's computer (if using PHP's usual file upload
mechanism, these are obtained from $_FILES[..]['tmp_name'] and $_FILES[..]['name'] fields respectively). To apply a
maximum file size (in bytes) beyond the general one, use $maxfilesize, otherwise set it to null. Set $onlyimage to
true if only image uploads (PNG, GIF, JPEG) are allowed. To apply a maximum width or height (in pixels) to uploaded
images, set $imagemaxwidth and $imagemaxheight. The function returns an array which may contain the following elements:
'error' => a string containing an error, if one occurred
'format' => the format (file extension) of the blob created (all scaled images end up as 'jpeg')
'width' => if an image, the width in pixels of the blob created (after possible scaling)
'height' => if an image, the height in pixels of the blob created (after possible scaling)
'blobid' => the blobid that was created (if there was no error)
'bloburl' => the url that can be used to view/download the created blob (if there was no error)
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$result=array();
// Check per-user upload limits if ($isimage) {
$imagesize = @getimagesize($localfilename);
require_once QA_INCLUDE_DIR.'app/users.php'; if (is_array($imagesize)) {
require_once QA_INCLUDE_DIR.'app/limits.php'; $result['width'] = $imagesize[0];
$result['height'] = $imagesize[1];
switch (qa_user_permit_error(null, QA_LIMIT_UPLOADS)) switch ($imagesize['2']) { // reassign format based on actual content, if we can
{ case IMAGETYPE_GIF:
case 'limit': $format = 'gif';
$result['error']=qa_lang('main/upload_limit'); break;
return $result;
case false: case IMAGETYPE_JPEG:
qa_limits_increment(qa_get_logged_in_userid(), QA_LIMIT_UPLOADS); $format = 'jpeg';
break; break;
default: case IMAGETYPE_PNG:
$result['error']=qa_lang('users/no_permission'); $format = 'png';
return $result; break;
}
} }
}
// Check the uploaded file is not too large $result['format'] = $format;
$filesize=filesize($localfilename);
if (isset($maxfilesize))
$maxfilesize=min($maxfilesize, qa_get_max_upload_size());
else
$maxfilesize=qa_get_max_upload_size();
if ( ($filesize<=0) || ($filesize>$maxfilesize) ) { // if file was too big for PHP, $filesize will be zero if ($onlyimage) {
$result['error']=qa_lang_sub('main/max_upload_size_x', qa_format_number($maxfilesize/1048576, 1).'MB'); if ((!$isimage) || !is_array($imagesize)) {
$result['error'] = qa_lang_sub('main/image_not_read', 'GIF, JPG, PNG');
return $result; return $result;
} }
}
// Find out what type of source file was uploaded and if appropriate, check it's an image and get preliminary size measure // Read in the raw file contents
$pathinfo=pathinfo($sourcefilename);
$format=strtolower(@$pathinfo['extension']);
$isimage=($format=='png') || ($format=='gif') || ($format=='jpeg') || ($format=='jpg'); // allowed image extensions
if ($isimage) {
$imagesize=@getimagesize($localfilename);
if (is_array($imagesize)) {
$result['width']=$imagesize[0];
$result['height']=$imagesize[1];
switch ($imagesize['2']) { // reassign format based on actual content, if we can
case IMAGETYPE_GIF:
$format='gif';
break;
case IMAGETYPE_JPEG:
$format='jpeg';
break;
case IMAGETYPE_PNG:
$format='png';
break;
}
}
}
$result['format']=$format;
if ($onlyimage)
if ( (!$isimage) || !is_array($imagesize) ) {
$result['error']=qa_lang_sub('main/image_not_read', 'GIF, JPG, PNG');
return $result;
}
// Read in the raw file contents
$content=file_get_contents($localfilename); $content = file_get_contents($localfilename);
// If appropriate, get more accurate image size and apply constraints to it // If appropriate, get more accurate image size and apply constraints to it
require_once QA_INCLUDE_DIR.'util/image.php'; require_once QA_INCLUDE_DIR . 'util/image.php';
if ($isimage && qa_has_gd_image()) { if ($isimage && qa_has_gd_image()) {
$image=@imagecreatefromstring($content); $image = @imagecreatefromstring($content);
if (is_resource($image)) { if (is_resource($image)) {
$result['width']=$width=imagesx($image); $result['width'] = $width = imagesx($image);
$result['height']=$height=imagesy($image); $result['height'] = $height = imagesy($image);
if (isset($imagemaxwidth) || isset($imagemaxheight)) if (isset($imagemaxwidth) || isset($imagemaxheight)) {
if (qa_image_constrain( if (qa_image_constrain(
$width, $height, $width, $height,
isset($imagemaxwidth) ? $imagemaxwidth : $width, isset($imagemaxwidth) ? $imagemaxwidth : $width,
isset($imagemaxheight) ? $imagemaxheight : $height isset($imagemaxheight) ? $imagemaxheight : $height
)) { )) {
qa_gd_image_resize($image, $width, $height); qa_gd_image_resize($image, $width, $height);
if (is_resource($image)) { if (is_resource($image)) {
$content=qa_gd_image_jpeg($image); $content = qa_gd_image_jpeg($image);
$result['format']=$format='jpeg'; $result['format'] = $format = 'jpeg';
$result['width']=$width; $result['width'] = $width;
$result['height']=$height; $result['height'] = $height;
}
} }
}
if (is_resource($image)) // might have been lost
imagedestroy($image);
} }
}
// Create the blob and return if (is_resource($image)) // might have been lost
imagedestroy($image);
require_once QA_INCLUDE_DIR.'app/blobs.php'; }
}
$userid=qa_get_logged_in_userid(); // Create the blob and return
$cookieid=isset($userid) ? qa_cookie_get() : qa_cookie_get_create();
$result['blobid']=qa_create_blob($content, $format, $sourcefilename, $userid, $cookieid, qa_remote_ip_address());
if (!isset($result['blobid'])) { require_once QA_INCLUDE_DIR . 'app/blobs.php';
$result['error']=qa_lang('main/general_error');
return $result;
}
$result['bloburl']=qa_get_blob_url($result['blobid'], true); $userid = qa_get_logged_in_userid();
$cookieid = isset($userid) ? qa_cookie_get() : qa_cookie_get_create();
$result['blobid'] = qa_create_blob($content, $format, $sourcefilename, $userid, $cookieid, qa_remote_ip_address());
if (!isset($result['blobid'])) {
$result['error'] = qa_lang('main/general_error');
return $result; return $result;
} }
$result['bloburl'] = qa_get_blob_url($result['blobid'], true);
function qa_upload_file_one($maxfilesize=null, $onlyimage=false, $imagemaxwidth=null, $imagemaxheight=null) return $result;
/* }
In response to a file upload, move the first uploaded file into blob storage. Other parameters are as for qa_upload_file(...)
*/
{
$file=reset($_FILES);
return qa_upload_file($file['tmp_name'], $file['name'], $maxfilesize, $onlyimage, $imagemaxwidth, $imagemaxheight);
}
/**
* In response to a file upload, move the first uploaded file into blob storage. Other parameters are as for qa_upload_file(...)
* @param $maxfilesize
* @param bool $onlyimage
* @param $imagemaxwidth
* @param $imagemaxheight
* @return array
*/
function qa_upload_file_one($maxfilesize = null, $onlyimage = false, $imagemaxwidth = null, $imagemaxheight = null)
{
$file = reset($_FILES);
/* return qa_upload_file($file['tmp_name'], $file['name'], $maxfilesize, $onlyimage, $imagemaxwidth, $imagemaxheight);
Omit PHP closing tag to help avoid accidental output }
*/
\ No newline at end of file
...@@ -20,382 +20,426 @@ ...@@ -20,382 +20,426 @@
More about this license: http://www.question2answer.org/license.php 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: ../'); header('Location: ../');
exit; exit;
} }
@define('QA_MIN_PASSWORD_LEN', 4); @define('QA_MIN_PASSWORD_LEN', 4);
@define('QA_NEW_PASSWORD_LEN', 8); // when resetting password @define('QA_NEW_PASSWORD_LEN', 8); // when resetting password
function qa_handle_email_filter(&$handle, &$email, $olduser=null) /**
/* * Return $errors fields for any invalid aspect of user-entered $handle (username) and $email. Works by calling through
Return $errors fields for any invalid aspect of user-entered $handle (username) and $email. Works by calling through * to all filter modules and also rejects existing values in database unless they belongs to $olduser (if set).
to all filter modules and also rejects existing values in database unless they belongs to $olduser (if set). * @param $handle
*/ * @param $email
{ * @param $olduser
require_once QA_INCLUDE_DIR.'db/users.php'; * @return array
require_once QA_INCLUDE_DIR.'util/string.php'; */
function qa_handle_email_filter(&$handle, &$email, $olduser = null)
{
require_once QA_INCLUDE_DIR . 'db/users.php';
require_once QA_INCLUDE_DIR . 'util/string.php';
$errors=array(); $errors = array();
// sanitise 4-byte Unicode // sanitise 4-byte Unicode
$handle = qa_remove_utf8mb4($handle); $handle = qa_remove_utf8mb4($handle);
$filtermodules=qa_load_modules_with('filter', 'filter_handle'); $filtermodules = qa_load_modules_with('filter', 'filter_handle');
foreach ($filtermodules as $filtermodule) { foreach ($filtermodules as $filtermodule) {
$error=$filtermodule->filter_handle($handle, $olduser); $error = $filtermodule->filter_handle($handle, $olduser);
if (isset($error)) { if (isset($error)) {
$errors['handle']=$error; $errors['handle'] = $error;
break; break;
}
}
if (!isset($errors['handle'])) { // first test through filters, then check for duplicates here
$handleusers=qa_db_user_find_by_handle($handle);
if (count($handleusers) && ( (!isset($olduser['userid'])) || (array_search($olduser['userid'], $handleusers)===false) ) )
$errors['handle']=qa_lang('users/handle_exists');
} }
}
$filtermodules=qa_load_modules_with('filter', 'filter_email'); if (!isset($errors['handle'])) { // first test through filters, then check for duplicates here
$handleusers = qa_db_user_find_by_handle($handle);
if (count($handleusers) && ((!isset($olduser['userid'])) || (array_search($olduser['userid'], $handleusers) === false)))
$errors['handle'] = qa_lang('users/handle_exists');
}
$error=null; $filtermodules = qa_load_modules_with('filter', 'filter_email');
foreach ($filtermodules as $filtermodule) {
$error=$filtermodule->filter_email($email, $olduser);
if (isset($error)) {
$errors['email']=$error;
break;
}
}
if (!isset($errors['email'])) { $error = null;
$emailusers=qa_db_user_find_by_email($email); foreach ($filtermodules as $filtermodule) {
if (count($emailusers) && ( (!isset($olduser['userid'])) || (array_search($olduser['userid'], $emailusers)===false) ) ) $error = $filtermodule->filter_email($email, $olduser);
$errors['email']=qa_lang('users/email_exists'); if (isset($error)) {
$errors['email'] = $error;
break;
} }
return $errors;
} }
if (!isset($errors['email'])) {
$emailusers = qa_db_user_find_by_email($email);
if (count($emailusers) && ((!isset($olduser['userid'])) || (array_search($olduser['userid'], $emailusers) === false)))
$errors['email'] = qa_lang('users/email_exists');
}
function qa_handle_make_valid($handle) return $errors;
/* }
Make $handle valid and unique in the database - if $allowuserid is set, allow it to match that user only
*/
{
require_once QA_INCLUDE_DIR.'util/string.php';
require_once QA_INCLUDE_DIR.'db/maxima.php';
require_once QA_INCLUDE_DIR.'db/users.php';
if (!strlen($handle))
$handle=qa_lang('users/registered_user');
$handle=preg_replace('/[\\@\\+\\/]/', ' ', $handle);
for ($attempt=0; $attempt<=99; $attempt++) { /**
$suffix=$attempt ? (' '.$attempt) : ''; * Make $handle valid and unique in the database - if $allowuserid is set, allow it to match that user only
$tryhandle=qa_substr($handle, 0, QA_DB_MAX_HANDLE_LENGTH-strlen($suffix)).$suffix; * @param $handle
* @return string
*/
function qa_handle_make_valid($handle)
{
require_once QA_INCLUDE_DIR . 'util/string.php';
require_once QA_INCLUDE_DIR . 'db/maxima.php';
require_once QA_INCLUDE_DIR . 'db/users.php';
$filtermodules=qa_load_modules_with('filter', 'filter_handle'); if (!strlen($handle))
foreach ($filtermodules as $filtermodule) $handle = qa_lang('users/registered_user');
$filtermodule->filter_handle($tryhandle, null); // filter first without worrying about errors, since our goal is to get a valid one
$haderror=false; $handle = preg_replace('/[\\@\\+\\/]/', ' ', $handle);
foreach ($filtermodules as $filtermodule) { for ($attempt = 0; $attempt <= 99; $attempt++) {
$error=$filtermodule->filter_handle($tryhandle, null); // now check for errors after we've filtered $suffix = $attempt ? (' ' . $attempt) : '';
if (isset($error)) $tryhandle = qa_substr($handle, 0, QA_DB_MAX_HANDLE_LENGTH - strlen($suffix)) . $suffix;
$haderror=true;
}
if (!$haderror) { $filtermodules = qa_load_modules_with('filter', 'filter_handle');
$handleusers=qa_db_user_find_by_handle($tryhandle); foreach ($filtermodules as $filtermodule) {
if (!count($handleusers)) // filter first without worrying about errors, since our goal is to get a valid one
return $tryhandle; $filtermodule->filter_handle($tryhandle, null);
}
} }
qa_fatal_error('Could not create a valid and unique handle from: '.$handle); $haderror = false;
}
function qa_password_validate($password, $olduser=null)
/*
Return an array with a single element (key 'password') if user-entered $password is valid, otherwise an empty array.
Works by calling through to all filter modules.
*/
{
$error=null;
$filtermodules=qa_load_modules_with('filter', 'validate_password');
foreach ($filtermodules as $filtermodule) { foreach ($filtermodules as $filtermodule) {
$error=$filtermodule->validate_password($password, $olduser); $error = $filtermodule->filter_handle($tryhandle, null); // now check for errors after we've filtered
if (isset($error)) if (isset($error))
break; $haderror = true;
} }
if (!isset($error)) { if (!$haderror) {
$minpasslen=max(QA_MIN_PASSWORD_LEN, 1); $handleusers = qa_db_user_find_by_handle($tryhandle);
if (qa_strlen($password)<$minpasslen) if (!count($handleusers))
$error=qa_lang_sub('users/password_min', $minpasslen); return $tryhandle;
} }
}
qa_fatal_error('Could not create a valid and unique handle from: ' . $handle);
}
/**
* Return an array with a single element (key 'password') if user-entered $password is valid, otherwise an empty array.
* Works by calling through to all filter modules.
* @param $password
* @param $olduser
* @return array
*/
function qa_password_validate($password, $olduser = null)
{
$error = null;
$filtermodules = qa_load_modules_with('filter', 'validate_password');
foreach ($filtermodules as $filtermodule) {
$error = $filtermodule->validate_password($password, $olduser);
if (isset($error)) if (isset($error))
return array('password' => $error); break;
}
return array(); if (!isset($error)) {
$minpasslen = max(QA_MIN_PASSWORD_LEN, 1);
if (qa_strlen($password) < $minpasslen)
$error = qa_lang_sub('users/password_min', $minpasslen);
} }
if (isset($error))
return array('password' => $error);
function qa_create_new_user($email, $password, $handle, $level=QA_USER_LEVEL_BASIC, $confirmed=false) return array();
/* }
Create a new user (application level) with $email, $password, $handle and $level.
Set $confirmed to true if the email address has been confirmed elsewhere.
Handles user points, notification and optional email confirmation.
*/
{
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/points.php';
require_once QA_INCLUDE_DIR.'app/options.php';
require_once QA_INCLUDE_DIR.'app/emails.php';
require_once QA_INCLUDE_DIR.'app/cookies.php';
$userid=qa_db_user_create($email, $password, $handle, $level, qa_remote_ip_address()); /**
qa_db_points_update_ifuser($userid, null); * Create a new user (application level) with $email, $password, $handle and $level.
qa_db_uapprovecount_update(); * Set $confirmed to true if the email address has been confirmed elsewhere.
* Handles user points, notification and optional email confirmation.
* @param $email
* @param $password
* @param $handle
* @param int $level
* @param bool $confirmed
* @return mixed
*/
function qa_create_new_user($email, $password, $handle, $level = QA_USER_LEVEL_BASIC, $confirmed = false)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if ($confirmed) require_once QA_INCLUDE_DIR . 'db/users.php';
qa_db_user_set_flag($userid, QA_USER_FLAGS_EMAIL_CONFIRMED, true); require_once QA_INCLUDE_DIR . 'db/points.php';
require_once QA_INCLUDE_DIR . 'app/options.php';
require_once QA_INCLUDE_DIR . 'app/emails.php';
require_once QA_INCLUDE_DIR . 'app/cookies.php';
if (qa_opt('show_notice_welcome')) $userid = qa_db_user_create($email, $password, $handle, $level, qa_remote_ip_address());
qa_db_user_set_flag($userid, QA_USER_FLAGS_WELCOME_NOTICE, true); qa_db_points_update_ifuser($userid, null);
qa_db_uapprovecount_update();
$custom=qa_opt('show_custom_welcome') ? trim(qa_opt('custom_welcome')) : ''; if ($confirmed)
qa_db_user_set_flag($userid, QA_USER_FLAGS_EMAIL_CONFIRMED, true);
if (qa_opt('confirm_user_emails') && ($level<QA_USER_LEVEL_EXPERT) && !$confirmed) { if (qa_opt('show_notice_welcome'))
$confirm=strtr(qa_lang('emails/welcome_confirm'), array( qa_db_user_set_flag($userid, QA_USER_FLAGS_WELCOME_NOTICE, true);
'^url' => qa_get_new_confirm_url($userid, $handle)
));
if (qa_opt('confirm_user_required')) $custom = qa_opt('show_custom_welcome') ? trim(qa_opt('custom_welcome')) : '';
qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_CONFIRM, true);
} else if (qa_opt('confirm_user_emails') && $level < QA_USER_LEVEL_EXPERT && !$confirmed) {
$confirm=''; $confirm = strtr(qa_lang('emails/welcome_confirm'), array(
'^url' => qa_get_new_confirm_url($userid, $handle),
));
if (qa_opt('moderate_users') && qa_opt('approve_user_required') && ($level<QA_USER_LEVEL_EXPERT)) if (qa_opt('confirm_user_required'))
qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_APPROVE, true); qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_CONFIRM, true);
qa_send_notification($userid, $email, $handle, qa_lang('emails/welcome_subject'), qa_lang('emails/welcome_body'), array( } else
'^password' => isset($password) ? qa_lang('main/hidden') : qa_lang('users/password_to_set'), // v 1.6.3: no longer email out passwords $confirm = '';
'^url' => qa_opt('site_url'),
'^custom' => strlen($custom) ? ($custom."\n\n") : '',
'^confirm' => $confirm,
));
qa_report_event('u_register', $userid, $handle, qa_cookie_get(), array( if (qa_opt('moderate_users') && qa_opt('approve_user_required') && $level < QA_USER_LEVEL_EXPERT)
'email' => $email, qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_APPROVE, true);
'level' => $level,
));
return $userid; qa_send_notification($userid, $email, $handle, qa_lang('emails/welcome_subject'), qa_lang('emails/welcome_body'), array(
} '^password' => isset($password) ? qa_lang('main/hidden') : qa_lang('users/password_to_set'), // v 1.6.3: no longer email out passwords
'^url' => qa_opt('site_url'),
'^custom' => strlen($custom) ? ($custom . "\n\n") : '',
'^confirm' => $confirm,
));
qa_report_event('u_register', $userid, $handle, qa_cookie_get(), array(
'email' => $email,
'level' => $level,
));
function qa_delete_user($userid) return $userid;
/* }
Delete $userid and all their votes and flags. Their posts will become anonymous.
Handles recalculations of votes and flags for posts this user has affected.
*/ /**
{ * Delete $userid and all their votes and flags. Their posts will become anonymous.
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } * Handles recalculations of votes and flags for posts this user has affected.
* @param $userid
* @return mixed
*/
function qa_delete_user($userid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/votes.php'; require_once QA_INCLUDE_DIR . 'db/votes.php';
require_once QA_INCLUDE_DIR.'db/users.php'; require_once QA_INCLUDE_DIR . 'db/users.php';
require_once QA_INCLUDE_DIR.'db/post-update.php'; require_once QA_INCLUDE_DIR . 'db/post-update.php';
require_once QA_INCLUDE_DIR.'db/points.php'; require_once QA_INCLUDE_DIR . 'db/points.php';
$postids=qa_db_uservoteflag_user_get($userid); // posts this user has flagged or voted on, whose counts need updating $postids = qa_db_uservoteflag_user_get($userid); // posts this user has flagged or voted on, whose counts need updating
qa_db_user_delete($userid); qa_db_user_delete($userid);
qa_db_uapprovecount_update(); qa_db_uapprovecount_update();
qa_db_userpointscount_update(); qa_db_userpointscount_update();
foreach ($postids as $postid) { // hoping there aren't many of these - saves a lot of new SQL code... foreach ($postids as $postid) { // hoping there aren't many of these - saves a lot of new SQL code...
qa_db_post_recount_votes($postid); qa_db_post_recount_votes($postid);
qa_db_post_recount_flags($postid); qa_db_post_recount_flags($postid);
} }
$postuserids=qa_db_posts_get_userids($postids); $postuserids = qa_db_posts_get_userids($postids);
foreach ($postuserids as $postuserid) foreach ($postuserids as $postuserid) {
qa_db_points_update_ifuser($postuserid, array('avoteds','qvoteds', 'upvoteds', 'downvoteds')); qa_db_points_update_ifuser($postuserid, array('avoteds', 'qvoteds', 'upvoteds', 'downvoteds'));
} }
}
function qa_send_new_confirm($userid) /**
/* * Set a new email confirmation code for the user and send it out
Set a new email confirmation code for the user and send it out * @param $userid
*/ * @return mixed
{ */
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } function qa_send_new_confirm($userid)
{
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';
require_once QA_INCLUDE_DIR.'db/selects.php'; require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR.'app/emails.php'; require_once QA_INCLUDE_DIR . 'app/emails.php';
$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));
$emailcode = qa_db_user_rand_emailcode(); $emailcode = qa_db_user_rand_emailcode();
if (!qa_send_notification($userid, $userinfo['email'], $userinfo['handle'], qa_lang('emails/confirm_subject'), qa_lang('emails/confirm_body'), array( if (!qa_send_notification($userid, $userinfo['email'], $userinfo['handle'], qa_lang('emails/confirm_subject'), qa_lang('emails/confirm_body'), array(
'^url' => qa_get_new_confirm_url($userid, $userinfo['handle'], $emailcode), '^url' => qa_get_new_confirm_url($userid, $userinfo['handle'], $emailcode),
'^code' => $emailcode, '^code' => $emailcode,
))) ))) {
qa_fatal_error('Could not send email confirmation'); qa_fatal_error('Could not send email confirmation');
} }
}
function qa_get_new_confirm_url($userid, $handle, $emailcode = null) /**
/* * Set a new email confirmation code for the user and return the corresponding link. If the email code is also sent then that value
Set a new email confirmation code for the user and return the corresponding link. If the email code is also sent then that value * is used. Otherwise, a new email code is generated
is used. Otherwise, a new email code is generated * @param $userid
*/ * @param $handle
{ * @param $emailcode
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } * @return mixed|string
*/
require_once QA_INCLUDE_DIR.'db/users.php'; function qa_get_new_confirm_url($userid, $handle, $emailcode = null)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if (!isset($emailcode)) { require_once QA_INCLUDE_DIR . 'db/users.php';
$emailcode = qa_db_user_rand_emailcode();
}
qa_db_user_set($userid, 'emailcode', $emailcode);
return qa_path_absolute('confirm', array('c' => $emailcode, 'u' => $handle)); if (!isset($emailcode)) {
$emailcode = qa_db_user_rand_emailcode();
} }
qa_db_user_set($userid, 'emailcode', $emailcode);
return qa_path_absolute('confirm', array('c' => $emailcode, 'u' => $handle));
}
function qa_complete_confirm($userid, $email, $handle)
/*
Complete the email confirmation process for the user
*/
{
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.'app/cookies.php'; * Complete the email confirmation process for the user
* @param $userid
* @param $email
* @param $handle
* @return mixed
*/
function qa_complete_confirm($userid, $email, $handle)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
qa_db_user_set_flag($userid, QA_USER_FLAGS_EMAIL_CONFIRMED, true); require_once QA_INCLUDE_DIR . 'db/users.php';
qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_CONFIRM, false); require_once QA_INCLUDE_DIR . 'app/cookies.php';
qa_db_user_set($userid, 'emailcode', ''); // to prevent re-use of the code
qa_report_event('u_confirmed', $userid, $handle, qa_cookie_get(), array( qa_db_user_set_flag($userid, QA_USER_FLAGS_EMAIL_CONFIRMED, true);
'email' => $email, qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_CONFIRM, false);
)); qa_db_user_set($userid, 'emailcode', ''); // to prevent re-use of the code
}
qa_report_event('u_confirmed', $userid, $handle, qa_cookie_get(), array(
'email' => $email,
));
}
function qa_set_user_level($userid, $handle, $level, $oldlevel)
/*
Set the user level of user $userid with $handle to $level (one of the QA_USER_LEVEL_* constraints in qa-app-users.php)
Pass the previous user level in $oldlevel. Reports the appropriate event, assumes change performed by the logged in user.
*/
{
require_once QA_INCLUDE_DIR.'db/users.php';
qa_db_user_set($userid, 'level', $level); /**
qa_db_uapprovecount_update(); * Set the user level of user $userid with $handle to $level (one of the QA_USER_LEVEL_* constraints in qa-app-users.php)
* Pass the previous user level in $oldlevel. Reports the appropriate event, assumes change performed by the logged in user.
* @param $userid
* @param $handle
* @param $level
* @param $oldlevel
*/
function qa_set_user_level($userid, $handle, $level, $oldlevel)
{
require_once QA_INCLUDE_DIR . 'db/users.php';
if ($level>=QA_USER_LEVEL_APPROVED) qa_db_user_set($userid, 'level', $level);
qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_APPROVE, false); qa_db_uapprovecount_update();
qa_report_event('u_level', qa_get_logged_in_userid(), qa_get_logged_in_handle(), qa_cookie_get(), array( if ($level >= QA_USER_LEVEL_APPROVED)
'userid' => $userid, qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_APPROVE, false);
'handle' => $handle,
'level' => $level,
'oldlevel' => $oldlevel,
));
}
qa_report_event('u_level', qa_get_logged_in_userid(), qa_get_logged_in_handle(), qa_cookie_get(), array(
'userid' => $userid,
'handle' => $handle,
'level' => $level,
'oldlevel' => $oldlevel,
));
}
function qa_set_user_blocked($userid, $handle, $blocked)
/*
Set the status of user $userid with $handle to blocked if $blocked is true, otherwise to unblocked. Reports the appropriate
event, assumes change performed by the logged in user.
*/
{
require_once QA_INCLUDE_DIR.'db/users.php';
qa_db_user_set_flag($userid, QA_USER_FLAGS_USER_BLOCKED, $blocked); /**
qa_db_uapprovecount_update(); * Set the status of user $userid with $handle to blocked if $blocked is true, otherwise to unblocked. Reports the appropriate
* event, assumes change performed by the logged in user.
* @param $userid
* @param $handle
* @param $blocked
*/
function qa_set_user_blocked($userid, $handle, $blocked)
{
require_once QA_INCLUDE_DIR . 'db/users.php';
qa_report_event($blocked ? 'u_block' : 'u_unblock', qa_get_logged_in_userid(), qa_get_logged_in_handle(), qa_cookie_get(), array( qa_db_user_set_flag($userid, QA_USER_FLAGS_USER_BLOCKED, $blocked);
'userid' => $userid, qa_db_uapprovecount_update();
'handle' => $handle,
));
}
qa_report_event($blocked ? 'u_block' : 'u_unblock', qa_get_logged_in_userid(), qa_get_logged_in_handle(), qa_cookie_get(), array(
'userid' => $userid,
'handle' => $handle,
));
}
function qa_start_reset_user($userid)
/*
Start the 'I forgot my password' process for $userid, sending reset code
*/
{
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.'app/options.php'; * Start the 'I forgot my password' process for $userid, sending reset code
require_once QA_INCLUDE_DIR.'app/emails.php'; * @param $userid
require_once QA_INCLUDE_DIR.'db/selects.php'; * @return mixed
*/
function qa_start_reset_user($userid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
qa_db_user_set($userid, 'emailcode', qa_db_user_rand_emailcode()); require_once QA_INCLUDE_DIR . 'db/users.php';
require_once QA_INCLUDE_DIR . 'app/options.php';
require_once QA_INCLUDE_DIR . 'app/emails.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
$userinfo=qa_db_select_with_pending(qa_db_user_account_selectspec($userid, true)); qa_db_user_set($userid, 'emailcode', qa_db_user_rand_emailcode());
if (!qa_send_notification($userid, $userinfo['email'], $userinfo['handle'], qa_lang('emails/reset_subject'), qa_lang('emails/reset_body'), array( $userinfo = qa_db_select_with_pending(qa_db_user_account_selectspec($userid, true));
'^code' => $userinfo['emailcode'],
'^url' => qa_path_absolute('reset', array('c' => $userinfo['emailcode'], 'e' => $userinfo['email'])), if (!qa_send_notification($userid, $userinfo['email'], $userinfo['handle'], qa_lang('emails/reset_subject'), qa_lang('emails/reset_body'), array(
))) '^code' => $userinfo['emailcode'],
qa_fatal_error('Could not send reset password email'); '^url' => qa_path_absolute('reset', array('c' => $userinfo['emailcode'], 'e' => $userinfo['email'])),
))) {
qa_fatal_error('Could not send reset password email');
} }
}
/** /**
* Successfully finish the 'I forgot my password' process for $userid, sending new password * Successfully finish the 'I forgot my password' process for $userid, sending new password
* *
* @deprecated This function has been replaced by qa_finish_reset_user since Q2A 1.8 * @deprecated This function has been replaced by qa_finish_reset_user since Q2A 1.8
* @param $userid
* @return mixed
*/ */
function qa_complete_reset_user($userid) function qa_complete_reset_user($userid)
{ {
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'util/string.php'; require_once QA_INCLUDE_DIR . 'util/string.php';
require_once QA_INCLUDE_DIR.'app/options.php'; require_once QA_INCLUDE_DIR . 'app/options.php';
require_once QA_INCLUDE_DIR.'app/emails.php'; require_once QA_INCLUDE_DIR . 'app/emails.php';
require_once QA_INCLUDE_DIR.'app/cookies.php'; require_once QA_INCLUDE_DIR . 'app/cookies.php';
require_once QA_INCLUDE_DIR.'db/selects.php'; require_once QA_INCLUDE_DIR . 'db/selects.php';
$password=qa_random_alphanum(max(QA_MIN_PASSWORD_LEN, QA_NEW_PASSWORD_LEN)); $password = qa_random_alphanum(max(QA_MIN_PASSWORD_LEN, QA_NEW_PASSWORD_LEN));
$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));
if (!qa_send_notification($userid, $userinfo['email'], $userinfo['handle'], qa_lang('emails/new_password_subject'), qa_lang('emails/new_password_body'), array( if (!qa_send_notification($userid, $userinfo['email'], $userinfo['handle'], qa_lang('emails/new_password_subject'), qa_lang('emails/new_password_body'), array(
'^password' => $password, '^password' => $password,
'^url' => qa_opt('site_url'), '^url' => qa_opt('site_url'),
))) ))) {
qa_fatal_error('Could not send new password - password not reset'); qa_fatal_error('Could not send new password - password not reset');
}
qa_db_user_set_password($userid, $password); // do this last, to be safe qa_db_user_set_password($userid, $password); // do this last, to be safe
qa_db_user_set($userid, 'emailcode', ''); // so can't be reused qa_db_user_set($userid, 'emailcode', ''); // so can't be reused
qa_report_event('u_reset', $userid, $userinfo['handle'], qa_cookie_get(), array( qa_report_event('u_reset', $userid, $userinfo['handle'], qa_cookie_get(), array(
'email' => $userinfo['email'], 'email' => $userinfo['email'],
)); ));
} }
/** /**
...@@ -404,83 +448,82 @@ ...@@ -404,83 +448,82 @@
* @param string $newPassword The new password for the user * @param string $newPassword The new password for the user
* @return void * @return void
*/ */
function qa_finish_reset_user($userId, $newPassword) function qa_finish_reset_user($userId, $newPassword)
{ {
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
// For qa_db_user_set_password(), qa_db_user_set() // For qa_db_user_set_password(), qa_db_user_set()
require_once QA_INCLUDE_DIR . 'db/users.php'; require_once QA_INCLUDE_DIR . 'db/users.php';
// For qa_set_logged_in_user() // For qa_set_logged_in_user()
require_once QA_INCLUDE_DIR . 'app/options.php'; require_once QA_INCLUDE_DIR . 'app/options.php';
// For qa_cookie_get() // For qa_cookie_get()
require_once QA_INCLUDE_DIR . 'app/cookies.php'; require_once QA_INCLUDE_DIR . 'app/cookies.php';
// For qa_db_select_with_pending(), qa_db_user_account_selectspec() // For qa_db_select_with_pending(), qa_db_user_account_selectspec()
require_once QA_INCLUDE_DIR . 'db/selects.php'; require_once QA_INCLUDE_DIR . 'db/selects.php';
// For qa_set_logged_in_user() // For qa_set_logged_in_user()
require_once QA_INCLUDE_DIR . 'app/users.php'; require_once QA_INCLUDE_DIR . 'app/users.php';
qa_db_user_set_password($userId, $newPassword); qa_db_user_set_password($userId, $newPassword);
qa_db_user_set($userId, 'emailcode', ''); // to prevent re-use of the code qa_db_user_set($userId, 'emailcode', ''); // to prevent re-use of the code
$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));
qa_set_logged_in_user($userId, $userInfo['handle'], false, $userInfo['sessionsource']); // reinstate this specific session qa_set_logged_in_user($userId, $userInfo['handle'], false, $userInfo['sessionsource']); // reinstate this specific session
qa_report_event('u_reset', $userId, $userInfo['handle'], qa_cookie_get(), array( qa_report_event('u_reset', $userId, $userInfo['handle'], qa_cookie_get(), array(
'email' => $userInfo['email'], 'email' => $userInfo['email'],
)); ));
} }
function qa_logged_in_user_flush() /**
/* * Flush any information about the currently logged in user, so it is retrieved from database again
Flush any information about the currently logged in user, so it is retrieved from database again */
*/ function qa_logged_in_user_flush()
{ {
global $qa_cached_logged_in_user; global $qa_cached_logged_in_user;
$qa_cached_logged_in_user=null; $qa_cached_logged_in_user = null;
} }
function qa_set_user_avatar($userid, $imagedata, $oldblobid=null) /**
/* * Set the avatar of $userid to the image in $imagedata, and remove $oldblobid from the database if not null
Set the avatar of $userid to the image in $imagedata, and remove $oldblobid from the database if not null * @param $userid
*/ * @param $imagedata
{ * @param $oldblobid
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } * @return bool
*/
function qa_set_user_avatar($userid, $imagedata, $oldblobid = null)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'util/image.php'; require_once QA_INCLUDE_DIR . 'util/image.php';
$imagedata=qa_image_constrain_data($imagedata, $width, $height, qa_opt('avatar_store_size')); $imagedata = qa_image_constrain_data($imagedata, $width, $height, qa_opt('avatar_store_size'));
if (isset($imagedata)) { if (isset($imagedata)) {
require_once QA_INCLUDE_DIR.'app/blobs.php'; require_once QA_INCLUDE_DIR . 'app/blobs.php';
$newblobid=qa_create_blob($imagedata, 'jpeg', null, $userid, null, qa_remote_ip_address()); $newblobid = qa_create_blob($imagedata, 'jpeg', null, $userid, null, qa_remote_ip_address());
if (isset($newblobid)) { if (isset($newblobid)) {
qa_db_user_set($userid, 'avatarblobid', $newblobid); qa_db_user_set($userid, 'avatarblobid', $newblobid);
qa_db_user_set($userid, 'avatarwidth', $width); qa_db_user_set($userid, 'avatarwidth', $width);
qa_db_user_set($userid, 'avatarheight', $height); qa_db_user_set($userid, 'avatarheight', $height);
qa_db_user_set_flag($userid, QA_USER_FLAGS_SHOW_AVATAR, true); qa_db_user_set_flag($userid, QA_USER_FLAGS_SHOW_AVATAR, true);
qa_db_user_set_flag($userid, QA_USER_FLAGS_SHOW_GRAVATAR, false); qa_db_user_set_flag($userid, QA_USER_FLAGS_SHOW_GRAVATAR, false);
if (isset($oldblobid)) if (isset($oldblobid))
qa_delete_blob($oldblobid); qa_delete_blob($oldblobid);
return true; return true;
}
} }
return false;
} }
return false;
/* }
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -20,289 +20,315 @@ ...@@ -20,289 +20,315 @@
More about this license: http://www.question2answer.org/license.php 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: ../'); header('Location: ../');
exit; exit;
} }
function qa_vote_error_html($post, $vote, $userid, $topage) /**
/* * Check if $userid can vote on $post, on the page $topage.
Check if $userid can vote on $post, on the page $topage. * Return an HTML error to display if there was a problem, or false if it's OK.
Return an HTML error to display if there was a problem, or false if it's OK. * @param $post
*/ * @param $vote
{ * @param $userid
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } * @param $topage
* @return bool|mixed|string
// The 'login', 'confirm', 'limit', 'userblock' and 'ipblock' permission errors are reported to the user here. */
// Others ('approve', 'level') prevent the buttons being clickable in the first place, in qa_get_vote_view(...) function qa_vote_error_html($post, $vote, $userid, $topage)
{
require_once QA_INCLUDE_DIR.'app/users.php'; if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'app/limits.php';
// The 'login', 'confirm', 'limit', 'userblock' and 'ipblock' permission errors are reported to the user here.
if ( // Others ('approve', 'level') prevent the buttons being clickable in the first place, in qa_get_vote_view(...)
is_array($post) &&
( ($post['basetype']=='Q') || ($post['basetype']=='A') ) && require_once QA_INCLUDE_DIR . 'app/users.php';
qa_opt(($post['basetype']=='Q') ? 'voting_on_qs' : 'voting_on_as') && require_once QA_INCLUDE_DIR . 'app/limits.php';
( (!isset($post['userid'])) || (!isset($userid)) || ($post['userid']!=$userid) )
) { if (
$permiterror=qa_user_post_permit_error(($post['basetype']=='Q') ? 'permit_vote_q' : 'permit_vote_a', $post, QA_LIMIT_VOTES); is_array($post) &&
($post['basetype'] == 'Q' || $post['basetype'] == 'A') &&
$errordownonly=(!$permiterror) && ($vote<0); qa_opt(($post['basetype'] == 'Q') ? 'voting_on_qs' : 'voting_on_as') &&
if ($errordownonly) (!isset($post['userid']) || !isset($userid) || $post['userid'] != $userid)
$permiterror=qa_user_post_permit_error('permit_vote_down', $post); ) {
$permiterror = qa_user_post_permit_error(($post['basetype'] == 'Q') ? 'permit_vote_q' : 'permit_vote_a', $post, QA_LIMIT_VOTES);
switch ($permiterror) {
case 'login': $errordownonly = !$permiterror && $vote < 0;
return qa_insert_login_links(qa_lang_html('main/vote_must_login'), $topage); if ($errordownonly)
break; $permiterror = qa_user_post_permit_error('permit_vote_down', $post);
case 'confirm': switch ($permiterror) {
return qa_insert_login_links(qa_lang_html($errordownonly ? 'main/vote_down_must_confirm' : 'main/vote_must_confirm'), $topage); case 'login':
break; return qa_insert_login_links(qa_lang_html('main/vote_must_login'), $topage);
case 'limit':
return qa_lang_html('main/vote_limit');
break;
default:
return qa_lang_html('users/no_permission');
break;
case false:
return false;
}
} else
return qa_lang_html('main/vote_not_allowed'); // voting option should not have been presented (but could happen due to options change)
}
function qa_vote_set($post, $userid, $handle, $cookieid, $vote)
/*
Actually set (application level) the $vote (-1/0/1) by $userid (with $handle and $cookieid) on $postid.
Handles user points, recounting and event reports as appropriate.
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/points.php';
require_once QA_INCLUDE_DIR.'db/hotness.php';
require_once QA_INCLUDE_DIR.'db/votes.php';
require_once QA_INCLUDE_DIR.'db/post-create.php';
require_once QA_INCLUDE_DIR.'app/limits.php';
$vote=(int)min(1, max(-1, $vote));
$oldvote=(int)qa_db_uservote_get($post['postid'], $userid);
qa_db_uservote_set($post['postid'], $userid, $vote);
qa_db_post_recount_votes($post['postid']);
$postisanswer=($post['basetype']=='A');
if ($postisanswer) {
qa_db_post_acount_update($post['parentid']);
qa_db_unupaqcount_update();
}
$columns=array();
if ( ($vote>0) || ($oldvote>0) )
$columns[]=$postisanswer ? 'aupvotes' : 'qupvotes';
if ( ($vote<0) || ($oldvote<0) )
$columns[]=$postisanswer ? 'adownvotes' : 'qdownvotes';
qa_db_points_update_ifuser($userid, $columns);
qa_db_points_update_ifuser($post['userid'], array($postisanswer ? 'avoteds' : 'qvoteds', 'upvoteds', 'downvoteds'));
if ($post['basetype']=='Q')
qa_db_hotness_update($post['postid']);
if ($vote<0)
$event=$postisanswer ? 'a_vote_down' : 'q_vote_down';
elseif ($vote>0)
$event=$postisanswer ? 'a_vote_up' : 'q_vote_up';
else
$event=$postisanswer ? 'a_vote_nil' : 'q_vote_nil';
qa_report_event($event, $userid, $handle, $cookieid, array(
'postid' => $post['postid'],
'userid' => $post['userid'],
'vote' => $vote,
'oldvote' => $oldvote,
));
}
function qa_flag_error_html($post, $userid, $topage)
/*
Check if $userid can flag $post, on the page $topage.
Return an HTML error to display if there was a problem, or false if it's OK.
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
// The 'login', 'confirm', 'limit', 'userblock' and 'ipblock' permission errors are reported to the user here.
// Others ('approve', 'level') prevent the flag button being shown, in qa_page_q_post_rules(...)
require_once QA_INCLUDE_DIR.'db/selects.php';
require_once QA_INCLUDE_DIR.'app/options.php';
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR.'app/limits.php';
if (
is_array($post) &&
qa_opt('flagging_of_posts') &&
( (!isset($post['userid'])) || (!isset($userid)) || ($post['userid']!=$userid) )
) {
switch (qa_user_post_permit_error('permit_flag', $post, QA_LIMIT_FLAGS)) {
case 'login':
return qa_insert_login_links(qa_lang_html('question/flag_must_login'), $topage);
break;
case 'confirm':
return qa_insert_login_links(qa_lang_html('question/flag_must_confirm'), $topage);
break;
case 'limit':
return qa_lang_html('question/flag_limit');
break;
default:
return qa_lang_html('users/no_permission');
break;
case false:
return false;
}
} else
return qa_lang_html('question/flag_not_allowed'); // flagging option should not have been presented
}
function qa_flag_set_tohide($oldpost, $userid, $handle, $cookieid, $question)
/*
Set (application level) a flag by $userid (with $handle and $cookieid) on $oldpost which belongs to $question.
Handles recounting, admin notifications and event reports as appropriate.
Returns true if the post should now be hidden because it has accumulated enough flags.
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/votes.php';
require_once QA_INCLUDE_DIR.'app/limits.php';
require_once QA_INCLUDE_DIR.'db/post-update.php';
qa_db_userflag_set($oldpost['postid'], $userid, true);
qa_db_post_recount_flags($oldpost['postid']);
qa_db_flaggedcount_update();
switch ($oldpost['basetype']) {
case 'Q':
$event='q_flag';
break; break;
case 'A': case 'confirm':
$event='a_flag'; return qa_insert_login_links(qa_lang_html($errordownonly ? 'main/vote_down_must_confirm' : 'main/vote_must_confirm'), $topage);
break; break;
case 'C': case 'limit':
$event='c_flag'; return qa_lang_html('main/vote_limit');
break; break;
}
$post=qa_db_select_with_pending(qa_db_full_post_selectspec(null, $oldpost['postid']));
qa_report_event($event, $userid, $handle, $cookieid, array(
'postid' => $oldpost['postid'],
'oldpost' => $oldpost,
'flagcount' => $post['flagcount'],
'questionid' => $question['postid'],
'question' => $question,
));
return ($post['flagcount']>=qa_opt('flagging_hide_after')) && !$post['hidden'];
}
function qa_flag_clear($oldpost, $userid, $handle, $cookieid)
/*
Clear (application level) a flag on $oldpost by $userid (with $handle and $cookieid).
Handles recounting and event reports as appropriate.
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/votes.php';
require_once QA_INCLUDE_DIR.'app/limits.php';
require_once QA_INCLUDE_DIR.'db/post-update.php';
qa_db_userflag_set($oldpost['postid'], $userid, false); default:
qa_db_post_recount_flags($oldpost['postid']); return qa_lang_html('users/no_permission');
qa_db_flaggedcount_update();
switch ($oldpost['basetype']) {
case 'Q':
$event='q_unflag';
break;
case 'A':
$event='a_unflag';
break; break;
case 'C': case false:
$event='c_unflag'; return false;
break;
} }
qa_report_event($event, $userid, $handle, $cookieid, array( } else
'postid' => $oldpost['postid'], return qa_lang_html('main/vote_not_allowed'); // voting option should not have been presented (but could happen due to options change)
'oldpost' => $oldpost, }
));
/**
* Actually set (application level) the $vote (-1/0/1) by $userid (with $handle and $cookieid) on $postid.
* Handles user points, recounting and event reports as appropriate.
* @param $post
* @param $userid
* @param $handle
* @param $cookieid
* @param $vote
* @return mixed
*/
function qa_vote_set($post, $userid, $handle, $cookieid, $vote)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR . 'db/points.php';
require_once QA_INCLUDE_DIR . 'db/hotness.php';
require_once QA_INCLUDE_DIR . 'db/votes.php';
require_once QA_INCLUDE_DIR . 'db/post-create.php';
require_once QA_INCLUDE_DIR . 'app/limits.php';
$vote = (int)min(1, max(-1, $vote));
$oldvote = (int)qa_db_uservote_get($post['postid'], $userid);
qa_db_uservote_set($post['postid'], $userid, $vote);
qa_db_post_recount_votes($post['postid']);
$postisanswer = ($post['basetype'] == 'A');
if ($postisanswer) {
qa_db_post_acount_update($post['parentid']);
qa_db_unupaqcount_update();
} }
$columns = array();
if ($vote > 0 || $oldvote > 0)
$columns[] = $postisanswer ? 'aupvotes' : 'qupvotes';
if ($vote < 0 || $oldvote < 0)
$columns[] = $postisanswer ? 'adownvotes' : 'qdownvotes';
qa_db_points_update_ifuser($userid, $columns);
qa_db_points_update_ifuser($post['userid'], array($postisanswer ? 'avoteds' : 'qvoteds', 'upvoteds', 'downvoteds'));
if ($post['basetype'] == 'Q')
qa_db_hotness_update($post['postid']);
if ($vote < 0)
$event = $postisanswer ? 'a_vote_down' : 'q_vote_down';
elseif ($vote > 0)
$event = $postisanswer ? 'a_vote_up' : 'q_vote_up';
else
$event = $postisanswer ? 'a_vote_nil' : 'q_vote_nil';
qa_report_event($event, $userid, $handle, $cookieid, array(
'postid' => $post['postid'],
'userid' => $post['userid'],
'vote' => $vote,
'oldvote' => $oldvote,
));
}
/**
* Check if $userid can flag $post, on the page $topage.
* Return an HTML error to display if there was a problem, or false if it's OK.
* @param $post
* @param $userid
* @param $topage
* @return bool|mixed|string
*/
function qa_flag_error_html($post, $userid, $topage)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
// The 'login', 'confirm', 'limit', 'userblock' and 'ipblock' permission errors are reported to the user here.
// Others ('approve', 'level') prevent the flag button being shown, in qa_page_q_post_rules(...)
require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR . 'app/options.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/limits.php';
if (
is_array($post) &&
qa_opt('flagging_of_posts') &&
(!isset($post['userid']) || !isset($userid) || $post['userid'] != $userid)
) {
switch (qa_user_post_permit_error('permit_flag', $post, QA_LIMIT_FLAGS)) {
case 'login':
return qa_insert_login_links(qa_lang_html('question/flag_must_login'), $topage);
break;
function qa_flags_clear_all($oldpost, $userid, $handle, $cookieid) case 'confirm':
/* return qa_insert_login_links(qa_lang_html('question/flag_must_confirm'), $topage);
Clear (application level) all flags on $oldpost by $userid (with $handle and $cookieid).
Handles recounting and event reports as appropriate.
*/
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/votes.php';
require_once QA_INCLUDE_DIR.'app/limits.php';
require_once QA_INCLUDE_DIR.'db/post-update.php';
qa_db_userflags_clear_all($oldpost['postid']);
qa_db_post_recount_flags($oldpost['postid']);
qa_db_flaggedcount_update();
switch ($oldpost['basetype']) {
case 'Q':
$event='q_clearflags';
break; break;
case 'A': case 'limit':
$event='a_clearflags'; return qa_lang_html('question/flag_limit');
break; break;
case 'C': default:
$event='c_clearflags'; return qa_lang_html('users/no_permission');
break; break;
case false:
return false;
} }
qa_report_event($event, $userid, $handle, $cookieid, array( } else
'postid' => $oldpost['postid'], return qa_lang_html('question/flag_not_allowed'); // flagging option should not have been presented
'oldpost' => $oldpost, }
));
/**
* Set (application level) a flag by $userid (with $handle and $cookieid) on $oldpost which belongs to $question.
* Handles recounting, admin notifications and event reports as appropriate.
* Returns true if the post should now be hidden because it has accumulated enough flags.
* @param $oldpost
* @param $userid
* @param $handle
* @param $cookieid
* @param $question
* @return bool
*/
function qa_flag_set_tohide($oldpost, $userid, $handle, $cookieid, $question)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR . 'db/votes.php';
require_once QA_INCLUDE_DIR . 'app/limits.php';
require_once QA_INCLUDE_DIR . 'db/post-update.php';
qa_db_userflag_set($oldpost['postid'], $userid, true);
qa_db_post_recount_flags($oldpost['postid']);
qa_db_flaggedcount_update();
switch ($oldpost['basetype']) {
case 'Q':
$event = 'q_flag';
break;
case 'A':
$event = 'a_flag';
break;
case 'C':
$event = 'c_flag';
break;
} }
$post = qa_db_select_with_pending(qa_db_full_post_selectspec(null, $oldpost['postid']));
qa_report_event($event, $userid, $handle, $cookieid, array(
'postid' => $oldpost['postid'],
'oldpost' => $oldpost,
'flagcount' => $post['flagcount'],
'questionid' => $question['postid'],
'question' => $question,
));
return $post['flagcount'] >= qa_opt('flagging_hide_after') && !$post['hidden'];
}
/**
* Clear (application level) a flag on $oldpost by $userid (with $handle and $cookieid).
* Handles recounting and event reports as appropriate.
* @param $oldpost
* @param $userid
* @param $handle
* @param $cookieid
* @return mixed
*/
function qa_flag_clear($oldpost, $userid, $handle, $cookieid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR . 'db/votes.php';
require_once QA_INCLUDE_DIR . 'app/limits.php';
require_once QA_INCLUDE_DIR . 'db/post-update.php';
qa_db_userflag_set($oldpost['postid'], $userid, false);
qa_db_post_recount_flags($oldpost['postid']);
qa_db_flaggedcount_update();
switch ($oldpost['basetype']) {
case 'Q':
$event = 'q_unflag';
break;
case 'A':
$event = 'a_unflag';
break;
case 'C':
$event = 'c_unflag';
break;
}
/* qa_report_event($event, $userid, $handle, $cookieid, array(
Omit PHP closing tag to help avoid accidental output 'postid' => $oldpost['postid'],
*/ 'oldpost' => $oldpost,
\ No newline at end of file ));
}
/**
* Clear (application level) all flags on $oldpost by $userid (with $handle and $cookieid).
* Handles recounting and event reports as appropriate.
* @param $oldpost
* @param $userid
* @param $handle
* @param $cookieid
* @return mixed
*/
function qa_flags_clear_all($oldpost, $userid, $handle, $cookieid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR . 'db/votes.php';
require_once QA_INCLUDE_DIR . 'app/limits.php';
require_once QA_INCLUDE_DIR . 'db/post-update.php';
qa_db_userflags_clear_all($oldpost['postid']);
qa_db_post_recount_flags($oldpost['postid']);
qa_db_flaggedcount_update();
switch ($oldpost['basetype']) {
case 'Q':
$event = 'q_clearflags';
break;
case 'A':
$event = 'a_clearflags';
break;
case 'C':
$event = 'c_clearflags';
break;
}
qa_report_event($event, $userid, $handle, $cookieid, array(
'postid' => $oldpost['postid'],
'oldpost' => $oldpost,
));
}
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