Commit 42a56c92 by Gideon Greenspan

1.6-beta-1

parent 2c67b77c
1.5.4 1.6-beta-1
\ No newline at end of file \ No newline at end of file
...@@ -69,6 +69,19 @@ ...@@ -69,6 +69,19 @@
*/ */
/* /*
If you wish, you can define QA_BLOBS_DIRECTORY to store BLOBs (binary large objects) such
as avatars and uploaded files on disk, rather than in the database. If so this directory
must be writable by the web server process - on Unix/Linux use chown/chmod as appropriate.
Note than if multiple Q2A sites are using QA_MYSQL_USERS_PREFIX to share users, they must
also have the same value for QA_BLOBS_DIRECTORY.
If there are already some BLOBs stored in the database from previous uploads, click the
'Move BLOBs to disk' button in the 'Stats' section of the admin panel to move them to disk.
define('QA_BLOBS_DIRECTORY', '/path/to/writable_blobs_directory/');
*/
/*
If you wish, you can define QA_COOKIE_DOMAIN so that any cookies created by Q2A are assigned If you wish, you can define QA_COOKIE_DOMAIN so that any cookies created by Q2A are assigned
to a specific domain name, instead of the full domain name of the request by default. This is to a specific domain name, instead of the full domain name of the request by default. This is
useful if you're running multiple Q2A sites on subdomains with a shared user base. useful if you're running multiple Q2A sites on subdomains with a shared user base.
......
...@@ -32,7 +32,7 @@ window.onbeforeunload=function(event) ...@@ -32,7 +32,7 @@ window.onbeforeunload=function(event)
event.returnValue=message; event.returnValue=message;
return message; return message;
} }
} };
function qa_recalc_click(state, elem, value, noteid) function qa_recalc_click(state, elem, value, noteid)
{ {
...@@ -58,7 +58,7 @@ function qa_recalc_click(state, elem, value, noteid) ...@@ -58,7 +58,7 @@ function qa_recalc_click(state, elem, value, noteid)
function qa_recalc_update(elem, state, noteid) function qa_recalc_update(elem, state, noteid)
{ {
if (state) if (state)
qa_ajax_post('recalc', {state:state}, qa_ajax_post('recalc', {state:state, code:elem.form.elements.code.value},
function(lines) { function(lines) {
if (lines[0]=='1') { if (lines[0]=='1') {
if (lines[2]) if (lines[2])
...@@ -114,16 +114,18 @@ function qa_admin_click(target) ...@@ -114,16 +114,18 @@ function qa_admin_click(target)
{ {
var p=target.name.split('_'); var p=target.name.split('_');
var params={postid:p[1], action:p[2]}; var params={entityid:p[1], action:p[2]};
params.code=target.form.elements.code.value;
qa_ajax_post('click_admin', params, qa_ajax_post('click_admin', params,
function (lines) { function (lines) {
if (lines[0]=='1') { if (lines[0]=='1')
qa_conceal(document.getElementById('p'+p[1]), 'q_item'); qa_conceal(document.getElementById('p'+p[1]), 'admin');
else if (lines[0]=='0') {
} else { alert(lines[1]);
qa_hide_waiting(target);
} else
qa_ajax_error(); qa_ajax_error();
}
} }
); );
......
...@@ -51,8 +51,6 @@ function qa_set_outer_html(elem, type, html) ...@@ -51,8 +51,6 @@ function qa_set_outer_html(elem, type, html)
function qa_show_waiting_after(elem, inside) function qa_show_waiting_after(elem, inside)
{ {
if (elem && !elem.qa_waiting_shown) { if (elem && !elem.qa_waiting_shown) {
elem.qa_waiting_shown=true;
var w=document.getElementById('qa-waiting-template'); var w=document.getElementById('qa-waiting-template');
if (w) { if (w) {
...@@ -63,18 +61,31 @@ function qa_show_waiting_after(elem, inside) ...@@ -63,18 +61,31 @@ function qa_show_waiting_after(elem, inside)
elem.insertBefore(c, null); elem.insertBefore(c, null);
else else
elem.parentNode.insertBefore(c, elem.nextSibling); elem.parentNode.insertBefore(c, elem.nextSibling);
elem.qa_waiting_shown=c;
} }
} }
} }
function qa_hide_waiting(elem)
{
var c=elem.qa_waiting_shown;
if (c) {
c.parentNode.removeChild(c);
elem.qa_waiting_shown=null;
}
}
function qa_vote_click(elem) function qa_vote_click(elem)
{ {
var ens=elem.name.split('_'); var ens=elem.name.split('_');
var postid=ens[1]; var postid=ens[1];
var vote=parseInt(ens[2]); var vote=parseInt(ens[2]);
var code=elem.form.elements.code.value;
var anchor=ens[3]; var anchor=ens[3];
qa_ajax_post('vote', {postid:postid, vote:vote}, qa_ajax_post('vote', {postid:postid, vote:vote, code:code},
function(lines) { function(lines) {
if (lines[0]=='1') { if (lines[0]=='1') {
qa_set_inner_html(document.getElementById('voting_'+postid), 'voting', lines.slice(1).join("\n")); qa_set_inner_html(document.getElementById('voting_'+postid), 'voting', lines.slice(1).join("\n"));
...@@ -105,11 +116,14 @@ function qa_vote_click(elem) ...@@ -105,11 +116,14 @@ function qa_vote_click(elem)
function qa_notice_click(elem) function qa_notice_click(elem)
{ {
var ens=elem.name.split('_'); var ens=elem.name.split('_');
var code=elem.form.elements.code.value;
qa_ajax_post('notice', {noticeid:ens[1]}, qa_ajax_post('notice', {noticeid:ens[1], code:code},
function(lines) { function(lines) {
if (lines[0]=='1') if (lines[0]=='1')
qa_conceal(document.getElementById('notice_'+ens[1]), 'notice'); qa_conceal(document.getElementById('notice_'+ens[1]), 'notice');
else if (lines[0]=='0')
alert(lines[1]);
else else
qa_ajax_error(); qa_ajax_error();
} }
...@@ -121,12 +135,16 @@ function qa_notice_click(elem) ...@@ -121,12 +135,16 @@ function qa_notice_click(elem)
function qa_favorite_click(elem) function qa_favorite_click(elem)
{ {
var ens=elem.name.split('_'); var ens=elem.name.split('_');
var code=elem.form.elements.code.value;
qa_ajax_post('favorite', {entitytype:ens[1], entityid:ens[2], favorite:parseInt(ens[3])}, qa_ajax_post('favorite', {entitytype:ens[1], entityid:ens[2], favorite:parseInt(ens[3]), code:code},
function (lines) { function (lines) {
if (lines[0]=='1') if (lines[0]=='1')
qa_set_inner_html(document.getElementById('favoriting'), 'favoriting', lines.slice(1).join("\n")); qa_set_inner_html(document.getElementById('favoriting'), 'favoriting', lines.slice(1).join("\n"));
else else if (lines[0]=='0') {
alert(lines[1]);
qa_hide_waiting(elem);
} else
qa_ajax_error(); qa_ajax_error();
} }
); );
......
...@@ -86,7 +86,9 @@ function qa_submit_answer(questionid, elem) ...@@ -86,7 +86,9 @@ function qa_submit_answer(questionid, elem)
b.style.display='none'; b.style.display='none';
} }
qa_set_inner_html(document.getElementById('a_list_title'), 'a_list_title', lines[2]); var t=document.getElementById('a_list_title');
qa_set_inner_html(t, 'a_list_title', lines[2]);
qa_reveal(t, 'a_list_title');
var e=document.createElement('DIV'); var e=document.createElement('DIV');
e.innerHTML=lines.slice(3).join("\n"); e.innerHTML=lines.slice(3).join("\n");
...@@ -104,7 +106,6 @@ function qa_submit_answer(questionid, elem) ...@@ -104,7 +106,6 @@ function qa_submit_answer(questionid, elem)
qa_conceal(a, 'form'); qa_conceal(a, 'form');
} else if (lines[0]=='0') { } else if (lines[0]=='0') {
// document.forms['q_page_form'].elements['a_doadd2'].value=1;
document.forms['a_form'].submit(); document.forms['a_form'].submit();
} else { } else {
...@@ -146,7 +147,6 @@ function qa_submit_comment(questionid, parentid, elem) ...@@ -146,7 +147,6 @@ function qa_submit_comment(questionid, parentid, elem)
qa_conceal(a, 'form'); qa_conceal(a, 'form');
} else if (lines[0]=='0') { } else if (lines[0]=='0') {
// document.forms['q_page_form'].elements['c'+parentid+'_doadd2'].value=1;
document.forms['c_form_'+parentid].submit(); document.forms['c_form_'+parentid].submit();
} else { } else {
...@@ -167,7 +167,7 @@ function qa_answer_click(answerid, questionid, target) ...@@ -167,7 +167,7 @@ function qa_answer_click(answerid, questionid, target)
params.answerid=answerid; params.answerid=answerid;
params.questionid=questionid; params.questionid=questionid;
params.code=target.form.elements.code.value;
params[target.name]=target.value; params[target.name]=target.value;
qa_ajax_post('click_a', params, qa_ajax_post('click_a', params,
...@@ -184,8 +184,8 @@ function qa_answer_click(answerid, questionid, target) ...@@ -184,8 +184,8 @@ function qa_answer_click(answerid, questionid, target)
qa_conceal(l, 'answer'); qa_conceal(l, 'answer');
} else { } else {
document.forms['q_page_form'].elements['qa_click'].value=target.name; target.form.elements.qa_click.value=target.name;
document.forms['q_page_form'].submit(); target.form.submit();
} }
} }
); );
...@@ -202,7 +202,7 @@ function qa_comment_click(commentid, questionid, parentid, target) ...@@ -202,7 +202,7 @@ function qa_comment_click(commentid, questionid, parentid, target)
params.commentid=commentid; params.commentid=commentid;
params.questionid=questionid; params.questionid=questionid;
params.parentid=parentid; params.parentid=parentid;
params.code=target.form.elements.code.value;
params[target.name]=target.value; params[target.name]=target.value;
qa_ajax_post('click_c', params, qa_ajax_post('click_c', params,
...@@ -217,8 +217,8 @@ function qa_comment_click(commentid, questionid, parentid, target) ...@@ -217,8 +217,8 @@ function qa_comment_click(commentid, questionid, parentid, target)
qa_conceal(l, 'comment'); qa_conceal(l, 'comment');
} else { } else {
document.forms['q_page_form'].elements['qa_click'].value=target.name; target.form.elements.qa_click.value=target.name;
document.forms['q_page_form'].submit(); target.form.submit();
} }
} }
); );
...@@ -228,10 +228,11 @@ function qa_comment_click(commentid, questionid, parentid, target) ...@@ -228,10 +228,11 @@ function qa_comment_click(commentid, questionid, parentid, target)
return false; return false;
} }
function qa_show_comments(parentid, elem) function qa_show_comments(questionid, parentid, elem)
{ {
var params={}; var params={};
params.c_questionid=questionid;
params.c_parentid=parentid; params.c_parentid=parentid;
qa_ajax_post('show_cs', params, qa_ajax_post('show_cs', params,
......
/*
Question2Answer (c) Gideon Greenspan
http://www.question2answer.org/
File: qa-content/qa-user.js
Version: See define()s at top of qa-include/qa-base.php
Description: Javascript to handle question page actions
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
More about this license: http://www.question2answer.org/license.php
*/
function qa_submit_wall_post(elem)
{
var params={};
params.message=document.forms.wallpost.message.value;
params.handle=document.forms.wallpost.handle.value;
params.code=document.forms.wallpost.code.value;
qa_ajax_post('wallpost', params,
function(lines) {
if (lines[0]=='1') {
var l=document.getElementById('wallmessages');
l.innerHTML=lines.slice(2).join("\n");
var c=document.getElementById(lines[1]); // id of new message
if (c) {
c.style.display='none';
qa_reveal(c, 'wallpost');
}
document.forms.wallpost.message.value='';
qa_hide_waiting(elem);
} else if (lines[0]=='0') {
document.forms.wallpost.qa_click.value=elem.name;
document.forms.wallpost.submit();
} else {
qa_ajax_error();
}
}
);
qa_show_waiting_after(elem, false);
return false;
}
function qa_wall_post_click(messageid, target)
{
var params={};
params.messageid=messageid;
params.handle=document.forms.wallpost.handle.value;
params.code=document.forms.wallpost.code.value;
params[target.name]=target.value;
qa_ajax_post('click_wall', params,
function (lines) {
if (lines[0]=='1') {
var l=document.getElementById('m'+messageid);
var h=lines.slice(1).join("\n");
if (h.length)
qa_set_outer_html(l, 'wallpost', h)
else
qa_conceal(l, 'wallpost');
} else {
document.forms.wallpost.qa_click.value=target.name;
document.forms.wallpost.submit();
}
}
);
qa_show_waiting_after(target, false);
return false;
}
\ No newline at end of file
...@@ -176,6 +176,7 @@ ...@@ -176,6 +176,7 @@
* userid: a user id appropriate for your response to qa_get_mysql_user_column_type() * userid: a user id appropriate for your response to qa_get_mysql_user_column_type()
* publicusername: a user description you are willing to show publicly, e.g. the username * publicusername: a user description you are willing to show publicly, e.g. the username
* email: the logged in user's email address * email: the logged in user's email address
* passsalt: (optional) password salt specific to this user, used for form security codes
* level: one of the QA_USER_LEVEL_* values below to denote the user's privileges: * level: one of the QA_USER_LEVEL_* values below to denote the user's privileges:
QA_USER_LEVEL_BASIC, QA_USER_LEVEL_EDITOR, QA_USER_LEVEL_ADMIN, QA_USER_LEVEL_SUPER QA_USER_LEVEL_BASIC, QA_USER_LEVEL_EDITOR, QA_USER_LEVEL_ADMIN, QA_USER_LEVEL_SUPER
......
...@@ -26,12 +26,23 @@ ...@@ -26,12 +26,23 @@
require_once QA_INCLUDE_DIR.'qa-app-users.php'; require_once QA_INCLUDE_DIR.'qa-app-users.php';
require_once QA_INCLUDE_DIR.'qa-app-limits.php'; require_once QA_INCLUDE_DIR.'qa-app-limits.php';
require_once QA_INCLUDE_DIR.'qa-db-selects.php';
// First check whether the person has permission to do this // Load relevant information about this question
$questionid=qa_post_text('a_questionid');
$userid=qa_get_logged_in_userid();
list($question, $childposts)=qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_child_posts_selectspec($userid, $questionid)
);
if (!qa_user_permit_error('permit_post_a', QA_LIMIT_ANSWERS)) { // Check if the question exists, is not closed, and whether the user has permission to do this
require_once QA_INCLUDE_DIR.'qa-db-selects.php';
if ((@$question['basetype']=='Q') && (!isset($question['closedbyid'])) && !qa_user_post_permit_error('permit_post_a', $question, QA_LIMIT_ANSWERS)) {
require_once QA_INCLUDE_DIR.'qa-app-captcha.php'; require_once QA_INCLUDE_DIR.'qa-app-captcha.php';
require_once QA_INCLUDE_DIR.'qa-app-format.php'; require_once QA_INCLUDE_DIR.'qa-app-format.php';
require_once QA_INCLUDE_DIR.'qa-app-post-create.php'; require_once QA_INCLUDE_DIR.'qa-app-post-create.php';
...@@ -40,65 +51,49 @@ ...@@ -40,65 +51,49 @@
require_once QA_INCLUDE_DIR.'qa-page-question-submit.php'; require_once QA_INCLUDE_DIR.'qa-page-question-submit.php';
// Load relevant information about this question and check it exists // Try to create the new answer
$usecaptcha=qa_user_use_captcha(); $usecaptcha=qa_user_use_captcha(qa_user_level_for_post($question));
$questionid=qa_post_text('a_questionid'); $answers=qa_page_q_load_as($question, $childposts);
$userid=qa_get_logged_in_userid(); $answerid=qa_page_q_add_a_submit($question, $answers, $usecaptcha, $in, $errors);
list($question, $childposts)=qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_child_posts_selectspec($userid, $questionid)
);
if ((@$question['basetype']=='Q') && !isset($question['closedbyid'])) { // If successful, page content will be updated via Ajax
$answers=qa_page_q_load_as($question, $childposts);
if (isset($answerid)) {
$answer=qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $answerid));
// Try to create the new answer $question=$question+qa_page_q_post_rules($question, null, null, $childposts); // array union
$answer=$answer+qa_page_q_post_rules($answer, $question, $answers, null);
$answerid=qa_page_q_add_a_submit($question, $answers, $usecaptcha, $in, $errors);
$countanswers=$question['acount']+1; $usershtml=qa_userids_handles_html(array($answer), true);
if (isset($answerid)) { $a_view=qa_page_q_answer_view($question, $answer, false, $usershtml, false);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-answer', null, null);
// If successful, page content will be updated via Ajax
echo "QA_AJAX_RESPONSE\n1\n";
$answer=qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $answerid));
// Send back whether the 'answer' button should still be visible
$question=$question+qa_page_q_post_rules($question, null, null, $childposts); // array union
$answer=$answer+qa_page_q_post_rules($answer, $question, $answers, null); echo (int)qa_opt('allow_multi_answers')."\n";
$usershtml=qa_userids_handles_html(array($answer), true);
$a_view=qa_page_q_answer_view($question, $answer, false, $usershtml, false);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-answer', null, null);
echo "QA_AJAX_RESPONSE\n1\n";
// Send back whether the 'answer' button should still be visible
echo (int)qa_opt('allow_multi_answers')."\n"; // Send back the count of answers
$countanswers=$question['acount']+1;
if ($countanswers==1)
// Send back the count of answers echo qa_lang_html('question/1_answer_title')."\n";
else
if ($countanswers==1) echo qa_lang_html_sub('question/x_answers_title', $countanswers)."\n";
echo qa_lang_html('question/1_answer_title')."\n";
else
echo qa_lang_html_sub('question/x_answers_title', $countanswers)."\n";
// Send back the HTML // Send back the HTML
$themeclass->a_list_item($a_view); $themeclass->a_list_item($a_view);
return; return;
}
} }
} }
......
...@@ -26,15 +26,18 @@ ...@@ -26,15 +26,18 @@
require_once QA_INCLUDE_DIR.'qa-app-admin.php'; require_once QA_INCLUDE_DIR.'qa-app-admin.php';
require_once QA_INCLUDE_DIR.'qa-app-users.php'; require_once QA_INCLUDE_DIR.'qa-app-users.php';
require_once QA_INCLUDE_DIR.'qa-app-cookies.php';
$postid=qa_post_text('postid'); $entityid=qa_post_text('entityid');
$action=qa_post_text('action'); $action=qa_post_text('action');
if (qa_admin_single_click($postid, $action)) // permission check happens in here if (!qa_check_form_security_code('admin/click', qa_post_text('code')))
echo "QA_AJAX_RESPONSE\n0\n".qa_lang('misc/form_security_reload');
elseif (qa_admin_single_click($entityid, $action)) // permission check happens in here
echo "QA_AJAX_RESPONSE\n1\n"; echo "QA_AJAX_RESPONSE\n1\n";
else else
echo "QA_AJAX_RESPONSE\n0\n"; echo "QA_AJAX_RESPONSE\n0\n".qa_lang('main/general_error');
/* /*
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
$userid=qa_get_logged_in_userid(); $userid=qa_get_logged_in_userid();
@list($answer, $question, $qchildposts, $achildposts)=qa_db_select_with_pending( list($answer, $question, $qchildposts, $achildposts)=qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $answerid), qa_db_full_post_selectspec($userid, $answerid),
qa_db_full_post_selectspec($userid, $questionid), qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_child_posts_selectspec($userid, $questionid), qa_db_full_child_posts_selectspec($userid, $questionid),
...@@ -94,7 +94,7 @@ ...@@ -94,7 +94,7 @@
$a_view=qa_page_q_answer_view($question, $answer, ($answer['postid']==$question['selchildid']) && ($answer['type']=='A'), $a_view=qa_page_q_answer_view($question, $answer, ($answer['postid']==$question['selchildid']) && ($answer['type']=='A'),
$usershtml, false); $usershtml, false);
$a_view['c_list']=qa_page_q_comment_follow_list($answer, $achildposts, false, $usershtml, false, null); $a_view['c_list']=qa_page_q_comment_follow_list($question, $answer, $achildposts, false, $usershtml, false, null);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-answer', null, null); $themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-answer', null, null);
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
$userid=qa_get_logged_in_userid(); $userid=qa_get_logged_in_userid();
@list($comment, $question, $parent, $children)=qa_db_select_with_pending( list($comment, $question, $parent, $children)=qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $commentid), qa_db_full_post_selectspec($userid, $commentid),
qa_db_full_post_selectspec($userid, $questionid), qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_post_selectspec($userid, $parentid), qa_db_full_post_selectspec($userid, $parentid),
...@@ -75,7 +75,7 @@ ...@@ -75,7 +75,7 @@
$usershtml=qa_userids_handles_html(array($comment), true); $usershtml=qa_userids_handles_html(array($comment), true);
$c_view=qa_page_q_comment_view($parent, $comment, $usershtml, false); $c_view=qa_page_q_comment_view($question, $parent, $comment, $usershtml, false);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-comment', null, null); $themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-comment', null, null);
......
<?php
/*
Question2Answer (c) Gideon Greenspan
http://www.question2answer.org/
File: qa-include/qa-ajax-click-wall.php
Version: See define()s at top of qa-include/qa-base.php
Description: Server-side response to Ajax single clicks on wall posts
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'qa-app-messages.php';
require_once QA_INCLUDE_DIR.'qa-app-users.php';
require_once QA_INCLUDE_DIR.'qa-app-cookies.php';
require_once QA_INCLUDE_DIR.'qa-db-selects.php';
$tohandle=qa_post_text('handle');
$usermessages=qa_db_select_with_pending(qa_db_recent_messages_selectspec(null, null, $tohandle, false));
$loginuserid=qa_get_logged_in_userid();
$usermessages=qa_wall_posts_add_rules($usermessages, $loginuserid);
foreach ($usermessages as $message)
if (qa_clicked('m'.$message['messageid'].'_dodelete') && $message['deleteable'])
if (qa_check_form_security_code('wall-'.$tohandle, qa_post_text('code'))) {
qa_wall_delete_post($loginuserid, qa_get_logged_in_handle(), qa_cookie_get(), $message);
echo "QA_AJAX_RESPONSE\n1\n";
return;
}
echo "QA_AJAX_RESPONSE\n0\n";
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -26,12 +26,29 @@ ...@@ -26,12 +26,29 @@
require_once QA_INCLUDE_DIR.'qa-app-users.php'; require_once QA_INCLUDE_DIR.'qa-app-users.php';
require_once QA_INCLUDE_DIR.'qa-app-limits.php'; require_once QA_INCLUDE_DIR.'qa-app-limits.php';
require_once QA_INCLUDE_DIR.'qa-db-selects.php';
// First check whether the person has permission to do this // Load relevant information about this question and the comment parent
if (!qa_user_permit_error('permit_post_c', QA_LIMIT_COMMENTS)) { $questionid=qa_post_text('c_questionid');
require_once QA_INCLUDE_DIR.'qa-db-selects.php'; $parentid=qa_post_text('c_parentid');
$userid=qa_get_logged_in_userid();
list($question, $parent, $children)=qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_post_selectspec($userid, $parentid),
qa_db_full_child_posts_selectspec($userid, $parentid)
);
// Check if the question and parent exist, and whether the user has permission to do this
if (
(@$question['basetype']=='Q') &&
((@$parent['basetype']=='Q') || (@$parent['basetype']=='A')) &&
!qa_user_post_permit_error('permit_post_c', $parent, QA_LIMIT_COMMENTS))
{
require_once QA_INCLUDE_DIR.'qa-app-captcha.php'; require_once QA_INCLUDE_DIR.'qa-app-captcha.php';
require_once QA_INCLUDE_DIR.'qa-app-format.php'; require_once QA_INCLUDE_DIR.'qa-app-format.php';
require_once QA_INCLUDE_DIR.'qa-app-post-create.php'; require_once QA_INCLUDE_DIR.'qa-app-post-create.php';
...@@ -41,66 +58,44 @@ ...@@ -41,66 +58,44 @@
require_once QA_INCLUDE_DIR.'qa-util-sort.php'; require_once QA_INCLUDE_DIR.'qa-util-sort.php';
// Load relevant information about this question and check it exists // Try to create the new comment
$usecaptcha=qa_user_use_captcha(); $usecaptcha=qa_user_use_captcha(qa_user_level_for_post($question));
$questionid=qa_post_text('c_questionid'); $commentid=qa_page_q_add_c_submit($question, $parent, $children, $usecaptcha, $in, $errors);
$parentid=qa_post_text('c_parentid');
$userid=qa_get_logged_in_userid();
@list($question, $parent, $children)=qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_post_selectspec($userid, $parentid),
qa_db_full_child_posts_selectspec($userid, $parentid)
);
if (
(@$question['basetype']=='Q') &&
((@$parent['basetype']=='Q') || (@$parent['basetype']=='A'))
) {
// Try to create the new comment // If successful, page content will be updated via Ajax
$commentid=qa_page_q_add_c_submit($question, $parent, $children, $usecaptcha, $in, $errors); if (isset($commentid)) {
$children=qa_db_select_with_pending(qa_db_full_child_posts_selectspec($userid, $parentid));
if (isset($commentid)) { $parent=$parent+qa_page_q_post_rules($parent, ($questionid==$parentid) ? null : $question, null, $children);
// in theory we should retrieve the parent's siblings for the above, but they're not going to be relevant
// If successful, page content will be updated via Ajax foreach ($children as $key => $child)
$children[$key]=$child+qa_page_q_post_rules($child, $parent, $children, null);
$children=qa_db_select_with_pending(qa_db_full_child_posts_selectspec($userid, $parentid));
$usershtml=qa_userids_handles_html($children, true);
$parent=$parent+qa_page_q_post_rules($parent, ($questionid==$parentid) ? null : $question, null, $children);
// in theory we should retrieve the parent's siblings for the above, but they're not going to be relevant qa_sort_by($children, 'created');
foreach ($children as $key => $child) $c_list=qa_page_q_comment_follow_list($question, $parent, $children, true, $usershtml, false, null);
$children[$key]=$child+qa_page_q_post_rules($child, $parent, $children, null);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-comments', null, null);
$usershtml=qa_userids_handles_html($children, true);
echo "QA_AJAX_RESPONSE\n1\n";
qa_sort_by($children, 'created');
$c_list=qa_page_q_comment_follow_list($parent, $children, true, $usershtml, false, null); // Send back the ID of the new comment
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-comments', null, null); echo qa_anchor('C', $commentid)."\n";
echo "QA_AJAX_RESPONSE\n1\n";
// Send back the ID of the new comment
echo qa_anchor('C', $commentid)."\n";
// Send back the HTML // Send back the HTML
foreach ($c_list['cs'] as $c_item) $themeclass->c_list_items($c_list['cs']);
$themeclass->c_list_item($c_item);
return; return;
}
} }
} }
......
...@@ -36,7 +36,10 @@ ...@@ -36,7 +36,10 @@
$userid=qa_get_logged_in_userid(); $userid=qa_get_logged_in_userid();
if (isset($userid)) { if (!qa_check_form_security_code('favorite-'.$entitytype.'-'.$entityid, qa_post_text('code')))
echo "QA_AJAX_RESPONSE\n0\n".qa_lang('misc/form_security_reload');
elseif (isset($userid)) {
$cookieid=qa_cookie_get(); $cookieid=qa_cookie_get();
qa_user_favorite_set($userid, qa_get_logged_in_handle(), $cookieid, $entitytype, $entityid, $setfavorite); qa_user_favorite_set($userid, qa_get_logged_in_handle(), $cookieid, $entitytype, $entityid, $setfavorite);
......
...@@ -31,20 +31,25 @@ ...@@ -31,20 +31,25 @@
$noticeid=qa_post_text('noticeid'); $noticeid=qa_post_text('noticeid');
if ($noticeid=='visitor') if (!qa_check_form_security_code('notice-'.$noticeid, qa_post_text('code')))
setcookie('qa_noticed', 1, time()+86400*3650, '/', QA_COOKIE_DOMAIN); echo "QA_AJAX_RESPONSE\n0\n".qa_lang('misc/form_security_reload');
else { else {
$userid=qa_get_logged_in_userid(); if ($noticeid=='visitor')
setcookie('qa_noticed', 1, time()+86400*3650, '/', QA_COOKIE_DOMAIN);
if ($noticeid=='welcome') else {
qa_db_user_set_flag($userid, QA_USER_FLAGS_WELCOME_NOTICE, false); $userid=qa_get_logged_in_userid();
else
qa_db_usernotice_delete($userid, $noticeid); if ($noticeid=='welcome')
} qa_db_user_set_flag($userid, QA_USER_FLAGS_WELCOME_NOTICE, false);
else
qa_db_usernotice_delete($userid, $noticeid);
}
echo "QA_AJAX_RESPONSE\n1";
echo "QA_AJAX_RESPONSE\n1";
}
/* /*
......
...@@ -29,13 +29,20 @@ ...@@ -29,13 +29,20 @@
if (qa_get_logged_in_level()>=QA_USER_LEVEL_ADMIN) { if (qa_get_logged_in_level()>=QA_USER_LEVEL_ADMIN) {
$state=qa_post_text('state');
$stoptime=time()+3;
while ( qa_recalc_perform_step($state) && (time()<$stoptime) ) if (!qa_check_form_security_code('admin/recalc', qa_post_text('code'))) {
; $state='';
$message=qa_lang('misc/form_security_reload');
} else {
$state=qa_post_text('state');
$stoptime=time()+3;
$message=qa_recalc_get_message($state); while ( qa_recalc_perform_step($state) && (time()<$stoptime) )
;
$message=qa_recalc_get_message($state);
}
} else { } else {
$state=''; $state='';
......
...@@ -34,10 +34,12 @@ ...@@ -34,10 +34,12 @@
// Load relevant information about this question and check it exists // Load relevant information about this question and check it exists
$questionid=qa_post_text('c_questionid');
$parentid=qa_post_text('c_parentid'); $parentid=qa_post_text('c_parentid');
$userid=qa_get_logged_in_userid(); $userid=qa_get_logged_in_userid();
list($parent, $children)=qa_db_select_with_pending( list($question, $parent, $children)=qa_db_select_with_pending(
qa_db_full_post_selectspec($userid, $questionid),
qa_db_full_post_selectspec($userid, $parentid), qa_db_full_post_selectspec($userid, $parentid),
qa_db_full_child_posts_selectspec($userid, $parentid) qa_db_full_child_posts_selectspec($userid, $parentid)
); );
...@@ -53,7 +55,7 @@ ...@@ -53,7 +55,7 @@
qa_sort_by($children, 'created'); qa_sort_by($children, 'created');
$c_list=qa_page_q_comment_follow_list($parent, $children, true, $usershtml, false, null); $c_list=qa_page_q_comment_follow_list($question, $parent, $children, true, $usershtml, false, null);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-comments', null, null); $themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-comments', null, null);
...@@ -62,8 +64,7 @@ ...@@ -62,8 +64,7 @@
// Send back the HTML // Send back the HTML
foreach ($c_list['cs'] as $c_item) $themeclass->c_list_items($c_list['cs']);
$themeclass->c_list_item($c_item);
return; return;
} }
......
...@@ -34,13 +34,18 @@ ...@@ -34,13 +34,18 @@
$postid=qa_post_text('postid'); $postid=qa_post_text('postid');
$vote=qa_post_text('vote'); $vote=qa_post_text('vote');
$code=qa_post_text('code');
$userid=qa_get_logged_in_userid(); $userid=qa_get_logged_in_userid();
$cookieid=qa_cookie_get(); $cookieid=qa_cookie_get();
$post=qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $postid)); if (!qa_check_form_security_code('vote', $code))
$voteerror=qa_lang_html('misc/form_security_reload');
$voteerror=qa_vote_error_html($post, $vote, $userid, qa_request());
else {
$post=qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $postid));
$voteerror=qa_vote_error_html($post, $vote, $userid, qa_request());
}
if ($voteerror===false) { if ($voteerror===false) {
qa_vote_set($post, $userid, qa_get_logged_in_handle(), $cookieid, $vote); qa_vote_set($post, $userid, qa_get_logged_in_handle(), $cookieid, $vote);
...@@ -48,7 +53,7 @@ ...@@ -48,7 +53,7 @@
$post=qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $postid)); $post=qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $postid));
$fields=qa_post_html_fields($post, $userid, $cookieid, array(), null, array( $fields=qa_post_html_fields($post, $userid, $cookieid, array(), null, array(
'voteview' => qa_get_vote_view($post['basetype'], true), // behave as if on question page since the vote succeeded 'voteview' => qa_get_vote_view($post, true), // behave as if on question page since the vote succeeded
)); ));
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'voting', null, null); $themeclass=qa_load_theme_class(qa_get_site_theme(), 'voting', null, null);
......
<?php
/*
Question2Answer (c) Gideon Greenspan
http://www.question2answer.org/
File: qa-include/qa-ajax-wallpost.php
Version: See define()s at top of qa-include/qa-base.php
Description: Server-side response to Ajax wall post requests
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
More about this license: http://www.question2answer.org/license.php
*/
require_once QA_INCLUDE_DIR.'qa-app-messages.php';
require_once QA_INCLUDE_DIR.'qa-app-users.php';
require_once QA_INCLUDE_DIR.'qa-app-cookies.php';
require_once QA_INCLUDE_DIR.'qa-db-selects.php';
$message=qa_post_text('message');
$tohandle=qa_post_text('handle');
$touseraccount=qa_db_select_with_pending(qa_db_user_account_selectspec($tohandle, false));
$loginuserid=qa_get_logged_in_userid();
$errorhtml=qa_wall_error_html($loginuserid, $touseraccount);
if ($errorhtml || (!strlen($message)) || !qa_check_form_security_code('wall-'.$tohandle, qa_post_text('code')) )
echo "QA_AJAX_RESPONSE\n0"; // if there's an error, process in non-Ajax way
else {
$messageid=qa_wall_add_post($loginuserid, qa_get_logged_in_handle(), qa_cookie_get(),
$touseraccount['userid'], $touseraccount['handle'], $message, '');
$usermessages=qa_db_select_with_pending(qa_db_recent_messages_selectspec(null, null, $touseraccount['userid'], true));
$usermessages=qa_wall_posts_add_rules($usermessages, $loginuserid);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'wall', null, null);
echo "QA_AJAX_RESPONSE\n1\n";
echo 'm'.$messageid."\n"; // element in list to be revealed
foreach ($usermessages as $message)
$themeclass->message_item(qa_wall_post_view($message, $loginuserid));
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -74,6 +74,8 @@ ...@@ -74,6 +74,8 @@
'click_c' => 'qa-ajax-click-comment.php', 'click_c' => 'qa-ajax-click-comment.php',
'click_admin' => 'qa-ajax-click-admin.php', 'click_admin' => 'qa-ajax-click-admin.php',
'show_cs' => 'qa-ajax-show-comments.php', 'show_cs' => 'qa-ajax-show-comments.php',
'wallpost' => 'qa-ajax-wallpost.php',
'click_wall' => 'qa-ajax-click-wall.php',
); );
$operation=qa_post_text('qa_operation'); $operation=qa_post_text('qa_operation');
......
...@@ -41,27 +41,109 @@ ...@@ -41,27 +41,109 @@
} }
function qa_get_max_upload_size() function qa_get_blob_directory($blobid)
/* {
Return the maximum size of file that can be uploaded, based on database and PHP limits 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)
{
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)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'qa-db-blobs.php';
$blobid=qa_db_blob_create(defined('QA_BLOBS_DIRECTORY') ? null : $content, $format, $sourcefilename, $userid, $cookieid, $ip);
if (defined('QA_BLOBS_DIRECTORY'))
if (!qa_write_blob_file($blobid, $content, $format))
qa_db_blob_set_content($blobid, $content); // still write to database if writing to disk failed
return $blobid;
}
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;
$directory=qa_get_blob_directory($blobid);
if (is_dir($directory) || mkdir($directory, fileperms(rtrim(QA_BLOBS_DIRECTORY, '/')) & 0777)) {
$filename=qa_get_blob_filename($blobid, $format);
$file=fopen($filename, 'xb');
if (is_resource($file)) {
if (fwrite($file, $content)>=strlen($content))
$written=true;
fclose($file);
if (!$written)
unlink($filename);
}
}
return $written;
}
function qa_read_blob($blobid)
{ {
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); }
$mindb=16777215; // from MEDIUMBLOB column type require_once QA_INCLUDE_DIR.'qa-db-blobs.php';
$blob=qa_db_blob_read($blobid);
$minphp=trim(ini_get('upload_max_filesize')); if (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)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
return file_get_contents(qa_get_blob_filename($blobid, $format));
}
function qa_delete_blob($blobid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
switch (strtolower(substr($minphp, -1))) { require_once QA_INCLUDE_DIR.'qa-db-blobs.php';
case 'g':
$minphp*=1024; if (defined('QA_BLOBS_DIRECTORY')) {
case 'm': $blob=qa_db_blob_read($blobid);
$minphp*=1024;
case 'k': if (isset($blob) && !isset($blob['content']))
$minphp*=1024; unlink(qa_get_blob_filename($blobid, $blob['format']));
} }
return min($mindb, $minphp); qa_db_blob_delete($blobid);
}
function qa_delete_blob_file($blobid, $format)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
unlink(qa_get_blob_filename($blobid, $format));
} }
......
...@@ -41,6 +41,28 @@ ...@@ -41,6 +41,28 @@
} }
function qa_captcha_reason_note($captchareason)
{
$notehtml=null;
switch ($captchareason) {
case 'login':
$notehtml=qa_insert_login_links(qa_lang_html('misc/captcha_login_fix'));
break;
case 'confirm':
$notehtml=qa_insert_login_links(qa_lang_html('misc/captcha_confirm_fix'));
break;
case 'approve':
$notehtml=qa_lang_html('misc/captcha_approve_fix');
break;
}
return $notehtml;
}
function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note=null) function qa_set_up_captcha_field(&$qa_content, &$fields, $errors, $note=null)
/* /*
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
......
...@@ -119,6 +119,8 @@ ...@@ -119,6 +119,8 @@
{ {
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); }
// @error_log(print_r($params, true));
require_once QA_INCLUDE_DIR.'qa-class.phpmailer.php'; require_once QA_INCLUDE_DIR.'qa-class.phpmailer.php';
$mailer=new PHPMailer(); $mailer=new PHPMailer();
......
...@@ -41,6 +41,15 @@ ...@@ -41,6 +41,15 @@
define('QA_LIMIT_MESSAGES', 'M'); define('QA_LIMIT_MESSAGES', 'M');
function qa_user_limits_remaining($action)
{
$userlimits=qa_db_get_pending_result('userlimits', qa_db_user_limits_selectspec(qa_get_logged_in_userid()));
$iplimits=qa_db_get_pending_result('iplimits', qa_db_ip_limits_selectspec(qa_remote_ip_address()));
return qa_limits_calc_remaining($action, @$userlimits[$action], @$iplimits[$action]);
}
function qa_limits_remaining($userid, $action) function qa_limits_remaining($userid, $action)
/* /*
Return how many more times user $userid and/or the requesting IP can perform $action this hour, Return how many more times user $userid and/or the requesting IP can perform $action this hour,
...@@ -49,56 +58,60 @@ ...@@ -49,56 +58,60 @@
{ {
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.'qa-app-options.php';
require_once QA_INCLUDE_DIR.'qa-db-limits.php'; require_once QA_INCLUDE_DIR.'qa-db-limits.php';
$period=(int)(qa_opt('db_time')/3600);
$dblimits=qa_db_limits_get($userid, qa_remote_ip_address(), $action); $dblimits=qa_db_limits_get($userid, qa_remote_ip_address(), $action);
return qa_limits_calc_remaining($action, $dblimits['user'], $dblimits['ip']);
}
function qa_limits_calc_remaining($action, $userlimits, $iplimits)
{
switch ($action) { switch ($action) {
case QA_LIMIT_QUESTIONS: case QA_LIMIT_QUESTIONS:
$userlimit=qa_opt('max_rate_user_qs'); $usermax=qa_opt('max_rate_user_qs');
$iplimit=qa_opt('max_rate_ip_qs'); $ipmax=qa_opt('max_rate_ip_qs');
break; break;
case QA_LIMIT_ANSWERS: case QA_LIMIT_ANSWERS:
$userlimit=qa_opt('max_rate_user_as'); $usermax=qa_opt('max_rate_user_as');
$iplimit=qa_opt('max_rate_ip_as'); $ipmax=qa_opt('max_rate_ip_as');
break; break;
case QA_LIMIT_COMMENTS: case QA_LIMIT_COMMENTS:
$userlimit=qa_opt('max_rate_user_cs'); $usermax=qa_opt('max_rate_user_cs');
$iplimit=qa_opt('max_rate_ip_cs'); $ipmax=qa_opt('max_rate_ip_cs');
break; break;
case QA_LIMIT_VOTES: case QA_LIMIT_VOTES:
$userlimit=qa_opt('max_rate_user_votes'); $usermax=qa_opt('max_rate_user_votes');
$iplimit=qa_opt('max_rate_ip_votes'); $ipmax=qa_opt('max_rate_ip_votes');
break; break;
case QA_LIMIT_REGISTRATIONS: case QA_LIMIT_REGISTRATIONS:
$userlimit=1; // not really relevant $usermax=1; // not really relevant
$iplimit=qa_opt('max_rate_ip_registers'); $ipmax=qa_opt('max_rate_ip_registers');
break; break;
case QA_LIMIT_LOGINS: case QA_LIMIT_LOGINS:
$userlimit=1; // not really relevant $usermax=1; // not really relevant
$iplimit=qa_opt('max_rate_ip_logins'); $ipmax=qa_opt('max_rate_ip_logins');
break; break;
case QA_LIMIT_UPLOADS: case QA_LIMIT_UPLOADS:
$userlimit=qa_opt('max_rate_user_uploads'); $usermax=qa_opt('max_rate_user_uploads');
$iplimit=qa_opt('max_rate_ip_uploads'); $ipmax=qa_opt('max_rate_ip_uploads');
break; break;
case QA_LIMIT_FLAGS: case QA_LIMIT_FLAGS:
$userlimit=qa_opt('max_rate_user_flags'); $usermax=qa_opt('max_rate_user_flags');
$iplimit=qa_opt('max_rate_ip_flags'); $ipmax=qa_opt('max_rate_ip_flags');
break; break;
case QA_LIMIT_MESSAGES: case QA_LIMIT_MESSAGES:
$userlimit=qa_opt('max_rate_user_messages'); $usermax=qa_opt('max_rate_user_messages');
$iplimit=qa_opt('max_rate_ip_messages'); $ipmax=qa_opt('max_rate_ip_messages');
break; break;
default: default:
...@@ -106,9 +119,11 @@ ...@@ -106,9 +119,11 @@
break; break;
} }
$period=(int)(qa_opt('db_time')/3600);
return max(0, min( return max(0, min(
$userlimit-((@$dblimits['user']['period']==$period) ? $dblimits['user']['count'] : 0), $usermax-((@$userlimits['period']==$period) ? $userlimits['count'] : 0),
$iplimit-((@$dblimits['ip']['period']==$period) ? $dblimits['ip']['count'] : 0) $ipmax-((@$iplimits['period']==$period) ? $iplimits['count'] : 0)
)); ));
} }
......
...@@ -122,7 +122,7 @@ ...@@ -122,7 +122,7 @@
qa_db_user_set($userid, 'emailcode', $emailcode); qa_db_user_set($userid, 'emailcode', $emailcode);
} }
$unsubscribeurl=qa_path('unsubscribe', array('c' => $emailcode, 'u' => $handle), qa_opt('site_url')); $unsubscribeurl=qa_path_absolute('unsubscribe', array('c' => $emailcode, 'u' => $handle));
return qa_send_email(array( return qa_send_email(array(
'fromemail' => qa_opt('mailing_from_email'), 'fromemail' => qa_opt('mailing_from_email'),
......
<?php
/*
Question2Answer (c) Gideon Greenspan
http://www.question2answer.org/
File: qa-include/qa-app-messages.php
Version: See define()s at top of qa-include/qa-base.php
Description: Handling public/private messages
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
More about this license: http://www.question2answer.org/license.php
*/
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../');
exit;
}
function qa_wall_error_html($fromuserid, $touseraccount)
{
require_once QA_INCLUDE_DIR.'qa-app-limits.php';
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
if ((!QA_FINAL_EXTERNAL_USERS) && qa_opt('allow_user_walls')) {
if ( ($touseraccount['flags'] & QA_USER_FLAGS_NO_WALL_POSTS) && !(isset($fromuserid) && ($fromuserid==$touseraccount['userid'])) )
return qa_lang_html('profile/post_wall_blocked');
else
switch (qa_user_permit_error('permit_post_wall', QA_LIMIT_MESSAGES)) {
case 'limit':
return qa_lang_html('profile/post_wall_limit');
break;
case 'login':
return qa_insert_login_links(qa_lang_html('profile/post_wall_must_login'), qa_request());
break;
case 'confirm':
return qa_insert_login_links(qa_lang_html('profile/post_wall_must_confirm'), qa_request());
break;
case 'approve':
return qa_lang_html('profile/post_wall_must_be_approved');
break;
case false:
return false;
break;
}
}
return qa_lang_html('users/no_permission');
}
function qa_wall_add_post($userid, $handle, $cookieid, $touserid, $tohandle, $content, $format)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'qa-app-format.php';
require_once QA_INCLUDE_DIR.'qa-db-messages.php';
$messageid=qa_db_message_create($userid, $touserid, $content, $format, true);
qa_report_event('u_wall_post', $userid, $handle, $cookieid, array(
'userid' => $touserid,
'handle' => $tohandle,
'messageid' => $messageid,
'content' => $content,
'format' => $format,
'text' => qa_viewer_text($content, $format),
));
return $messageid;
}
function qa_wall_delete_post($userid, $handle, $cookieid, $message)
{
require_once QA_INCLUDE_DIR.'qa-db-messages.php';
qa_db_message_delete($message['messageid']);
qa_report_event('u_wall_delete', $userid, $handle, $cookieid, array(
'messageid' => $message['messageid'],
'oldmessage' => $message,
));
}
function qa_wall_posts_add_rules($usermessages, $userid)
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$deleteable=isset($userid); // can delete all most recent messages...
foreach ($usermessages as $key => $message) {
if (($message['touserid']!=$userid) && ($message['fromuserid']!=$userid))
$deleteable=false; // ... until we come across one that doesn't involve me
$usermessages[$key]['deleteable']=$deleteable;
}
return $usermessages;
}
function qa_wall_post_view($message, $userid)
{
require_once QA_INCLUDE_DIR.'qa-app-format.php';
$options=qa_message_html_defaults();
$htmlfields=qa_message_html_fields($message, $userid, $options);
if ($message['deleteable'])
$htmlfields['form']=array(
'style' => 'light',
'buttons' => array(
'delete' => array(
'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'),
'popup' => qa_lang_html('profile/delete_wall_post_popup'),
),
),
);
return $htmlfields;
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -36,6 +36,8 @@ ...@@ -36,6 +36,8 @@
define('QA_PERMIT_CONFIRMED', 110); define('QA_PERMIT_CONFIRMED', 110);
define('QA_PERMIT_POINTS', 106); define('QA_PERMIT_POINTS', 106);
define('QA_PERMIT_POINTS_CONFIRMED', 104); 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_EXPERTS', 100);
define('QA_PERMIT_EDITORS', 70); define('QA_PERMIT_EDITORS', 70);
define('QA_PERMIT_MODERATORS', 40); define('QA_PERMIT_MODERATORS', 40);
...@@ -204,14 +206,17 @@ ...@@ -204,14 +206,17 @@
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); }
$fixed_defaults=array( $fixed_defaults=array(
'allow_anon_name' => 1,
'allow_change_usernames' => 1, 'allow_change_usernames' => 1,
'allow_close_questions' => 1, 'allow_close_questions' => 1,
'allow_multi_answers' => 1, 'allow_multi_answers' => 1,
'allow_private_messages' => 1, 'allow_private_messages' => 1,
'allow_user_walls' => 1,
'allow_self_answer' => 1, 'allow_self_answer' => 1,
'allow_view_q_bots' => 1, 'allow_view_q_bots' => 1,
'avatar_allow_gravatar' => 1, 'avatar_allow_gravatar' => 1,
'avatar_allow_upload' => 1, 'avatar_allow_upload' => 1,
'avatar_message_list_size' => 20,
'avatar_profile_size' => 200, 'avatar_profile_size' => 200,
'avatar_q_list_size' => 0, 'avatar_q_list_size' => 0,
'avatar_q_page_a_size' => 40, 'avatar_q_page_a_size' => 40,
...@@ -282,6 +287,7 @@ ...@@ -282,6 +287,7 @@
'min_num_q_tags' => 0, 'min_num_q_tags' => 0,
'moderate_notify_admin' => 1, 'moderate_notify_admin' => 1,
'moderate_points_limit' => 150, 'moderate_points_limit' => 150,
'moderate_update_time' => 1,
'nav_ask' => 1, 'nav_ask' => 1,
'nav_qa_not_home' => 1, 'nav_qa_not_home' => 1,
'nav_questions' => 1, 'nav_questions' => 1,
...@@ -302,7 +308,6 @@ ...@@ -302,7 +308,6 @@
'page_size_tag_qs' => 20, 'page_size_tag_qs' => 20,
'page_size_tags' => 30, 'page_size_tags' => 30,
'page_size_una_qs' => 20, 'page_size_una_qs' => 20,
'page_size_user_posts' => 20,
'page_size_users' => 20, 'page_size_users' => 20,
'pages_prev_next' => 3, 'pages_prev_next' => 3,
'permit_anon_view_ips' => QA_PERMIT_EDITORS, 'permit_anon_view_ips' => QA_PERMIT_EDITORS,
...@@ -311,11 +316,14 @@ ...@@ -311,11 +316,14 @@
'permit_edit_a' => QA_PERMIT_EXPERTS, 'permit_edit_a' => QA_PERMIT_EXPERTS,
'permit_edit_c' => QA_PERMIT_EDITORS, 'permit_edit_c' => QA_PERMIT_EDITORS,
'permit_edit_q' => QA_PERMIT_EDITORS, 'permit_edit_q' => QA_PERMIT_EDITORS,
'permit_edit_silent' => QA_PERMIT_MODERATORS,
'permit_flag' => QA_PERMIT_CONFIRMED, 'permit_flag' => QA_PERMIT_CONFIRMED,
'permit_hide_show' => QA_PERMIT_EDITORS, 'permit_hide_show' => QA_PERMIT_EDITORS,
'permit_moderate' => QA_PERMIT_EXPERTS, 'permit_moderate' => QA_PERMIT_EXPERTS,
'permit_post_wall' => QA_PERMIT_CONFIRMED,
'permit_select_a' => QA_PERMIT_EXPERTS, 'permit_select_a' => QA_PERMIT_EXPERTS,
'permit_view_q_page' => QA_PERMIT_ALL, 'permit_view_q_page' => QA_PERMIT_ALL,
'permit_view_voters_flaggers' => QA_PERMIT_ADMINS,
'permit_vote_a' => QA_PERMIT_USERS, 'permit_vote_a' => QA_PERMIT_USERS,
'permit_vote_down' => QA_PERMIT_USERS, 'permit_vote_down' => QA_PERMIT_USERS,
'permit_vote_q' => QA_PERMIT_USERS, 'permit_vote_q' => QA_PERMIT_USERS,
...@@ -472,6 +480,11 @@ ...@@ -472,6 +480,11 @@
case 'mailing_body': case 'mailing_body':
$value="\n\n\n--\n".qa_opt('site_title')."\n".qa_opt('site_url'); $value="\n\n\n--\n".qa_opt('site_title')."\n".qa_opt('site_url');
break; break;
case 'form_security_salt':
require_once QA_INCLUDE_DIR.'qa-util-string.php';
$value=qa_random_alphanum(32);
break;
default: // call option_default method in any registered modules default: // call option_default method in any registered modules
$moduletypes=qa_list_module_types(); $moduletypes=qa_list_module_types();
...@@ -525,8 +538,9 @@ ...@@ -525,8 +538,9 @@
'contentview' => $full, 'contentview' => $full,
'voteview' => qa_get_vote_view($basetype, $full), 'voteview' => qa_get_vote_view($basetype, $full),
'flagsview' => qa_opt('flagging_of_posts') && $full, 'flagsview' => qa_opt('flagging_of_posts') && $full,
'favoritedview' => true,
'answersview' => $basetype=='Q', 'answersview' => $basetype=='Q',
'viewsview' => ($basetype=='Q') && qa_opt('do_count_q_views') && qa_opt('show_view_counts'), 'viewsview' => ($basetype=='Q') && qa_opt('do_count_q_views') && ($full ? qa_opt('show_view_count_q_page') : qa_opt('show_view_counts')),
'whatview' => true, 'whatview' => true,
'whatlink' => qa_opt('show_a_c_links'), 'whatlink' => qa_opt('show_a_c_links'),
'whenview' => qa_opt('show_when_created'), 'whenview' => qa_opt('show_when_created'),
...@@ -544,37 +558,87 @@ ...@@ -544,37 +558,87 @@
); );
} }
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;
}
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'),
);
}
function qa_get_vote_view($basetype, $full=false, $enabledif=true) 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 posts of $basetype (Q/A/C), 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. 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); } 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=''; $disabledsuffix='';
if ($basetype=='Q') { if (($basetype=='Q') || ($basetype=='A')) {
$view=qa_opt('voting_on_qs'); $view=($basetype=='A') ? qa_opt('voting_on_as') : qa_opt('voting_on_qs');
if (!($enabledif && ($full || !qa_opt('voting_on_q_page_only'))))
$disabledsuffix='-disabled-page';
elseif (qa_user_permit_error('permit_vote_q')=='level')
$disabledsuffix='-disabled-level';
elseif (qa_user_permit_error('permit_vote_down')=='level')
$disabledsuffix='-uponly-level';
} elseif ($basetype=='A') {
$view=qa_opt('voting_on_as');
if (!$enabledif) if (!($enabledif && (($basetype=='A') || $full || !qa_opt('voting_on_q_page_only'))))
$disabledsuffix='-disabled-page'; $disabledsuffix='-disabled-page';
elseif (qa_user_permit_error('permit_vote_a')=='level')
$disabledsuffix='-disabled-level';
elseif (qa_user_permit_error('permit_vote_down')=='level')
$disabledsuffix='-uponly-level';
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');
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 } else
$view=false; $view=false;
...@@ -692,12 +756,17 @@ ...@@ -692,12 +756,17 @@
if (qa_opt('comment_on_qs') || qa_opt('comment_on_as')) if (qa_opt('comment_on_qs') || qa_opt('comment_on_as'))
$permits[]='permit_edit_c'; $permits[]='permit_edit_c';
$permits[]='permit_edit_silent';
if (qa_opt('allow_close_questions')) if (qa_opt('allow_close_questions'))
$permits[]='permit_close_q'; $permits[]='permit_close_q';
array_push($permits, 'permit_select_a', 'permit_anon_view_ips'); array_push($permits, 'permit_select_a', 'permit_anon_view_ips');
if (qa_opt('voting_on_qs') || qa_opt('voting_on_as') || qa_opt('flagging_of_posts'))
$permits[]='permit_view_voters_flaggers';
if (qa_opt('flagging_of_posts')) if (qa_opt('flagging_of_posts'))
$permits[]='permit_flag'; $permits[]='permit_flag';
...@@ -705,6 +774,9 @@ ...@@ -705,6 +774,9 @@
array_push($permits, 'permit_hide_show', 'permit_delete_hidden'); array_push($permits, 'permit_hide_show', 'permit_delete_hidden');
if (qa_opt('allow_user_walls'))
$permits[]='permit_post_wall';
return $permits; return $permits;
} }
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
function qa_question_create($followanswer, $userid, $handle, $cookieid, $title, $content, $format, $text, $tagstring, $notify, $email, function qa_question_create($followanswer, $userid, $handle, $cookieid, $title, $content, $format, $text, $tagstring, $notify, $email,
$categoryid=null, $extravalue=null, $queued=false) $categoryid=null, $extravalue=null, $queued=false, $name=null)
/* /*
Add a question (application level) - create record, update appropriate counts, index it, send notifications. Add a question (application level) - create record, update appropriate counts, index it, send notifications.
If question is follow-on from an answer, $followanswer should contain answer database record, otherwise null. If question is follow-on from an answer, $followanswer should contain answer database record, otherwise null.
...@@ -56,7 +56,8 @@ ...@@ -56,7 +56,8 @@
require_once QA_INCLUDE_DIR.'qa-db-selects.php'; require_once QA_INCLUDE_DIR.'qa-db-selects.php';
$postid=qa_db_post_create($queued ? 'Q_QUEUED' : 'Q', @$followanswer['postid'], $userid, isset($userid) ? null : $cookieid, $postid=qa_db_post_create($queued ? 'Q_QUEUED' : 'Q', @$followanswer['postid'], $userid, isset($userid) ? null : $cookieid,
qa_remote_ip_address(), $title, $content, $format, $tagstring, qa_combine_notify_email($userid, $notify, $email), $categoryid); qa_remote_ip_address(), $title, $content, $format, $tagstring, qa_combine_notify_email($userid, $notify, $email),
$categoryid, isset($userid) ? null : $name);
if (isset($extravalue)) { if (isset($extravalue)) {
require_once QA_INCLUDE_DIR.'qa-db-metas.php'; require_once QA_INCLUDE_DIR.'qa-db-metas.php';
...@@ -66,14 +67,13 @@ ...@@ -66,14 +67,13 @@
qa_db_posts_calc_category_path($postid); qa_db_posts_calc_category_path($postid);
qa_db_hotness_update($postid); qa_db_hotness_update($postid);
if (!$queued) { if ($queued) {
qa_db_category_path_qcount_update(qa_db_post_get_category_path($postid)); qa_db_queuedcount_update();
} else {
qa_post_index($postid, 'Q', $postid, @$followanswer['postid'], $title, $content, $format, $text, $tagstring, $categoryid); qa_post_index($postid, 'Q', $postid, @$followanswer['postid'], $title, $content, $format, $text, $tagstring, $categoryid);
qa_update_counts_for_q($postid);
qa_db_points_update_ifuser($userid, 'qposts'); qa_db_points_update_ifuser($userid, 'qposts');
qa_db_qcount_update();
qa_db_unaqcount_update();
qa_db_unselqcount_update();
qa_db_unupaqcount_update();
} }
qa_report_event($queued ? 'q_queue' : 'q_post', $userid, $handle, $cookieid, array( qa_report_event($queued ? 'q_queue' : 'q_post', $userid, $handle, $cookieid, array(
...@@ -87,6 +87,7 @@ ...@@ -87,6 +87,7 @@
'tags' => $tagstring, 'tags' => $tagstring,
'categoryid' => $categoryid, 'categoryid' => $categoryid,
'extra' => $extravalue, 'extra' => $extravalue,
'name' => $name,
'notify' => $notify, 'notify' => $notify,
'email' => $email, 'email' => $email,
)); ));
...@@ -95,6 +96,18 @@ ...@@ -95,6 +96,18 @@
} }
function qa_update_counts_for_q($postid)
{
if (isset($postid)) // post might no longer exist
qa_db_category_path_qcount_update(qa_db_post_get_category_path($postid));
qa_db_qcount_update();
qa_db_unaqcount_update();
qa_db_unselqcount_update();
qa_db_unupaqcount_update();
}
function qa_array_filter_by_keys($inarray, $keys) function qa_array_filter_by_keys($inarray, $keys)
/* /*
Return an array containing the elements of $inarray whose key is in $keys Return an array containing the elements of $inarray whose key is in $keys
...@@ -141,7 +154,7 @@ ...@@ -141,7 +154,7 @@
} }
function qa_answer_create($userid, $handle, $cookieid, $content, $format, $text, $notify, $email, $question, $queued=false) function qa_answer_create($userid, $handle, $cookieid, $content, $format, $text, $notify, $email, $question, $queued=false, $name=null)
/* /*
Add an answer (application level) - create record, update appropriate counts, index it, send notifications. Add an answer (application level) - create record, update appropriate counts, index it, send notifications.
$question should contain database record for the question this is an answer to. $question should contain database record for the question this is an answer to.
...@@ -149,19 +162,20 @@ ...@@ -149,19 +162,20 @@
*/ */
{ {
$postid=qa_db_post_create($queued ? 'A_QUEUED' : 'A', $question['postid'], $userid, isset($userid) ? null : $cookieid, $postid=qa_db_post_create($queued ? 'A_QUEUED' : 'A', $question['postid'], $userid, isset($userid) ? null : $cookieid,
qa_remote_ip_address(), null, $content, $format, null, qa_combine_notify_email($userid, $notify, $email), $question['categoryid']); qa_remote_ip_address(), null, $content, $format, null, qa_combine_notify_email($userid, $notify, $email),
$question['categoryid'], isset($userid) ? null : $name);
qa_db_posts_calc_category_path($postid); qa_db_posts_calc_category_path($postid);
if (!$queued) { if ($queued) {
qa_db_queuedcount_update();
} else {
if ($question['type']=='Q') // don't index answer if parent question is hidden or queued if ($question['type']=='Q') // don't index answer if parent question is hidden or queued
qa_post_index($postid, 'A', $question['postid'], $question['postid'], null, $content, $format, $text, null, $question['categoryid']); qa_post_index($postid, 'A', $question['postid'], $question['postid'], null, $content, $format, $text, null, $question['categoryid']);
qa_db_post_acount_update($question['postid']); qa_update_q_counts_for_a($question['postid']);
qa_db_hotness_update($question['postid']);
qa_db_points_update_ifuser($userid, 'aposts'); qa_db_points_update_ifuser($userid, 'aposts');
qa_db_acount_update();
qa_db_unaqcount_update();
} }
qa_report_event($queued ? 'a_queue' : 'a_post', $userid, $handle, $cookieid, array( qa_report_event($queued ? 'a_queue' : 'a_post', $userid, $handle, $cookieid, array(
...@@ -172,15 +186,26 @@ ...@@ -172,15 +186,26 @@
'format' => $format, 'format' => $format,
'text' => $text, 'text' => $text,
'categoryid' => $question['categoryid'], 'categoryid' => $question['categoryid'],
'name' => $name,
'notify' => $notify, 'notify' => $notify,
'email' => $email, 'email' => $email,
)); ));
return $postid; return $postid;
} }
function qa_update_q_counts_for_a($questionid)
{
qa_db_post_acount_update($questionid);
qa_db_hotness_update($questionid);
qa_db_acount_update();
qa_db_unaqcount_update();
qa_db_unupaqcount_update();
}
function qa_comment_create($userid, $handle, $cookieid, $content, $format, $text, $notify, $email, $question, $parent, $commentsfollows, $queued=false) function qa_comment_create($userid, $handle, $cookieid, $content, $format, $text, $notify, $email, $question, $parent, $commentsfollows, $queued=false, $name=null)
/* /*
Add a comment (application level) - create record, update appropriate counts, index it, send notifications. Add a comment (application level) - create record, update appropriate counts, index it, send notifications.
$question should contain database record for the question this is part of (as direct or comment on Q's answer). $question should contain database record for the question this is part of (as direct or comment on Q's answer).
...@@ -199,11 +224,15 @@ ...@@ -199,11 +224,15 @@
$parent=$question; // for backwards compatibility with old answer parameter $parent=$question; // for backwards compatibility with old answer parameter
$postid=qa_db_post_create($queued ? 'C_QUEUED' : 'C', $parent['postid'], $userid, isset($userid) ? null : $cookieid, $postid=qa_db_post_create($queued ? 'C_QUEUED' : 'C', $parent['postid'], $userid, isset($userid) ? null : $cookieid,
qa_remote_ip_address(), null, $content, $format, null, qa_combine_notify_email($userid, $notify, $email), $question['categoryid']); qa_remote_ip_address(), null, $content, $format, null, qa_combine_notify_email($userid, $notify, $email),
$question['categoryid'], isset($userid) ? null : $name);
qa_db_posts_calc_category_path($postid); qa_db_posts_calc_category_path($postid);
if (!$queued) { if ($queued) {
qa_db_queuedcount_update();
} else {
if ( ($question['type']=='Q') && (($parent['type']=='Q') || ($parent['type']=='A')) ) // only index if antecedents fully visible if ( ($question['type']=='Q') && (($parent['type']=='Q') || ($parent['type']=='A')) ) // only index if antecedents fully visible
qa_post_index($postid, 'C', $question['postid'], $parent['postid'], null, $content, $format, $text, null, $question['categoryid']); qa_post_index($postid, 'C', $question['postid'], $parent['postid'], null, $content, $format, $text, null, $question['categoryid']);
...@@ -229,6 +258,7 @@ ...@@ -229,6 +258,7 @@
'format' => $format, 'format' => $format,
'text' => $text, 'text' => $text,
'categoryid' => $question['categoryid'], 'categoryid' => $question['categoryid'],
'name' => $name,
'notify' => $notify, 'notify' => $notify,
'email' => $email, 'email' => $email,
)); ));
......
...@@ -32,20 +32,19 @@ ...@@ -32,20 +32,19 @@
function qa_q_list_page_content($questions, $pagesize, $start, $count, $sometitle, $nonetitle, function qa_q_list_page_content($questions, $pagesize, $start, $count, $sometitle, $nonetitle,
$navcategories, $categoryid, $categoryqcount, $categorypathprefix, $feedpathprefix, $suggest, $navcategories, $categoryid, $categoryqcount, $categorypathprefix, $feedpathprefix, $suggest,
$pagelinkparams=null, $categoryparams=null, $categoryisfavorite=null) $pagelinkparams=null, $categoryparams=null, $dummy=null)
/* /*
Returns the $qa_content structure for a question list page showing $questions retrieved from the database. Returns the $qa_content structure for a question list page showing $questions retrieved from the
If $pagesize is not null, it sets the max number of questions to display. database. If $pagesize is not null, it sets the max number of questions to display. If $count is
If $count is not null, pagination is determined by $start and $count. not null, pagination is determined by $start and $count. The page title is $sometitle unless
The page title is $sometitle unless there are no questions shown, in which case it's $nonetitle. there are no questions shown, in which case it's $nonetitle. $navcategories should contain the
$navcategories should contain the categories retrived from the database using qa_db_category_nav_selectspec(...) for categories retrived from the database using qa_db_category_nav_selectspec(...) for $categoryid,
$categoryid, which is the current category shown (set $categoryisfavorite to whether the user has favorited it). which is the current category shown. If $categorypathprefix is set, category navigation will be
If $categorypathprefix is set, category navigation will be shown, with per-category question counts if shown, with per-category question counts if $categoryqcount is true. The nav links will have the
$categoryqcount is true. The nav links will have the prefix $categorypathprefix and possible extra $categoryparams. prefix $categorypathprefix and possible extra $categoryparams. If $feedpathprefix is set, the
If $feedpathprefix is set, the page has an RSS feed whose URL uses that prefix. page has an RSS feed whose URL uses that prefix. If there are no links to other pages, $suggest
If there are no links to other pages, $suggest is used to suggest what the user should do. is used to suggest what the user should do. The $pagelinkparams are passed through to
The $pagelinkparams are passed through to qa_html_page_links(...) which creates links for page 2, 3, etc.. qa_html_page_links(...) which creates links for page 2, 3, etc..
*/ */
{ {
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); }
...@@ -70,6 +69,10 @@ ...@@ -70,6 +69,10 @@
$qa_content['q_list']['form']=array( $qa_content['q_list']['form']=array(
'tags' => 'METHOD="POST" ACTION="'.qa_self_html().'"', 'tags' => 'METHOD="POST" ACTION="'.qa_self_html().'"',
'hidden' => array(
'code' => qa_get_form_security_code('vote'),
),
); );
$qa_content['q_list']['qs']=array(); $qa_content['q_list']['qs']=array();
...@@ -77,19 +80,24 @@ ...@@ -77,19 +80,24 @@
if (count($questions)) { if (count($questions)) {
$qa_content['title']=$sometitle; $qa_content['title']=$sometitle;
$options=qa_post_html_defaults('Q'); $defaults=qa_post_html_defaults('Q');
if (isset($categorypathprefix)) if (isset($categorypathprefix))
$options['categorypathprefix']=$categorypathprefix; $defaults['categorypathprefix']=$categorypathprefix;
foreach ($questions as $question) foreach ($questions as $question)
$qa_content['q_list']['qs'][]=qa_any_to_q_html_fields($question, $userid, qa_cookie_get(), $usershtml, null, $options); $qa_content['q_list']['qs'][]=qa_any_to_q_html_fields($question, $userid, qa_cookie_get(),
$usershtml, null, qa_post_html_options($question, $defaults));
} else } else
$qa_content['title']=$nonetitle; $qa_content['title']=$nonetitle;
if (isset($userid) && isset($categoryid) && isset($categoryisfavorite)) {
$favoritemap=qa_get_favorite_non_qs_map();
$categoryisfavorite=@$favoritemap['category'][$navcategories[$categoryid]['backpath']] ? true : false;
if (isset($userid) && isset($categoryid) && isset($categoryisfavorite))
$qa_content['favorite']=qa_favorite_form(QA_ENTITY_CATEGORY, $categoryid, $categoryisfavorite, $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'])); qa_lang_sub($categoryisfavorite ? 'main/remove_x_favorites' : 'main/add_category_x_favorites', $navcategories[$categoryid]['title']));
}
if (isset($count) && isset($pagesize)) if (isset($count) && isset($pagesize))
$qa_content['page_links']=qa_html_page_links(qa_request(), $start, $pagesize, $count, qa_opt('pages_prev_next'), $pagelinkparams); $qa_content['page_links']=qa_html_page_links(qa_request(), $start, $pagesize, $count, qa_opt('pages_prev_next'), $pagelinkparams);
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
^tagwords (all): index of words in tags of posts (a tag can contain multiple words) ^tagwords (all): index of words in tags of posts (a tag can contain multiple words)
^posttags (all): index tags of posts ^posttags (all): index tags of posts
^words (all): list of words used for indexes ^words (all): list of words used for indexes
^options (title=cache_qcount|cache_acount|cache_ccount|cache_tagcount|cache_unaqcount): total Qs, As, Cs, tags, unanswered Qs ^options (title=cache_*): cached values for various things (e.g. counting questions)
Recalculated in dorecountposts: Recalculated in dorecountposts:
============================== ==============================
...@@ -70,6 +70,7 @@ ...@@ -70,6 +70,7 @@
require_once QA_INCLUDE_DIR.'qa-db-points.php'; require_once QA_INCLUDE_DIR.'qa-db-points.php';
require_once QA_INCLUDE_DIR.'qa-db-selects.php'; require_once QA_INCLUDE_DIR.'qa-db-selects.php';
require_once QA_INCLUDE_DIR.'qa-db-admin.php'; require_once QA_INCLUDE_DIR.'qa-db-admin.php';
require_once QA_INCLUDE_DIR.'qa-db-users.php';
require_once QA_INCLUDE_DIR.'qa-app-options.php'; require_once QA_INCLUDE_DIR.'qa-app-options.php';
require_once QA_INCLUDE_DIR.'qa-app-post-create.php'; require_once QA_INCLUDE_DIR.'qa-app-post-create.php';
require_once QA_INCLUDE_DIR.'qa-app-post-update.php'; require_once QA_INCLUDE_DIR.'qa-app-post-update.php';
...@@ -228,6 +229,7 @@ ...@@ -228,6 +229,7 @@
case 'dorecalcpoints_usercount': case 'dorecalcpoints_usercount':
qa_db_userpointscount_update(); // for progress update - not necessarily accurate qa_db_userpointscount_update(); // for progress update - not necessarily accurate
qa_db_uapprovecount_update(); // needs to be somewhere and this is the most appropriate place
qa_recalc_transition($state, 'dorecalcpoints_recalc'); qa_recalc_transition($state, 'dorecalcpoints_recalc');
break; break;
...@@ -294,7 +296,16 @@ ...@@ -294,7 +296,16 @@
foreach ($posts as $postid => $post) { foreach ($posts as $postid => $post) {
$followonq=($post['basetype']=='Q') && ($postid!=$questionid); $followonq=($post['basetype']=='Q') && ($postid!=$questionid);
qa_create_event_for_q_user($questionid, $postid, $followonq ? QA_UPDATE_FOLLOWS : null, $post['userid'], @$posts[$post['parentid']]['userid'], $post['created']); if ($followonq)
$updatetype=QA_UPDATE_FOLLOWS;
elseif ( ($post['basetype']=='C') && (@$posts[$post['parentid']]['basetype']=='Q') )
$updatetype=QA_UPDATE_C_FOR_Q;
elseif ( ($post['basetype']=='C') && (@$posts[$post['parentid']]['basetype']=='A') )
$updatetype=QA_UPDATE_C_FOR_A;
else
$updatetype=null;
qa_create_event_for_q_user($questionid, $postid, $updatetype, $post['userid'], @$posts[$post['parentid']]['userid'], $post['created']);
if (isset($post['updated']) && !$followonq) if (isset($post['updated']) && !$followonq)
qa_create_event_for_q_user($questionid, $postid, $post['updatetype'], $post['lastuserid'], $post['userid'], $post['updated']); qa_create_event_for_q_user($questionid, $postid, $post['updatetype'], $post['lastuserid'], $post['userid'], $post['updated']);
...@@ -323,7 +334,7 @@ ...@@ -323,7 +334,7 @@
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'], null, $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;
...@@ -460,6 +471,51 @@ ...@@ -460,6 +471,51 @@
} else } else
qa_recalc_transition($state, 'dodeletehidden_complete'); qa_recalc_transition($state, 'dodeletehidden_complete');
break; break;
case 'doblobstodisk':
qa_recalc_transition($state, 'doblobstodisk_move');
break;
case 'doblobstodisk_move':
$blob=qa_db_get_next_blob_in_db($next);
if (isset($blob)) {
require_once QA_INCLUDE_DIR.'qa-app-blobs.php';
require_once QA_INCLUDE_DIR.'qa-db-blobs.php';
if (qa_write_blob_file($blob['blobid'], $blob['content'], $blob['format']))
qa_db_blob_set_content($blob['blobid'], null);
$next=1+$blob['blobid'];
$done++;
$continue=true;
} else
qa_recalc_transition($state, 'doblobstodisk_complete');
break;
case 'doblobstodb':
qa_recalc_transition($state, 'doblobstodb_move');
break;
case 'doblobstodb_move':
$blob=qa_db_get_next_blob_on_disk($next);
if (isset($blob)) {
require_once QA_INCLUDE_DIR.'qa-app-blobs.php';
require_once QA_INCLUDE_DIR.'qa-db-blobs.php';
$content=qa_read_blob_file($blob['blobid'], $blob['format']);
qa_db_blob_set_content($blob['blobid'], $content);
qa_delete_blob_file($blob['blobid'], $blob['format']);
$next=1+$blob['blobid'];
$done++;
$continue=true;
} else
qa_recalc_transition($state, 'doblobstodb_complete');
break;
default: default:
$state=''; $state='';
...@@ -530,6 +586,14 @@ ...@@ -530,6 +586,14 @@
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':
$length=qa_db_count_blobs_in_db();
break;
case 'doblobstodb_move':
$length=qa_db_count_blobs_on_disk();
break;
default: default:
$length=0; $length=0;
...@@ -676,6 +740,19 @@ ...@@ -676,6 +740,19 @@
case 'dodeletehidden_complete': case 'dodeletehidden_complete':
$message=qa_lang('admin/delete_hidden_complete'); $message=qa_lang('admin/delete_hidden_complete');
break; break;
case 'doblobstodisk_move':
case 'doblobstodb_move':
$message=strtr(qa_lang('admin/blobs_move_moved'), array(
'^1' => number_format($done),
'^2' => number_format($length)
));
break;
case 'doblobstodisk_complete':
case 'doblobstodb_complete':
$message=qa_lang('admin/blobs_move_complete');
break;
default: default:
$message=''; $message='';
......
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
// Perform the appropriate database queries // Perform the appropriate database queries
@list($postidfull, $postidtype, $postidquestion, $pageidpage)=qa_db_select_with_pending( list($postidfull, $postidtype, $postidquestion, $pageidpage)=qa_db_select_with_pending(
count($keypostidgetfull) ? qa_db_posts_selectspec($userid, array_keys($keypostidgetfull), $fullcontent) : null, count($keypostidgetfull) ? qa_db_posts_selectspec($userid, array_keys($keypostidgetfull), $fullcontent) : null,
count($keypostidgettype) ? qa_db_posts_basetype_selectspec(array_keys($keypostidgettype)) : 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($keypostidgetquestion) ? qa_db_posts_to_qs_selectspec($userid, array_keys($keypostidgetquestion), $fullcontent) : null,
......
...@@ -44,13 +44,18 @@ ...@@ -44,13 +44,18 @@
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_FOLLOWS', 'F'); // questions only (this is only set in streams tables, not on post)
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
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_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 Omit PHP closing tag to help avoid accidental output
......
<?php
/*
Question2Answer (c) Gideon Greenspan
http://www.question2answer.org/
File: qa-include/qa-app-upload.php
Version: See define()s at top of qa-include/qa-base.php
Description: Application-level file upload functionality
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
More about this license: http://www.question2answer.org/license.php
*/
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../');
exit;
}
function qa_get_max_upload_size()
/*
Return the maximum size of file that can be uploaded, based on database and PHP limits
*/
{
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'));
switch (strtolower(substr($minphp, -1))) {
case 'g':
$minphp*=1024;
case 'm':
$minphp*=1024;
case 'k':
$minphp*=1024;
}
return min($mindb, $minphp);
}
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);
}
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.'qa-app-users.php';
require_once QA_INCLUDE_DIR.'qa-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;
default:
$result['error']=qa_lang('users/no_permission');
return $result;
}
// Check the uploaded file is not too large
$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
$result['error']=qa_lang_sub('main/max_upload_size_x', number_format($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
$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);
// If appropriate, get more accurate image size and apply constraints to it
require_once QA_INCLUDE_DIR.'qa-util-image.php';
if ($isimage && qa_has_gd_image()) {
$image=@imagecreatefromstring($content);
if (is_resource($image)) {
$result['width']=$width=imagesx($image);
$result['height']=$height=imagesy($image);
if (isset($imagemaxwidth) || isset($imagemaxheight))
if (qa_image_constrain(
$width, $height,
isset($imagemaxwidth) ? $imagemaxwidth : $width,
isset($imagemaxheight) ? $imagemaxheight : $height
)) {
qa_gd_image_resize($image, $width, $height);
if (is_resource($image)) {
$content=qa_gd_image_jpeg($image);
$result['format']=$format='jpeg';
$result['width']=$width;
$result['height']=$height;
}
}
if (is_resource($image)) // might have been lost
imagedestroy($image);
}
}
// Create the blob and return
require_once QA_INCLUDE_DIR.'qa-app-blobs.php';
$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;
}
$result['bloburl']=qa_get_blob_url($result['blobid'], true);
return $result;
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -166,6 +166,7 @@ ...@@ -166,6 +166,7 @@
$userid=qa_db_user_create($email, $password, $handle, $level, qa_remote_ip_address()); $userid=qa_db_user_create($email, $password, $handle, $level, qa_remote_ip_address());
qa_db_points_update_ifuser($userid, null); qa_db_points_update_ifuser($userid, null);
qa_db_uapprovecount_update();
if ($confirmed) if ($confirmed)
qa_db_user_set_flag($userid, QA_USER_FLAGS_EMAIL_CONFIRMED, true); qa_db_user_set_flag($userid, QA_USER_FLAGS_EMAIL_CONFIRMED, true);
...@@ -186,6 +187,9 @@ ...@@ -186,6 +187,9 @@
} else } else
$confirm=''; $confirm='';
if (qa_opt('moderate_users') && qa_opt('approve_user_required') && ($level<QA_USER_LEVEL_EXPERT))
qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_APPROVE, true);
qa_send_notification($userid, $email, $handle, qa_lang('emails/welcome_subject'), qa_lang('emails/welcome_body'), array( qa_send_notification($userid, $email, $handle, qa_lang('emails/welcome_subject'), qa_lang('emails/welcome_body'), array(
'^password' => isset($password) ? $password : qa_lang('users/password_to_set'), '^password' => isset($password) ? $password : qa_lang('users/password_to_set'),
'^url' => qa_opt('site_url'), '^url' => qa_opt('site_url'),
...@@ -218,6 +222,7 @@ ...@@ -218,6 +222,7 @@
$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();
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);
...@@ -263,7 +268,7 @@ ...@@ -263,7 +268,7 @@
$emailcode=qa_db_user_rand_emailcode(); $emailcode=qa_db_user_rand_emailcode();
qa_db_user_set($userid, 'emailcode', $emailcode); qa_db_user_set($userid, 'emailcode', $emailcode);
return qa_path('confirm', array('c' => $emailcode, 'u' => $handle), qa_opt('site_url')); return qa_path_absolute('confirm', array('c' => $emailcode, 'u' => $handle));
} }
...@@ -285,6 +290,41 @@ ...@@ -285,6 +290,41 @@
'email' => $email, 'email' => $email,
)); ));
} }
function qa_set_user_level($userid, $handle, $level, $oldlevel)
{
require_once QA_INCLUDE_DIR.'qa-db-users.php';
if ($level!=$oldlevel) {
qa_db_user_set($userid, 'level', $level);
qa_db_uapprovecount_update();
if ($level>=QA_USER_LEVEL_APPROVED)
qa_db_user_set_flag($userid, QA_USER_FLAGS_MUST_APPROVE, false);
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)
{
require_once QA_INCLUDE_DIR.'qa-db-users.php';
qa_db_user_set_flag($userid, QA_USER_FLAGS_USER_BLOCKED, $blocked);
qa_db_uapprovecount_update();
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) function qa_start_reset_user($userid)
...@@ -305,7 +345,7 @@ ...@@ -305,7 +345,7 @@
if (!qa_send_notification($userid, $userinfo['email'], $userinfo['handle'], qa_lang('emails/reset_subject'), qa_lang('emails/reset_body'), array( if (!qa_send_notification($userid, $userinfo['email'], $userinfo['handle'], qa_lang('emails/reset_subject'), qa_lang('emails/reset_body'), array(
'^code' => $userinfo['emailcode'], '^code' => $userinfo['emailcode'],
'^url' => qa_path('reset', array('c' => $userinfo['emailcode'], 'e' => $userinfo['email']), qa_opt('site_url')), '^url' => qa_path_absolute('reset', array('c' => $userinfo['emailcode'], 'e' => $userinfo['email'])),
))) )))
qa_fatal_error('Could not send reset password email'); qa_fatal_error('Could not send reset password email');
} }
...@@ -366,9 +406,9 @@ ...@@ -366,9 +406,9 @@
$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.'qa-db-blobs.php'; require_once QA_INCLUDE_DIR.'qa-app-blobs.php';
$newblobid=qa_db_blob_create($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);
...@@ -378,7 +418,7 @@ ...@@ -378,7 +418,7 @@
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_db_blob_delete($oldblobid); qa_delete_blob($oldblobid);
return true; return true;
} }
......
...@@ -38,6 +38,9 @@ ...@@ -38,6 +38,9 @@
{ {
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); }
// 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(...)
require_once QA_INCLUDE_DIR.'qa-app-users.php'; require_once QA_INCLUDE_DIR.'qa-app-users.php';
require_once QA_INCLUDE_DIR.'qa-app-limits.php'; require_once QA_INCLUDE_DIR.'qa-app-limits.php';
...@@ -47,11 +50,11 @@ ...@@ -47,11 +50,11 @@
qa_opt(($post['basetype']=='Q') ? 'voting_on_qs' : 'voting_on_as') && qa_opt(($post['basetype']=='Q') ? 'voting_on_qs' : 'voting_on_as') &&
( (!isset($post['userid'])) || (!isset($userid)) || ($post['userid']!=$userid) ) ( (!isset($post['userid'])) || (!isset($userid)) || ($post['userid']!=$userid) )
) { ) {
$permiterror=qa_user_permit_error(($post['basetype']=='Q') ? 'permit_vote_q' : 'permit_vote_a', QA_LIMIT_VOTES); $permiterror=qa_user_post_permit_error(($post['basetype']=='Q') ? 'permit_vote_q' : 'permit_vote_a', $post, QA_LIMIT_VOTES);
$errordownonly=(!$permiterror) && ($vote<0); $errordownonly=(!$permiterror) && ($vote<0);
if ($errordownonly) if ($errordownonly)
$permiterror=qa_user_permit_error('permit_vote_down'); $permiterror=qa_user_post_permit_error('permit_vote_down', $post);
switch ($permiterror) { switch ($permiterror) {
case 'login': case 'login':
...@@ -144,6 +147,9 @@ ...@@ -144,6 +147,9 @@
{ {
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); }
// 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.'qa-db-selects.php'; require_once QA_INCLUDE_DIR.'qa-db-selects.php';
require_once QA_INCLUDE_DIR.'qa-app-options.php'; require_once QA_INCLUDE_DIR.'qa-app-options.php';
require_once QA_INCLUDE_DIR.'qa-app-users.php'; require_once QA_INCLUDE_DIR.'qa-app-users.php';
...@@ -155,7 +161,7 @@ ...@@ -155,7 +161,7 @@
( (!isset($post['userid'])) || (!isset($userid)) || ($post['userid']!=$userid) ) ( (!isset($post['userid'])) || (!isset($userid)) || ($post['userid']!=$userid) )
) { ) {
switch (qa_user_permit_error('permit_flag', QA_LIMIT_FLAGS)) { switch (qa_user_post_permit_error('permit_flag', $post, QA_LIMIT_FLAGS)) {
case 'login': case 'login':
return qa_insert_login_links(qa_lang_html('question/flag_must_login'), $topage); return qa_insert_login_links(qa_lang_html('question/flag_must_login'), $topage);
break; break;
...@@ -192,9 +198,11 @@ ...@@ -192,9 +198,11 @@
require_once QA_INCLUDE_DIR.'qa-db-votes.php'; require_once QA_INCLUDE_DIR.'qa-db-votes.php';
require_once QA_INCLUDE_DIR.'qa-app-limits.php'; require_once QA_INCLUDE_DIR.'qa-app-limits.php';
require_once QA_INCLUDE_DIR.'qa-db-post-update.php';
qa_db_userflag_set($oldpost['postid'], $userid, true); qa_db_userflag_set($oldpost['postid'], $userid, true);
qa_db_post_recount_flags($oldpost['postid']); qa_db_post_recount_flags($oldpost['postid']);
qa_db_flaggedcount_update();
switch ($oldpost['basetype']) { switch ($oldpost['basetype']) {
case 'Q': case 'Q':
...@@ -234,9 +242,11 @@ ...@@ -234,9 +242,11 @@
require_once QA_INCLUDE_DIR.'qa-db-votes.php'; require_once QA_INCLUDE_DIR.'qa-db-votes.php';
require_once QA_INCLUDE_DIR.'qa-app-limits.php'; require_once QA_INCLUDE_DIR.'qa-app-limits.php';
require_once QA_INCLUDE_DIR.'qa-db-post-update.php';
qa_db_userflag_set($oldpost['postid'], $userid, false); qa_db_userflag_set($oldpost['postid'], $userid, false);
qa_db_post_recount_flags($oldpost['postid']); qa_db_post_recount_flags($oldpost['postid']);
qa_db_flaggedcount_update();
switch ($oldpost['basetype']) { switch ($oldpost['basetype']) {
case 'Q': case 'Q':
...@@ -269,9 +279,11 @@ ...@@ -269,9 +279,11 @@
require_once QA_INCLUDE_DIR.'qa-db-votes.php'; require_once QA_INCLUDE_DIR.'qa-db-votes.php';
require_once QA_INCLUDE_DIR.'qa-app-limits.php'; require_once QA_INCLUDE_DIR.'qa-app-limits.php';
require_once QA_INCLUDE_DIR.'qa-db-post-update.php';
qa_db_userflags_clear_all($oldpost['postid']); qa_db_userflags_clear_all($oldpost['postid']);
qa_db_post_recount_flags($oldpost['postid']); qa_db_post_recount_flags($oldpost['postid']);
qa_db_flaggedcount_update();
switch ($oldpost['basetype']) { switch ($oldpost['basetype']) {
case 'Q': case 'Q':
......
...@@ -25,8 +25,8 @@ ...@@ -25,8 +25,8 @@
*/ */
define('QA_VERSION', '1.5.4'); // also used as suffix for .js and .css requests define('QA_VERSION', '1.6-beta-1'); // also used as suffix for .js and .css requests
define('QA_BUILD_DATE', '2012-11-29'); define('QA_BUILD_DATE', '2013-06-06');
// Execution section of this file - remainder contains function definitions // Execution section of this file - remainder contains function definitions
...@@ -314,7 +314,8 @@ ...@@ -314,7 +314,8 @@
$functionindex=array(); $functionindex=array();
foreach ($qa_override_files as $index => $override) { foreach ($qa_override_files as $index => $override) {
$functionsphp=file_get_contents($override['directory'].$override['include']); $filename=$override['directory'].$override['include'];
$functionsphp=file_get_contents($filename);
preg_match_all('/\Wfunction\s+(qa_[a-z_]+)\s*\(/im', $functionsphp, $rawmatches, PREG_PATTERN_ORDER|PREG_OFFSET_CAPTURE); preg_match_all('/\Wfunction\s+(qa_[a-z_]+)\s*\(/im', $functionsphp, $rawmatches, PREG_PATTERN_ORDER|PREG_OFFSET_CAPTURE);
...@@ -344,7 +345,7 @@ ...@@ -344,7 +345,7 @@
// echo '<PRE STYLE="text-align:left;">'.htmlspecialchars($functionsphp).'</PRE>'; // to debug munged code // echo '<PRE STYLE="text-align:left;">'.htmlspecialchars($functionsphp).'</PRE>'; // to debug munged code
eval('?'.'>'.$functionsphp); qa_eval_from_file($functionsphp, $filename);
} }
} }
...@@ -493,6 +494,31 @@ ...@@ -493,6 +494,31 @@
// Low-level functions used throughout Q2A // Low-level functions used throughout Q2A
function qa_eval_from_file($contents, $filename)
{
// could also use ini_set('error_append_string') but apparently it doesn't work for errors logged on disk
global $php_errormsg;
$oldtrackerrors=@ini_set('track_errors', 1);
$php_errormsg=null;
eval('?'.'>'.$contents);
if (strlen($php_errormsg)) {
switch (strtolower(@ini_get('display_errors'))) {
case 'on': case '1': case 'yes': case 'true': case 'stdout': case 'stderr':
echo ' of '.qa_html($filename)."\n";
break;
}
@error_log('PHP Question2Answer more info: '.$php_errormsg." in eval()'d code from ".qa_html($filename));
}
@ini_set('track_errors', $oldtrackerrors);
}
function qa_call($function, $args) function qa_call($function, $args)
/* /*
Call $function with the arguments in the $args array (doesn't work with call-by-reference functions) Call $function with the arguments in the $args array (doesn't work with call-by-reference functions)
...@@ -574,8 +600,7 @@ ...@@ -574,8 +600,7 @@
$backtrace=array_reverse(array_slice(debug_backtrace(), 1)); $backtrace=array_reverse(array_slice(debug_backtrace(), 1));
foreach ($backtrace as $trace) foreach ($backtrace as $trace)
echo '<FONT COLOR="#'.((strpos(@$trace['file'], '/qa-plugin/')!==false) ? 'f00' : '999').'">'. echo '<FONT COLOR="#'.((strpos(@$trace['file'], '/qa-plugin/')!==false) ? 'f00' : '999').'">'.
qa_html(@$trace['function'].'() '.@$trace['file'].':'.@$trace['line']).'</FONT><BR>'; qa_html(@$trace['function'].'() in '.basename(@$trace['file']).':'.@$trace['line']).'</FONT><BR>';
qa_exit('error'); qa_exit('error');
} }
...@@ -635,7 +660,7 @@ ...@@ -635,7 +660,7 @@
$object=new $module['class']; $object=new $module['class'];
if (method_exists($object, 'load_module')) if (method_exists($object, 'load_module'))
$object->load_module($module['directory'], qa_path_to_root().$module['urltoroot']); $object->load_module($module['directory'], qa_path_to_root().$module['urltoroot'], $type, $name);
$qa_modules[$type][$name]['object']=$object; $qa_modules[$type][$name]['object']=$object;
return $object; return $object;
...@@ -742,6 +767,12 @@ ...@@ -742,6 +767,12 @@
} }
function qa_xml($string)
{
return htmlspecialchars(preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F]/', '', (string)$string));
}
function qa_js($value, $forcequotes=false) function qa_js($value, $forcequotes=false)
/* /*
Return JavaScript representation of $value, putting in quotes if non-numeric or if $forcequote is true Return JavaScript representation of $value, putting in quotes if non-numeric or if $forcequote is true
...@@ -856,12 +887,13 @@ ...@@ -856,12 +887,13 @@
function qa_clicked($name) function qa_clicked($name)
/* /*
Return true if form button $name was clicked (as TYPE=SUBMIT/IMAGE) to create this page request. Return true if form button $name was clicked (as TYPE=SUBMIT/IMAGE) to create this page request, or if a
simulated click was sent for the button (via 'qa_click' POST field)
*/ */
{ {
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($_POST[$name]) || isset($_POST[$name.'_x']); return isset($_POST[$name]) || isset($_POST[$name.'_x']) || (qa_post_text('qa_click')==$name);
} }
...@@ -1166,6 +1198,12 @@ ...@@ -1166,6 +1198,12 @@
{ {
return qa_html(qa_path($request, $params, $rooturl, $neaturls, $anchor)); return qa_html(qa_path($request, $params, $rooturl, $neaturls, $anchor));
} }
function qa_path_absolute($request, $params=null, $anchor=null)
{
return qa_path($request, $params, qa_opt('site_url'), null, $anchor);
}
function qa_q_request($questionid, $title) function qa_q_request($questionid, $title)
...@@ -1227,7 +1265,7 @@ ...@@ -1227,7 +1265,7 @@
{ {
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); }
if ( (($showtype=='A') || ($showtype=='C')) && isset($showid)) { if ( (($showtype=='Q') || ($showtype=='A') || ($showtype=='C')) && isset($showid)) {
$params=array('show' => $showid); // due to pagination $params=array('show' => $showid); // due to pagination
$anchor=qa_anchor($showtype, $showid); $anchor=qa_anchor($showtype, $showid);
......
...@@ -45,11 +45,11 @@ ...@@ -45,11 +45,11 @@
// Output the blob in question // Output the blob in question
require_once QA_INCLUDE_DIR.'qa-db-blobs.php'; require_once QA_INCLUDE_DIR.'qa-app-blobs.php';
qa_db_connect('qa_blob_db_fail_handler'); qa_db_connect('qa_blob_db_fail_handler');
$blob=qa_db_blob_read(qa_get('qa_blobid')); $blob=qa_read_blob(qa_get('qa_blobid'));
if (isset($blob)) { if (isset($blob)) {
header('Cache-Control: max-age=2592000, public'); // allows browsers and proxies to cache the blob header('Cache-Control: max-age=2592000, public'); // allows browsers and proxies to cache the blob
......
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
echo '<H1>Checking US English files in <code>qa-include</code>...</H1>'; echo '<H1>Checking US English files in <code>qa-include</code>...</H1>';
$includefiles=glob(QA_INCLUDE_DIR.'qa-*.php'); $includefiles=array_merge(glob(QA_INCLUDE_DIR.'qa-*.php'), glob(QA_PLUGIN_DIR.'*/qa-*.php'));
$definite=array(); $definite=array();
$probable=array(); $probable=array();
......
...@@ -138,7 +138,7 @@ ...@@ -138,7 +138,7 @@
*/ */
{ {
return qa_db_read_all_values(qa_db_query_sub( return qa_db_read_all_values(qa_db_query_sub(
"SELECT postid FROM ^posts WHERE userid=# AND type IN ('Q', 'A', 'C')", "SELECT postid FROM ^posts WHERE userid=# AND type IN ('Q', 'A', 'C', 'Q_QUEUED', 'A_QUEUED', 'C_QUEUED')",
$userid $userid
)); ));
} }
...@@ -150,7 +150,7 @@ ...@@ -150,7 +150,7 @@
*/ */
{ {
return qa_db_read_all_values(qa_db_query_sub( return qa_db_read_all_values(qa_db_query_sub(
"SELECT postid FROM ^posts WHERE createip=INET_ATON($) AND type IN ('Q', 'A', 'C')", "SELECT postid FROM ^posts WHERE createip=INET_ATON($) AND type IN ('Q', 'A', 'C', 'Q_QUEUED', 'A_QUEUED', 'C_QUEUED')",
$ip $ip
)); ));
} }
...@@ -169,6 +169,45 @@ ...@@ -169,6 +169,45 @@
else else
return array(); return array();
} }
function qa_db_get_unapproved_users($count)
{
$results=qa_db_read_all_assoc(qa_db_query_sub(
"SELECT ^users.userid, UNIX_TIMESTAMP(created) AS created, INET_NTOA(createip) AS createip, email, handle, title, content FROM ^users LEFT JOIN ^userprofile ON ^users.userid=^userprofile.userid AND LENGTH(content)>0 WHERE level<# AND NOT (flags&#) ORDER BY created DESC LIMIT #",
QA_USER_LEVEL_APPROVED, QA_USER_FLAGS_USER_BLOCKED, $count
));
$users=array();
foreach ($results as $result) {
$userid=$result['userid'];
if (!isset($users[$userid])) {
$users[$result['userid']]=$result;
$users[$result['userid']]['profile']=array();
unset($users[$userid]['title']);
unset($users[$userid]['content']);
}
if (isset($result['title']) && isset($result['content']))
$users[$userid]['profile'][$result['title']]=$result['content'];
}
return $users;
}
function qa_db_has_blobs_on_disk()
{
return count(qa_db_read_all_values(qa_db_query_sub('SELECT blobid FROM ^blobs WHERE content IS NULL LIMIT 1'))) ? true : false;
}
function qa_db_has_blobs_in_db()
{
return count(qa_db_read_all_values(qa_db_query_sub('SELECT blobid FROM ^blobs WHERE content IS NOT NULL LIMIT 1'))) ? true : false;
}
function qa_db_category_last_pos($parentid) function qa_db_category_last_pos($parentid)
...@@ -442,7 +481,7 @@ ...@@ -442,7 +481,7 @@
} }
function qa_db_userfield_create($title, $content, $flags) function qa_db_userfield_create($title, $content, $flags, $permit=null)
/* /*
Create a new user field with (internal) tag $title, label $content, and $flags in the database Create a new user field with (internal) tag $title, label $content, and $flags in the database
*/ */
...@@ -450,22 +489,22 @@ ...@@ -450,22 +489,22 @@
$position=qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^userfields')); $position=qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^userfields'));
qa_db_query_sub( qa_db_query_sub(
'INSERT INTO ^userfields (title, content, position, flags) VALUES ($, $, #, #)', 'INSERT INTO ^userfields (title, content, position, flags, permit) VALUES ($, $, #, #, #)',
$title, $content, $position, $flags $title, $content, $position, $flags, $permit
); );
return qa_db_last_insert_id(); return qa_db_last_insert_id();
} }
function qa_db_userfield_set_fields($fieldid, $content, $flags) function qa_db_userfield_set_fields($fieldid, $content, $flags, $permit=null)
/* /*
Change the user field $fieldid to have label $content and $flags in the database (the title column cannot be changed once set) Change the user field $fieldid to have label $content and $flags in the database (the title column cannot be changed once set)
*/ */
{ {
qa_db_query_sub( qa_db_query_sub(
'UPDATE ^userfields SET content=$, flags=# WHERE fieldid=#', 'UPDATE ^userfields SET content=$, flags=#, permit=# WHERE fieldid=#',
$content, $flags, $fieldid $content, $flags, $permit, $fieldid
); );
} }
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
} }
function qa_db_blob_create($content, $format, $filename=null, $userid=null, $cookieid=null, $ip=null) function qa_db_blob_create($content, $format, $sourcefilename=null, $userid=null, $cookieid=null, $ip=null)
/* /*
Create a new blob in the database with $content and $format, returning its blobid Create a new blob in the database with $content and $format, returning its blobid
*/ */
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
qa_db_query_sub( qa_db_query_sub(
'INSERT INTO ^blobs (blobid, format, content, filename, userid, cookieid, createip, created) VALUES (#, $, $, $, $, #, INET_ATON($), NOW())', 'INSERT INTO ^blobs (blobid, format, content, filename, userid, cookieid, createip, created) VALUES (#, $, $, $, $, #, INET_ATON($), NOW())',
$blobid, $format, $content, $filename, $userid, $cookieid, $ip $blobid, $format, $content, $sourcefilename, $userid, $cookieid, $ip
); );
return $blobid; return $blobid;
...@@ -69,6 +69,15 @@ ...@@ -69,6 +69,15 @@
} }
function qa_db_blob_set_content($blobid, $content)
{
qa_db_query_sub(
'UPDATE ^blobs SET content=$ WHERE blobid=#',
$content, $blobid
);
}
function qa_db_blob_delete($blobid) function qa_db_blob_delete($blobid)
/* /*
Delete blob $blobid in the database Delete blob $blobid in the database
......
...@@ -117,7 +117,7 @@ ...@@ -117,7 +117,7 @@
Add an event to the event stream for $userid which is not related to an entity they are following (but rather a Add an event to the event stream for $userid which is not related to an entity they are following (but rather a
notification which is relevant for them, e.g. if someone answers their question). The event of type $updatetype notification which is relevant for them, e.g. if someone answers their question). The event of type $updatetype
relates to $lastpostid whose antecedent question is $questionid, and was caused by $lastuserid. Pass a unix 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. Also handles truncation. $timestamp for the event time or leave as null to use now. Also handles truncation of event streams.
*/ */
{ {
require_once QA_INCLUDE_DIR.'qa-app-updates.php'; require_once QA_INCLUDE_DIR.'qa-app-updates.php';
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
@define('QA_DB_MAX_CONTENT_LENGTH', 8000); @define('QA_DB_MAX_CONTENT_LENGTH', 8000);
@define('QA_DB_MAX_FORMAT_LENGTH', 20); @define('QA_DB_MAX_FORMAT_LENGTH', 20);
@define('QA_DB_MAX_TAGS_LENGTH', 800); @define('QA_DB_MAX_TAGS_LENGTH', 800);
@define('QA_DB_MAX_NAME_LENGTH', 40);
@define('QA_DB_MAX_WORD_LENGTH', 80); @define('QA_DB_MAX_WORD_LENGTH', 80);
@define('QA_DB_MAX_CAT_PAGE_TITLE_LENGTH', 80); @define('QA_DB_MAX_CAT_PAGE_TITLE_LENGTH', 80);
@define('QA_DB_MAX_CAT_PAGE_TAGS_LENGTH', 200); @define('QA_DB_MAX_CAT_PAGE_TAGS_LENGTH', 200);
......
...@@ -30,18 +30,27 @@ ...@@ -30,18 +30,27 @@
} }
function qa_db_message_create($fromuserid, $touserid, $content, $format) function qa_db_message_create($fromuserid, $touserid, $content, $format, $public=false)
/* /*
Record a private message sent from $fromuserid to $touserid with $content in $format Record a private message sent from $fromuserid to $touserid with $content in $format
*/ */
{ {
qa_db_query_sub( qa_db_query_sub(
'INSERT INTO ^messages (fromuserid, touserid, content, format, created) VALUES (#, #, $, $, NOW())', 'INSERT INTO ^messages (type, fromuserid, touserid, content, format, created) VALUES ($, #, #, $, $, NOW())',
$fromuserid, $touserid, $content, $format $public ? 'PUBLIC' : 'PRIVATE', $fromuserid, $touserid, $content, $format
); );
return qa_db_last_insert_id(); return qa_db_last_insert_id();
} }
function qa_db_message_delete($messageid)
{
qa_db_query_sub(
'DELETE FROM ^messages WHERE messageid=#',
$messageid
);
}
/* /*
......
...@@ -30,14 +30,15 @@ ...@@ -30,14 +30,15 @@
} }
function qa_db_post_create($type, $parentid, $userid, $cookieid, $ip, $title, $content, $format, $tagstring, $notify, $categoryid=null) function qa_db_post_create($type, $parentid, $userid, $cookieid, $ip, $title, $content, $format, $tagstring, $notify, $categoryid=null, $name=null)
/* /*
Create a new post in the database and return its ID (based on auto-incrementing) Create a new post in the database and return its ID (based on auto-incrementing)
*/ */
{ {
qa_db_query_sub( qa_db_query_sub(
'INSERT INTO ^posts (categoryid, type, parentid, userid, cookieid, createip, title, content, format, tags, notify, created) VALUES (#, $, #, $, #, INET_ATON($), $, $, $, $, $, NOW())', 'INSERT INTO ^posts (categoryid, type, parentid, userid, cookieid, createip, title, content, format, tags, notify, name, created) '.
$categoryid, $type, $parentid, $userid, $cookieid, $ip, $title, $content, $format, $tagstring, $notify 'VALUES (#, $, #, $, #, INET_ATON($), $, $, $, $, $, $, NOW())',
$categoryid, $type, $parentid, $userid, $cookieid, $ip, $title, $content, $format, $tagstring, $notify, $name
); );
return qa_db_last_insert_id(); return qa_db_last_insert_id();
...@@ -352,6 +353,13 @@ ...@@ -352,6 +353,13 @@
if (qa_should_update_counts()) if (qa_should_update_counts())
qa_db_query_sub("REPLACE ^options (title, content) SELECT 'cache_unupaqcount', COUNT(*) FROM ^posts WHERE type='Q' AND amaxvote=0"); qa_db_query_sub("REPLACE ^options (title, content) SELECT 'cache_unupaqcount', COUNT(*) FROM ^posts WHERE type='Q' AND amaxvote=0");
} }
function qa_db_queuedcount_update()
{
if (qa_should_update_counts())
qa_db_query_sub("REPLACE ^options (title, content) SELECT 'cache_queuedcount', COUNT(*) FROM ^posts WHERE type IN ('Q_QUEUED', 'A_QUEUED', 'C_QUEUED')");
}
/* /*
Omit PHP closing tag to help avoid accidental output Omit PHP closing tag to help avoid accidental output
......
...@@ -113,21 +113,21 @@ ...@@ -113,21 +113,21 @@
} }
function qa_db_post_set_content($postid, $title, $content, $format, $tagstring, $notify, $lastuserid=null, $lastip=null, $updatetype=QA_UPDATE_CONTENT) function qa_db_post_set_content($postid, $title, $content, $format, $tagstring, $notify, $lastuserid=null, $lastip=null, $updatetype=QA_UPDATE_CONTENT, $name=null)
/* /*
Set the text fields in the database of $postid to $title, $content, $tagstring and $notify, and record Set the text fields in the database of $postid to $title, $content, $tagstring and $notify, and record
that $lastuserid did it from $lastip (if at least one is specified) with $updatetype. that $lastuserid did it from $lastip (if at least one is specified) with $updatetype.
*/ */
{ {
if (isset($lastuserid) || isset($lastip)) if (isset($lastuserid) || isset($lastip)) // use COALESCE() for name since $name=null means it should not be modified (for backwards compatibility)
qa_db_query_sub( qa_db_query_sub(
'UPDATE ^posts SET title=$, content=$, format=$, tags=$, notify=$, updated=NOW(), updatetype=$, lastuserid=$, lastip=INET_ATON($) WHERE postid=#', 'UPDATE ^posts SET title=$, content=$, format=$, tags=$, name=COALESCE($, name), notify=$, updated=NOW(), updatetype=$, lastuserid=$, lastip=INET_ATON($) WHERE postid=#',
$title, $content, $format, $tagstring, $notify, $updatetype, $lastuserid, $lastip, $postid $title, $content, $format, $tagstring, $name, $notify, $updatetype, $lastuserid, $lastip, $postid
); );
else else
qa_db_query_sub( qa_db_query_sub(
'UPDATE ^posts SET title=$, content=$, format=$, tags=$, notify=$ WHERE postid=#', 'UPDATE ^posts SET title=$, content=$, format=$, tags=$, name=COALESCE($, name), notify=$ WHERE postid=#',
$title, $content, $format, $tagstring, $notify, $postid $title, $content, $format, $tagstring, $name, $notify, $postid
); );
} }
...@@ -193,6 +193,21 @@ ...@@ -193,6 +193,21 @@
} }
function qa_db_post_set_updated($postid, $updated)
{
if (isset($updated))
qa_db_query_sub(
'UPDATE ^posts SET updated=FROM_UNIXTIME(#) WHERE postid=#',
$updated, $postid
);
else
qa_db_query_sub(
'UPDATE ^posts SET updated=NOW() WHERE postid=#',
$postid
);
}
function qa_db_post_delete($postid) function qa_db_post_delete($postid)
/* /*
Deletes post $postid from the database (will also delete any votes on the post due to foreign key cascading) Deletes post $postid from the database (will also delete any votes on the post due to foreign key cascading)
...@@ -330,6 +345,12 @@ ...@@ -330,6 +345,12 @@
return array(); return array();
} }
function qa_db_flaggedcount_update()
{
if (qa_should_update_counts())
qa_db_query_sub("REPLACE ^options (title, content) SELECT 'cache_flaggedcount', COUNT(*) FROM ^posts WHERE flagcount>0 AND type IN ('Q', 'A', 'C')");
}
/* /*
Omit PHP closing tag to help avoid accidental output Omit PHP closing tag to help avoid accidental output
......
...@@ -377,7 +377,36 @@ ...@@ -377,7 +377,36 @@
$type.'_HIDDEN', $startpostid $type.'_HIDDEN', $startpostid
)); ));
} }
// For moving blobs between database and disk...
function qa_db_count_blobs_in_db()
{
return qa_db_read_one_value(qa_db_query_sub('SELECT COUNT(*) FROM ^blobs WHERE content IS NOT NULL'));
}
function qa_db_get_next_blob_in_db($startblobid)
{
return qa_db_read_one_assoc(qa_db_query_sub(
'SELECT blobid, content, format FROM ^blobs WHERE blobid>=# AND content IS NOT NULL',
$startblobid
), true);
}
function qa_db_count_blobs_on_disk()
{
return qa_db_read_one_value(qa_db_query_sub('SELECT COUNT(*) FROM ^blobs WHERE content IS NULL'));
}
function qa_db_get_next_blob_on_disk($startblobid)
{
return qa_db_read_one_assoc(qa_db_query_sub(
'SELECT blobid, format FROM ^blobs WHERE blobid>=# AND content IS NULL',
$startblobid
), true);
}
/* /*
Omit PHP closing tag to help avoid accidental output Omit PHP closing tag to help avoid accidental output
......
...@@ -273,7 +273,7 @@ ...@@ -273,7 +273,7 @@
*/ */
{ {
if ($sync) { // need to lock all tables since any could be used by a plugin's event module if ($sync) { // need to lock all tables since any could be used by a plugin's event module
$tables=qa_db_list_tables_lc(); $tables=qa_db_list_tables();
$locks=array(); $locks=array();
foreach ($tables as $table) foreach ($tables as $table)
...@@ -286,6 +286,21 @@ ...@@ -286,6 +286,21 @@
} }
function qa_db_user_levels_set($userid, $userlevels)
{
qa_db_query_sub(
'DELETE FROM ^userlevels WHERE userid=$',
$userid
);
foreach ($userlevels as $userlevel)
qa_db_query_sub(
'REPLACE ^userlevels (userid, entitytype, entityid, level) VALUES ($, $, #, #)',
$userid, $userlevel['entitytype'], $userlevel['entityid'], $userlevel['level']
);
}
function qa_db_users_get_mailing_next($lastuserid, $count) function qa_db_users_get_mailing_next($lastuserid, $count)
/* /*
Get the information required for sending a mailing to the next $count users with userids greater than $lastuserid Get the information required for sending a mailing to the next $count users with userids greater than $lastuserid
...@@ -296,6 +311,16 @@ ...@@ -296,6 +311,16 @@
$lastuserid, $count $lastuserid, $count
)); ));
} }
function qa_db_uapprovecount_update()
{
if ( qa_should_update_counts() && !QA_FINAL_EXTERNAL_USERS )
qa_db_query_sub(
"REPLACE ^options (title, content) SELECT 'cache_uapprovecount', COUNT(*) FROM ^users WHERE level<# AND NOT (flags&#)",
QA_USER_LEVEL_APPROVED, QA_USER_FLAGS_USER_BLOCKED
);
}
/* /*
......
...@@ -131,6 +131,22 @@ ...@@ -131,6 +131,22 @@
)); ));
} }
function qa_db_uservoteflag_posts_get($postids)
{
if (QA_FINAL_EXTERNAL_USERS)
return qa_db_read_all_assoc(qa_db_query_sub(
'SELECT postid, userid, vote, flag FROM ^uservotes WHERE postid IN (#) AND ((vote!=0) OR (flag!=0))',
$postids
));
else
return qa_db_read_all_assoc(qa_db_query_sub(
'SELECT postid, handle, vote, flag FROM ^uservotes LEFT JOIN ^users ON ^uservotes.userid=^users.userid WHERE postid IN (#) AND ((vote!=0) OR (flag!=0))',
$postids
));
}
/* /*
Omit PHP closing tag to help avoid accidental output Omit PHP closing tag to help avoid accidental output
......
...@@ -274,7 +274,7 @@ ...@@ -274,7 +274,7 @@
$prefix=QA_MYSQL_TABLE_PREFIX; $prefix=QA_MYSQL_TABLE_PREFIX;
if (defined('QA_MYSQL_USERS_PREFIX')) if (defined('QA_MYSQL_USERS_PREFIX')) {
switch (strtolower($rawname)) { switch (strtolower($rawname)) {
case 'users': case 'users':
case 'userlogins': case 'userlogins':
...@@ -284,9 +284,12 @@ ...@@ -284,9 +284,12 @@
case 'cookies': case 'cookies':
case 'blobs': case 'blobs':
case 'cache': case 'cache':
case 'userlogins_ibfk_1': // also special cases for constraint names
case 'userprofile_ibfk_1':
$prefix=QA_MYSQL_USERS_PREFIX; $prefix=QA_MYSQL_USERS_PREFIX;
break; break;
} }
}
return $prefix.$rawname; return $prefix.$rawname;
} }
...@@ -395,12 +398,13 @@ ...@@ -395,12 +398,13 @@
Return an array of the names of all tables in the Q2A database, converted to lower case Return an array of the names of all tables in the Q2A database, converted to lower case
*/ */
{ {
$tables=qa_db_read_all_values(qa_db_query_raw('SHOW TABLES')); return array_map('strtolower', qa_db_list_tables());
}
foreach ($tables as $key => $table)
$tables[$key]=strtolower($table);
function qa_db_list_tables()
return $tables; {
return qa_db_read_all_values(qa_db_query_raw('SHOW TABLES'));
} }
......
...@@ -69,6 +69,7 @@ ...@@ -69,6 +69,7 @@
break; break;
case 'u_message': case 'u_message':
case 'u_wall_post':
qa_limits_increment($userid, QA_LIMIT_MESSAGES); qa_limits_increment($userid, QA_LIMIT_MESSAGES);
break; break;
} }
......
...@@ -42,13 +42,14 @@ ...@@ -42,13 +42,14 @@
switch ($event) { switch ($event) {
case 'q_post': case 'q_post':
$followanswer=@$params['followanswer']; $followanswer=@$params['followanswer'];
$sendhandle=isset($handle) ? $handle : (strlen($params['name']) ? $params['name'] : qa_lang('main/anonymous'));
if (isset($followanswer['notify']) && !qa_post_is_by_user($followanswer, $userid, $cookieid)) { if (isset($followanswer['notify']) && !qa_post_is_by_user($followanswer, $userid, $cookieid)) {
$blockwordspreg=qa_get_block_words_preg(); $blockwordspreg=qa_get_block_words_preg();
$sendtext=qa_viewer_text($followanswer['content'], $followanswer['format'], array('blockwordspreg' => $blockwordspreg)); $sendtext=qa_viewer_text($followanswer['content'], $followanswer['format'], array('blockwordspreg' => $blockwordspreg));
qa_send_notification($followanswer['userid'], $followanswer['notify'], @$followanswer['handle'], qa_lang('emails/a_followed_subject'), qa_lang('emails/a_followed_body'), array( qa_send_notification($followanswer['userid'], $followanswer['notify'], @$followanswer['handle'], qa_lang('emails/a_followed_subject'), qa_lang('emails/a_followed_body'), array(
'^q_handle' => isset($handle) ? $handle : qa_lang('main/anonymous'), '^q_handle' => $sendhandle,
'^q_title' => qa_block_words_replace($params['title'], $blockwordspreg), '^q_title' => qa_block_words_replace($params['title'], $blockwordspreg),
'^a_content' => $sendtext, '^a_content' => $sendtext,
'^url' => qa_q_path($params['postid'], $params['title'], true), '^url' => qa_q_path($params['postid'], $params['title'], true),
...@@ -57,7 +58,7 @@ ...@@ -57,7 +58,7 @@
if (qa_opt('notify_admin_q_post')) if (qa_opt('notify_admin_q_post'))
qa_send_notification(null, qa_opt('feedback_email'), null, qa_lang('emails/q_posted_subject'), qa_lang('emails/q_posted_body'), array( qa_send_notification(null, qa_opt('feedback_email'), null, qa_lang('emails/q_posted_subject'), qa_lang('emails/q_posted_body'), array(
'^q_handle' => isset($handle) ? $handle : qa_lang('main/anonymous'), '^q_handle' => $sendhandle,
'^q_title' => $params['title'], // don't censor title or content here since we want the admin to see bad words '^q_title' => $params['title'], // don't censor title or content here since we want the admin to see bad words
'^q_content' => $params['text'], '^q_content' => $params['text'],
'^url' => qa_q_path($params['postid'], $params['title'], true), '^url' => qa_q_path($params['postid'], $params['title'], true),
...@@ -71,7 +72,7 @@ ...@@ -71,7 +72,7 @@
if (isset($question['notify']) && !qa_post_is_by_user($question, $userid, $cookieid)) if (isset($question['notify']) && !qa_post_is_by_user($question, $userid, $cookieid))
qa_send_notification($question['userid'], $question['notify'], @$question['handle'], qa_lang('emails/q_answered_subject'), qa_lang('emails/q_answered_body'), array( qa_send_notification($question['userid'], $question['notify'], @$question['handle'], qa_lang('emails/q_answered_subject'), qa_lang('emails/q_answered_body'), array(
'^a_handle' => isset($handle) ? $handle : qa_lang('main/anonymous'), '^a_handle' => isset($handle) ? $handle : (strlen($params['name']) ? $params['name'] : qa_lang('main/anonymous')),
'^q_title' => $question['title'], '^q_title' => $question['title'],
'^a_content' => qa_block_words_replace($params['text'], qa_get_block_words_preg()), '^a_content' => qa_block_words_replace($params['text'], qa_get_block_words_preg()),
'^url' => qa_q_path($question['postid'], $question['title'], true, 'A', $params['postid']), '^url' => qa_q_path($question['postid'], $question['title'], true, 'A', $params['postid']),
...@@ -101,7 +102,7 @@ ...@@ -101,7 +102,7 @@
} }
$blockwordspreg=qa_get_block_words_preg(); $blockwordspreg=qa_get_block_words_preg();
$sendhandle=isset($handle) ? $handle : qa_lang('main/anonymous'); $sendhandle=isset($handle) ? $handle : (strlen($params['name']) ? $params['name'] : qa_lang('main/anonymous'));
$sendcontext=qa_block_words_replace($context, $blockwordspreg); $sendcontext=qa_block_words_replace($context, $blockwordspreg);
$sendtext=qa_block_words_replace($params['text'], $blockwordspreg); $sendtext=qa_block_words_replace($params['text'], $blockwordspreg);
$sendurl=qa_q_path($question['postid'], $question['title'], true, $parent['basetype'], $parent['postid']); $sendurl=qa_q_path($question['postid'], $question['title'], true, $parent['basetype'], $parent['postid']);
...@@ -152,32 +153,54 @@ ...@@ -152,32 +153,54 @@
case 'q_queue': case 'q_queue':
case 'q_requeue':
if (qa_opt('moderate_notify_admin')) if (qa_opt('moderate_notify_admin'))
qa_send_notification(null, qa_opt('feedback_email'), null, qa_lang('emails/moderate_subject'), qa_lang('emails/moderate_body'), array( qa_send_notification(null, qa_opt('feedback_email'), null,
'^p_handle' => isset($handle) ? $handle : qa_lang('main/anonymous'), ($event=='q_requeue') ? qa_lang('emails/remoderate_subject') : qa_lang('emails/moderate_subject'),
'^p_context' => trim(@$params['title']."\n\n".$params['text']), ($event=='q_requeue') ? qa_lang('emails/remoderate_body') : qa_lang('emails/moderate_body'),
'^url' => qa_q_path($params['postid'], $params['title'], true), array(
)); '^p_handle' => isset($handle) ? $handle : (strlen($params['name']) ? $params['name'] :
(strlen(@$oldquestion['name']) ? $oldquestion['name'] : qa_lang('main/anonymous'))),
'^p_context' => trim(@$params['title']."\n\n".$params['text']),
'^url' => qa_q_path($params['postid'], $params['title'], true),
'^a_url' => qa_path_absolute('admin/moderate'),
)
);
break; break;
case 'a_queue': case 'a_queue':
case 'a_requeue':
if (qa_opt('moderate_notify_admin')) if (qa_opt('moderate_notify_admin'))
qa_send_notification(null, qa_opt('feedback_email'), null, qa_lang('emails/moderate_subject'), qa_lang('emails/moderate_body'), array( qa_send_notification(null, qa_opt('feedback_email'), null,
'^p_handle' => isset($handle) ? $handle : qa_lang('main/anonymous'), ($event=='a_requeue') ? qa_lang('emails/remoderate_subject') : qa_lang('emails/moderate_subject'),
'^p_context' => $params['text'], ($event=='a_requeue') ? qa_lang('emails/remoderate_body') : qa_lang('emails/moderate_body'),
'^url' => qa_q_path($params['parentid'], $params['parent']['title'], true, 'A', $params['postid']), array(
)); '^p_handle' => isset($handle) ? $handle : (strlen($params['name']) ? $params['name'] :
(strlen(@$oldanswer['name']) ? $oldanswer['name'] : qa_lang('main/anonymous'))),
'^p_context' => $params['text'],
'^url' => qa_q_path($params['parentid'], $params['parent']['title'], true, 'A', $params['postid']),
'^a_url' => qa_path_absolute('admin/moderate'),
)
);
break; break;
case 'c_queue': case 'c_queue':
case 'c_requeue':
if (qa_opt('moderate_notify_admin')) if (qa_opt('moderate_notify_admin'))
qa_send_notification(null, qa_opt('feedback_email'), null, qa_lang('emails/moderate_subject'), qa_lang('emails/moderate_body'), array( qa_send_notification(null, qa_opt('feedback_email'), null,
'^p_handle' => isset($handle) ? $handle : qa_lang('main/anonymous'), ($event=='c_requeue') ? qa_lang('emails/remoderate_subject') : qa_lang('emails/moderate_subject'),
'^p_context' => $params['text'], ($event=='c_requeue') ? qa_lang('emails/remoderate_body') : qa_lang('emails/moderate_body'),
'^url' => qa_q_path($params['questionid'], $params['question']['title'], true, 'C', $params['postid']), array(
)); '^p_handle' => isset($handle) ? $handle : (strlen($params['name']) ? $params['name'] :
(strlen(@$oldcomment['name']) ? $oldcomment['name'] : // could also be after answer converted to comment
(strlen(@$oldanswer['name']) ? $oldanswer['name'] : qa_lang('main/anonymous')))),
'^p_context' => $params['text'],
'^url' => qa_q_path($params['questionid'], $params['question']['title'], true, 'C', $params['postid']),
'^a_url' => qa_path_absolute('admin/moderate'),
)
);
break; break;
...@@ -190,10 +213,12 @@ ...@@ -190,10 +213,12 @@
if ( ($notifycount>=0) && (($notifycount % qa_opt('flagging_notify_every'))==0) ) if ( ($notifycount>=0) && (($notifycount % qa_opt('flagging_notify_every'))==0) )
qa_send_notification(null, qa_opt('feedback_email'), null, qa_lang('emails/flagged_subject'), qa_lang('emails/flagged_body'), array( qa_send_notification(null, qa_opt('feedback_email'), null, qa_lang('emails/flagged_subject'), qa_lang('emails/flagged_body'), array(
'^p_handle' => isset($oldpost['handle']) ? $oldpost['handle'] : qa_lang('main/anonymous'), '^p_handle' => isset($oldpost['handle']) ? $oldpost['handle'] :
(strlen($oldpost['name']) ? $oldpost['name'] : qa_lang('main/anonymous')),
'^flags' => ($flagcount==1) ? qa_lang_html_sub('main/1_flag', '1', '1') : qa_lang_html_sub('main/x_flags', $flagcount), '^flags' => ($flagcount==1) ? qa_lang_html_sub('main/1_flag', '1', '1') : qa_lang_html_sub('main/x_flags', $flagcount),
'^p_context' => trim(@$oldpost['title']."\n\n".qa_viewer_text($oldpost['content'], $oldpost['format'])), '^p_context' => trim(@$oldpost['title']."\n\n".qa_viewer_text($oldpost['content'], $oldpost['format'])),
'^url' => qa_q_path($params['questionid'], $params['question']['title'], true, $oldpost['basetype'], $oldpost['postid']), '^url' => qa_q_path($params['questionid'], $params['question']['title'], true, $oldpost['basetype'], $oldpost['postid']),
'^a_url' => qa_path_absolute('admin/flagged'),
)); ));
break; break;
...@@ -213,6 +238,32 @@ ...@@ -213,6 +238,32 @@
)); ));
} }
break; break;
case 'u_register':
if (qa_opt('register_notify_admin'))
qa_send_notification(null, qa_opt('feedback_email'), null, qa_lang('emails/u_registered_subject'),
qa_opt('moderate_users') ? qa_lang('emails/u_to_approve_body') : qa_lang('emails/u_registered_body'), array(
'^u_handle' => $handle,
'^url' => qa_path_absolute('user/'.$handle),
'^a_url' => qa_path_absolute('admin/approve'),
));
break;
case 'u_level':
if ( ($params['level']>=QA_USER_LEVEL_APPROVED) && ($params['oldlevel']<QA_USER_LEVEL_APPROVED) )
qa_send_notification($params['userid'], null, $params['handle'], qa_lang('emails/u_approved_subject'), qa_lang('emails/u_approved_body'), array(
'^url' => qa_path_absolute('user/'.$params['handle']),
));
break;
case 'u_wall_post':
if ($userid!=$params['userid'])
qa_send_notification($params['userid'], null, $params['handle'], qa_lang('emails/wall_post_subject'), qa_lang('emails/wall_post_body'), array(
'^f_handle' => isset($handle) ? $handle : qa_lang('main/anonymous'),
'^post' => $params['text'],
'^url' => qa_path_absolute('user/'.$params['handle'], null, 'wall'),
));
break;
} }
} }
......
...@@ -34,10 +34,12 @@ ...@@ -34,10 +34,12 @@
function process_event($event, $userid, $handle, $cookieid, $params) function process_event($event, $userid, $handle, $cookieid, $params)
{ {
if (@$params['silent']) // don't create updates about silent edits, and possibly other silent events in future
return;
require_once QA_INCLUDE_DIR.'qa-db-events.php'; require_once QA_INCLUDE_DIR.'qa-db-events.php';
require_once QA_INCLUDE_DIR.'qa-app-events.php'; require_once QA_INCLUDE_DIR.'qa-app-events.php';
switch ($event) { switch ($event) {
case 'q_post': case 'q_post':
if (isset($params['parent'])) // question is following an answer if (isset($params['parent'])) // question is following an answer
...@@ -55,8 +57,6 @@ ...@@ -55,8 +57,6 @@
case 'c_post': case 'c_post':
qa_create_event_for_q_user($params['questionid'], $params['postid'], null, $userid, $params['parent']['userid']);
$keyuserids=array(); $keyuserids=array();
foreach ($params['thread'] as $comment) // previous comments in thread (but not author of parent again) foreach ($params['thread'] as $comment) // previous comments in thread (but not author of parent again)
...@@ -64,8 +64,27 @@ ...@@ -64,8 +64,27 @@
$keyuserids[$comment['userid']]=true; $keyuserids[$comment['userid']]=true;
foreach ($keyuserids as $keyuserid => $dummy) foreach ($keyuserids as $keyuserid => $dummy)
if ( ($keyuserid != $userid) && ($keyuserid != $params['parent']['userid']) ) if ($keyuserid != $userid)
qa_db_event_create_not_entity($keyuserid, $params['questionid'], $params['postid'], null, $userid); qa_db_event_create_not_entity($keyuserid, $params['questionid'], $params['postid'], QA_UPDATE_FOLLOWS, $userid);
switch ($params['parent']['basetype'])
{
case 'Q':
$updatetype=QA_UPDATE_C_FOR_Q;
break;
case 'A':
$updatetype=QA_UPDATE_C_FOR_A;
break;
default:
$updatetype=null;
break;
}
qa_create_event_for_q_user($params['questionid'], $params['postid'], $updatetype, $userid,
@$keyuserids[$params['parent']['userid']] ? null : $params['parent']['userid']);
// give precedence to 'your comment followed' rather than 'your Q/A commented' if both are true
break; break;
...@@ -97,11 +116,17 @@ ...@@ -97,11 +116,17 @@
break; break;
case 'q_hide':
if (isset($params['oldquestion']['userid']))
qa_db_event_create_not_entity($params['oldquestion']['userid'], $params['postid'], $params['postid'], QA_UPDATE_VISIBLE, $userid);
break;
case 'q_reshow': case 'q_reshow':
qa_create_event_for_q_user($params['postid'], $params['postid'], QA_UPDATE_VISIBLE, $userid, $params['oldquestion']['userid']); qa_create_event_for_q_user($params['postid'], $params['postid'], QA_UPDATE_VISIBLE, $userid, $params['oldquestion']['userid']);
break; break;
case 'q_move': case 'q_move':
qa_create_event_for_q_user($params['postid'], $params['postid'], QA_UPDATE_CATEGORY, $userid, $params['oldquestion']['userid']); qa_create_event_for_q_user($params['postid'], $params['postid'], QA_UPDATE_CATEGORY, $userid, $params['oldquestion']['userid']);
qa_create_event_for_category($params['categoryid'], $params['postid'], QA_UPDATE_CATEGORY, $userid); qa_create_event_for_category($params['categoryid'], $params['postid'], QA_UPDATE_CATEGORY, $userid);
...@@ -114,6 +139,12 @@ ...@@ -114,6 +139,12 @@
break; break;
case 'a_hide':
if (isset($params['oldanswer']['userid']))
qa_db_event_create_not_entity($params['oldanswer']['userid'], $params['parentid'], $params['postid'], QA_UPDATE_VISIBLE, $userid);
break;
case 'a_reshow': case 'a_reshow':
qa_create_event_for_q_user($params['parentid'], $params['postid'], QA_UPDATE_VISIBLE, $userid, $params['oldanswer']['userid']); qa_create_event_for_q_user($params['parentid'], $params['postid'], QA_UPDATE_VISIBLE, $userid, $params['oldanswer']['userid']);
break; break;
...@@ -133,6 +164,12 @@ ...@@ -133,6 +164,12 @@
break; break;
case 'c_hide':
if (isset($params['oldcomment']['userid']))
qa_db_event_create_not_entity($params['oldcomment']['userid'], $params['questionid'], $params['postid'], QA_UPDATE_VISIBLE, $userid);
break;
case 'c_reshow': case 'c_reshow':
qa_create_event_for_q_user($params['questionid'], $params['postid'], QA_UPDATE_VISIBLE, $userid, $params['oldcomment']['userid']); qa_create_event_for_q_user($params['questionid'], $params['postid'], QA_UPDATE_VISIBLE, $userid, $params['oldcomment']['userid']);
break; break;
......
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
{ {
$countslugs=@count($categoryslugs); $countslugs=@count($categoryslugs);
@list($questions1, $questions2, $questions3, $questions4, $categories, $categoryid)=qa_db_select_with_pending( list($questions1, $questions2, $questions3, $questions4, $categories, $categoryid)=qa_db_select_with_pending(
$questionselectspec1, $questionselectspec1,
$questionselectspec2, $questionselectspec2,
$questionselectspec3, $questionselectspec3,
...@@ -292,8 +292,8 @@ ...@@ -292,8 +292,8 @@
$lines[]='<rss version="2.0">'; $lines[]='<rss version="2.0">';
$lines[]='<channel>'; $lines[]='<channel>';
$lines[]='<title>'.qa_html($sitetitle.' - '.$title).'</title>'; $lines[]='<title>'.qa_xml($sitetitle.' - '.$title).'</title>';
$lines[]='<link>'.qa_path_html($linkrequest, $linkparams, $siteurl).'</link>'; $lines[]='<link>'.qa_xml(qa_path($linkrequest, $linkparams, $siteurl)).'</link>';
$lines[]='<description>Powered by Question2Answer</description>'; $lines[]='<description>Powered by Question2Answer</description>';
foreach ($questions as $question) { foreach ($questions as $question) {
...@@ -320,7 +320,7 @@ ...@@ -320,7 +320,7 @@
if ($feedtype=='search') { if ($feedtype=='search') {
$titleprefix=''; $titleprefix='';
$urlhtml=qa_html($question['url']); $urlxml=qa_xml($question['url']);
} else { } else {
switch (@$question['obasetype'].'-'.@$question['oupdatetype']) { switch (@$question['obasetype'].'-'.@$question['oupdatetype']) {
...@@ -386,7 +386,7 @@ ...@@ -386,7 +386,7 @@
$titleprefix=isset($langstring) ? qa_lang($langstring) : ''; $titleprefix=isset($langstring) ? qa_lang($langstring) : '';
$urlhtml=qa_q_path_html($question['postid'], $question['title'], true, @$question['obasetype'], @$question['opostid']) ; $urlxml=qa_xml(qa_q_path($question['postid'], $question['title'], true, @$question['obasetype'], @$question['opostid']));
} }
if (isset($blockwordspreg)) if (isset($blockwordspreg))
...@@ -395,19 +395,19 @@ ...@@ -395,19 +395,19 @@
// Build the inner XML structure for each item // Build the inner XML structure for each item
$lines[]='<item>'; $lines[]='<item>';
$lines[]='<title>'.qa_html($titleprefix.$question['title']).'</title>'; $lines[]='<title>'.qa_xml($titleprefix.$question['title']).'</title>';
$lines[]='<link>'.$urlhtml.'</link>'; $lines[]='<link>'.$urlxml.'</link>';
if (isset($htmlcontent)) if (isset($htmlcontent))
$lines[]='<description>'.qa_html($htmlcontent).'</description>'; // qa_html() a second time to put HTML code inside XML wrapper $lines[]='<description>'.qa_xml($htmlcontent).'</description>';
if (isset($question['categoryname'])) if (isset($question['categoryname']))
$lines[]='<category>'.qa_html($question['categoryname']).'</category>'; $lines[]='<category>'.qa_xml($question['categoryname']).'</category>';
$lines[]='<guid isPermaLink="true">'.$urlhtml.'</guid>'; $lines[]='<guid isPermaLink="true">'.$urlxml.'</guid>';
if (isset($time)) if (isset($time))
$lines[]='<pubDate>'.qa_html(gmdate('r', $time)).'</pubDate>'; $lines[]='<pubDate>'.qa_xml(gmdate('r', $time)).'</pubDate>';
$lines[]='</item>'; $lines[]='</item>';
} }
......
...@@ -63,13 +63,13 @@ ...@@ -63,13 +63,13 @@
} else { } else {
require_once QA_INCLUDE_DIR.'qa-app-options.php'; require_once QA_INCLUDE_DIR.'qa-app-options.php';
require_once QA_INCLUDE_DIR.'qa-db-blobs.php'; require_once QA_INCLUDE_DIR.'qa-app-blobs.php';
require_once QA_INCLUDE_DIR.'qa-util-image.php'; require_once QA_INCLUDE_DIR.'qa-util-image.php';
// Otherwise retrieve the raw image and scale as appropriate // Otherwise retrieve the raw image and scale as appropriate
$blob=qa_db_blob_read($blobid); $blob=qa_read_blob($blobid);
if (isset($blob)) { if (isset($blob)) {
if ($size>0) if ($size>0)
......
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
$relativedepth=count($requestparts); $relativedepth=count($requestparts);
// Workaround for fact that Apache unescapes characters while rewriting, based on assumption that $_GET['qa-rewrite'] has // Workaround for fact that Apache unescapes characters while rewriting, based on assumption that $_GET['qa-rewrite'] has
// right path depth, which is true do long as there are only escaped characters in the last part of the path // right path depth, which is true so long as there are only escaped characters in the last part of the path
if (!empty($_SERVER['REQUEST_URI'])) { if (!empty($_SERVER['REQUEST_URI'])) {
$origpath=$_SERVER['REQUEST_URI']; $origpath=$_SERVER['REQUEST_URI'];
$_GET=array(); $_GET=array();
...@@ -73,8 +73,10 @@ ...@@ -73,8 +73,10 @@
$params=explode('&', substr($origpath, $questionpos+1)); $params=explode('&', substr($origpath, $questionpos+1));
foreach ($params as $param) foreach ($params as $param)
if (preg_match('/^([^\=]*)(\=(.*))?$/', $param, $matches)) if (preg_match('/^([^\=]*)(\=(.*))?$/', $param, $matches)) {
$_GET[urldecode($matches[1])]=qa_string_to_gpc(urldecode(@$matches[3])); $argument=strtr(urldecode($matches[1]), '.', '_'); // simulate PHP's $_GET behavior
$_GET[$argument]=qa_string_to_gpc(urldecode(@$matches[3]));
}
$origpath=substr($origpath, 0, $questionpos); $origpath=substr($origpath, 0, $questionpos);
} }
......
...@@ -97,11 +97,9 @@ ...@@ -97,11 +97,9 @@
global $pass_failure_from_install; global $pass_failure_from_install;
if (@$pass_failure_from_install) if (@$pass_failure_from_install)
$errorhtml.="Question2Answer was unable to perform the installation query below. Please check the user in the config file has CREATE and ALTER permissions:\n\n"; $errorhtml.="Question2Answer was unable to perform the installation query below. Please check the user in the config file has CREATE and ALTER permissions:\n\n".qa_html($pass_failure_query."\n\nError ".$pass_failure_errno.": ".$pass_failure_error."\n\n");
else else
$errorhtml.="Question2Answer query failed:\n\n"; $errorhtml.="A Question2Answer database query failed when generating this page.\n\nA full description of the failure is available in the web server's error log file.";
$errorhtml.=qa_html($pass_failure_query."\n\nError ".$pass_failure_errno.": ".$pass_failure_error."\n\n");
break; break;
} }
......
...@@ -44,6 +44,15 @@ ...@@ -44,6 +44,15 @@
'moderate_title' => 'Moderate', 'moderate_title' => 'Moderate',
'basic_editor' => 'Basic Editor', 'basic_editor' => 'Basic Editor',
'before_main_menu' => 'Before tabs at top', 'before_main_menu' => 'Before tabs at top',
'blobs_directory_error' => 'The directory ^ defined as QA_BLOBS_DIRECTORY is not writable by the web server.',
'blobs_move_complete' => 'Migration of uploaded images and documents completed.',
'blobs_move_moved' => 'Migration ^1 of ^2 uploaded images and documents',
'blobs_stop' => 'Stop migrating',
'blobs_to_db' => 'Blobs to database',
'blobs_to_db_note' => '- migrate all uploaded images and documents from disk files to the database',
'blobs_to_disk' => 'Blobs to disk',
'blobs_to_disk_note' => '- migrate all uploaded images and documents from the database to disk files',
'block_button' => 'block',
'block_ips_note' => 'Use a hyphen for ranges or * to match any number. Examples: 192.168.0.4 , 192.168.0.0-192.168.0.31 , 192.168.0.*', 'block_ips_note' => 'Use a hyphen for ranges or * to match any number. Examples: 192.168.0.4 , 192.168.0.0-192.168.0.31 , 192.168.0.*',
'block_words_note' => 'Use a * to match any letters. Examples: doh (will only match exact word doh) , doh* (will match doh or dohno) , do*h (will match doh, dooh, dough).', 'block_words_note' => 'Use a * to match any letters. Examples: doh (will only match exact word doh) , doh* (will match doh or dohno) , do*h (will match doh, dooh, dough).',
'cancel_mailing_button' => 'Cancel Mailing', 'cancel_mailing_button' => 'Cancel Mailing',
...@@ -104,6 +113,7 @@ ...@@ -104,6 +113,7 @@
'field_type' => 'Content type:', 'field_type' => 'Content type:',
'first' => 'First', 'first' => 'First',
'flagged_title' => 'Flagged', 'flagged_title' => 'Flagged',
'form_security_expired' => 'Form security code expired - please try again',
'from_anon' => 'From anonymous:', 'from_anon' => 'From anonymous:',
'from_users' => 'From users:', 'from_users' => 'From users:',
'general_title' => 'General', 'general_title' => 'General',
...@@ -112,7 +122,6 @@ ...@@ -112,7 +122,6 @@
'hidden_questions_deleted' => 'Deleted ^1 of ^2 hidden questions without dependents...', 'hidden_questions_deleted' => 'Deleted ^1 of ^2 hidden questions without dependents...',
'hotness_factors' => 'Relative importance for question hotness:', 'hotness_factors' => 'Relative importance for question hotness:',
'hidden_title' => 'Hidden', 'hidden_title' => 'Hidden',
'installed_plugins' => 'Installed plugins:',
'ip_address_pages' => 'IP address pages', 'ip_address_pages' => 'IP address pages',
'layout_title' => 'Layout', 'layout_title' => 'Layout',
'link_name' => 'Text of link:', 'link_name' => 'Text of link:',
...@@ -126,6 +135,7 @@ ...@@ -126,6 +135,7 @@
'mailing_unsubscribe' => 'An unsubscribe link will be added at the bottom of every message.', 'mailing_unsubscribe' => 'An unsubscribe link will be added at the bottom of every message.',
'maintenance_admin_only' => 'Your site is in ^1maintenance^2 and is currently inaccessible to regular users.', 'maintenance_admin_only' => 'Your site is in ^1maintenance^2 and is currently inaccessible to regular users.',
'maximum_x' => ' (max ^)', 'maximum_x' => ' (max ^)',
'approve_users_title' => 'Approve users',
'module_x_database_init' => 'The ^1 ^2 module requires some ^3database initialization^4.', 'module_x_database_init' => 'The ^1 ^2 module requires some ^3database initialization^4.',
'most_flagged_title' => 'Flagged content', 'most_flagged_title' => 'Flagged content',
'mysql_version' => 'MySQL version:', 'mysql_version' => 'MySQL version:',
...@@ -139,8 +149,8 @@ ...@@ -139,8 +149,8 @@
'no_image_gd' => 'The installed version of PHP was compiled without GD image support, so users cannot upload their avatars directly.', 'no_image_gd' => 'The installed version of PHP was compiled without GD image support, so users cannot upload their avatars directly.',
'no_link' => 'No link', 'no_link' => 'No link',
'no_multibyte' => 'The installed version of PHP was compiled without multibyte string support. Searching will be less effective for non-Roman characters.', 'no_multibyte' => 'The installed version of PHP was compiled without multibyte string support. Searching will be less effective for non-Roman characters.',
'no_plugin_options' => 'None of your installed plugins have options to display.',
'no_privileges' => 'Only administrators may access this page.', 'no_privileges' => 'Only administrators may access this page.',
'no_unapproved_found' => 'No users waiting for approval',
'not_logged_in' => 'Please ^1log in^2 as the administrator to access this page.', 'not_logged_in' => 'Please ^1log in^2 as the administrator to access this page.',
'opposite_main_menu' => 'Far end of tabs at top', 'opposite_main_menu' => 'Far end of tabs at top',
'options_reset' => 'Options reset', 'options_reset' => 'Options reset',
...@@ -170,7 +180,7 @@ ...@@ -170,7 +180,7 @@
'points' => 'points', 'points' => 'points',
'position' => 'Position:', 'position' => 'Position:',
'posting_title' => 'Posting', 'posting_title' => 'Posting',
'profile_fields' => 'Extra fields on user profile:', 'profile_fields' => 'Extra fields for users:',
'q2a_build_date' => 'Build date:', 'q2a_build_date' => 'Build date:',
'q2a_db_size' => 'Database size:', 'q2a_db_size' => 'Database size:',
'q2a_db_version' => 'Q2A database version:', 'q2a_db_version' => 'Q2A database version:',
...@@ -218,6 +228,7 @@ ...@@ -218,6 +228,7 @@
'save_recalc_button' => 'Save and Recalculate', 'save_recalc_button' => 'Save and Recalculate',
'send_test_button' => 'Send Test to Me', 'send_test_button' => 'Send Test to Me',
'show_defaults_button' => 'Show Defaults', 'show_defaults_button' => 'Show Defaults',
'show_on_register_form' => 'Show field on user registration form',
'slug_bad_chars' => 'The slug may not contain these characters: ^', 'slug_bad_chars' => 'The slug may not contain these characters: ^',
'slug_reserved' => 'This slug is reserved for use by another page', 'slug_reserved' => 'This slug is reserved for use by another page',
'spam_title' => 'Spam', 'spam_title' => 'Spam',
......
...@@ -43,10 +43,10 @@ ...@@ -43,10 +43,10 @@
'feedback_body' => "Comments:\n^message\n\nName:\n^name\n\nEmail:\n^email\n\nPrevious page:\n^previous\n\nUser:\n^url\n\nIP address:\n^ip\n\nBrowser:\n^browser", 'feedback_body' => "Comments:\n^message\n\nName:\n^name\n\nEmail:\n^email\n\nPrevious page:\n^previous\n\nUser:\n^url\n\nIP address:\n^ip\n\nBrowser:\n^browser",
'feedback_subject' => '^ feedback', 'feedback_subject' => '^ feedback',
'flagged_body' => "A post by ^p_handle has received ^flags:\n\n^open^p_context^close\n\nClick below to see the post:\n\n^url\n\nThank you,\n\n^site_title", 'flagged_body' => "A post by ^p_handle has received ^flags:\n\n^open^p_context^close\n\nClick below to see the post:\n\n^url\n\n\nClick below to review all flagged posts:\n\n^a_url\n\n\nThank you,\n\n^site_title",
'flagged_subject' => '^site_title has a flagged post', 'flagged_subject' => '^site_title has a flagged post',
'moderate_body' => "A post by ^p_handle requires your approval:\n\n^open^p_context^close\n\nClick below to approve or reject the post:\n\n^url\n\nThank you,\n\n^site_title", 'moderate_body' => "A post by ^p_handle requires your approval:\n\n^open^p_context^close\n\nClick below to approve or reject the post:\n\n^url\n\n\nClick below to review all queued posts:\n\n^a_url\n\n\nThank you,\n\n^site_title",
'moderate_subject' => '^site_title moderation', 'moderate_subject' => '^site_title moderation',
'new_password_body' => "Your new password for ^site_title is below.\n\nPassword: ^password\n\nIt is recommended to change this password immediately after logging in.\n\nThank you,\n^site_title\n^url", 'new_password_body' => "Your new password for ^site_title is below.\n\nPassword: ^password\n\nIt is recommended to change this password immediately after logging in.\n\nThank you,\n^site_title\n^url",
...@@ -65,11 +65,24 @@ ...@@ -65,11 +65,24 @@
'q_posted_body' => "A new question has been asked by ^q_handle:\n\n^open^q_title\n\n^q_content^close\n\nClick below to see the question:\n\n^url\n\nThank you,\n\n^site_title", 'q_posted_body' => "A new question has been asked by ^q_handle:\n\n^open^q_title\n\n^q_content^close\n\nClick below to see the question:\n\n^url\n\nThank you,\n\n^site_title",
'q_posted_subject' => '^site_title has a new question', 'q_posted_subject' => '^site_title has a new question',
'remoderate_body' => "An edited post by ^p_handle requires your reapproval:\n\n^open^p_context^close\n\nClick below to approve or hide the edited post:\n\n^url\n\n\nClick below to review all queued posts:\n\n^a_url\n\n\nThank you,\n\n^site_title",
'remoderate_subject' => '^site_title moderation',
'reset_body' => "Please click below to reset your password for ^site_title.\n\n^url\n\nAlternatively, enter the code below into the field provided.\n\nCode: ^code\n\nIf you did not ask to reset your password, please ignore this message.\n\nThank you,\n^site_title", 'reset_body' => "Please click below to reset your password for ^site_title.\n\n^url\n\nAlternatively, enter the code below into the field provided.\n\nCode: ^code\n\nIf you did not ask to reset your password, please ignore this message.\n\nThank you,\n^site_title",
'reset_subject' => '^site_title - Reset Forgotten Password', 'reset_subject' => '^site_title - Reset Forgotten Password',
'to_handle_prefix' => "^,\n\n", 'to_handle_prefix' => "^,\n\n",
'u_registered_body' => "A new user has registered as ^u_handle.\n\nClick below to view the user profile:\n\n^url\n\nThank you,\n\n^site_title",
'u_to_approve_body' => "A new user has registered as ^u_handle.\n\nClick below to approve the user:\n\n^url\n\nClick below to review all users waiting for approval:\n\n^a_url\n\nThank you,\n\n^site_title",
'u_registered_subject' => '^site_title has a new registered user',
'u_approved_body' => "You can see your new user profile here:\n\n^url\n\nThank you,\n\n^site_title",
'u_approved_subject' => 'Your ^site_title user has been approved',
'wall_post_subject' => 'Post on your ^site_title wall',
'wall_post_body' => "^f_handle has posted on your user wall at ^site_title:\n\n^open^post^close\n\nYou may respond to the post here:\n\n^url\n\nThank you,\n\n^site_title",
'welcome_body' => "Thank you for registering for ^site_title.\n\n^custom^confirmYour login details are as follows:\n\nEmail: ^email\nPassword: ^password\n\nPlease keep this information safe for future reference.\n\nThank you,\n\n^site_title\n^url", 'welcome_body' => "Thank you for registering for ^site_title.\n\n^custom^confirmYour login details are as follows:\n\nEmail: ^email\nPassword: ^password\n\nPlease keep this information safe for future reference.\n\nThank you,\n\n^site_title\n^url",
'welcome_confirm' => "Please click below to confirm your email address.\n\n^url\n\n", 'welcome_confirm' => "Please click below to confirm your email address.\n\n^url\n\n",
......
...@@ -178,11 +178,14 @@ ...@@ -178,11 +178,14 @@
'unupvoteda_qs_in_x' => 'Questions without an upvoted answer in ^', 'unupvoteda_qs_in_x' => 'Questions without an upvoted answer in ^',
'unupvoteda_qs_title' => 'Recent questions without an upvoted answer', 'unupvoteda_qs_title' => 'Recent questions without an upvoted answer',
'upload_limit' => 'Too many uploads - please try again in an hour', 'upload_limit' => 'Too many uploads - please try again in an hour',
'view_q_must_be_approved' => 'Your account must be approved to view question pages.',
'view_q_must_confirm' => 'Please ^5confirm your email address^6 to view question pages.', 'view_q_must_confirm' => 'Please ^5confirm your email address^6 to view question pages.',
'view_q_must_login' => 'Please ^1log in^2 or ^3register^4 to view question pages.', 'view_q_must_login' => 'Please ^1log in^2 or ^3register^4 to view question pages.',
'viewed_qs_in_x' => 'Most viewed questions in ^', 'viewed_qs_in_x' => 'Most viewed questions in ^',
'viewed_qs_title' => 'Most viewed questions', 'viewed_qs_title' => 'Most viewed questions',
'vote_disabled_approve' => 'You account must be approved before you can vote',
'vote_disabled_down' => 'Voting down is only available to some users', 'vote_disabled_down' => 'Voting down is only available to some users',
'vote_disabled_down_approve' => 'Your account must be approved before you can vote down',
'vote_disabled_hidden_a' => 'You cannot vote on hidden answers', 'vote_disabled_hidden_a' => 'You cannot vote on hidden answers',
'vote_disabled_hidden_q' => 'You cannot vote on hidden questions', 'vote_disabled_hidden_q' => 'You cannot vote on hidden questions',
'vote_disabled_level' => 'Voting is only available to some users', 'vote_disabled_level' => 'Voting is only available to some users',
...@@ -200,6 +203,7 @@ ...@@ -200,6 +203,7 @@
'voted_qs_in_x' => 'Highest voted questions in ^', 'voted_qs_in_x' => 'Highest voted questions in ^',
'voted_qs_title' => 'Highest voted questions', 'voted_qs_title' => 'Highest voted questions',
'voted_up_popup' => 'You have voted this up - click to remove vote', 'voted_up_popup' => 'You have voted this up - click to remove vote',
'written' => '', // blank in English - placeholder for other languages
'x_ago' => '^ ago', 'x_ago' => '^ ago',
'x_answers' => '^ answers', 'x_answers' => '^ answers',
'x_comments' => '^ comments', 'x_comments' => '^ comments',
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
return array( return array(
'block_ip_button' => 'Block IP address', 'block_ip_button' => 'Block IP address',
'browse_categories' => 'Browse categories', 'browse_categories' => 'Browse categories',
'captcha_approve_fix' => 'This verification will stop appearing once your account is approved.',
'captcha_confirm_fix' => 'To avoid this verification in future, please ^5confirm your email address^6.', 'captcha_confirm_fix' => 'To avoid this verification in future, please ^5confirm your email address^6.',
'captcha_error' => 'Please complete the anti-spam verification', 'captcha_error' => 'Please complete the anti-spam verification',
'captcha_label' => 'Anti-spam verification:', 'captcha_label' => 'Anti-spam verification:',
...@@ -53,6 +54,8 @@ ...@@ -53,6 +54,8 @@
'feedback_name' => 'Your name: (optional)', 'feedback_name' => 'Your name: (optional)',
'feedback_sent' => 'Your message below was sent - thank you.', 'feedback_sent' => 'Your message below was sent - thank you.',
'feedback_title' => 'Send feedback', 'feedback_title' => 'Send feedback',
'form_security_again' => 'Please click again to confirm',
'form_security_reload' => 'Please reload the page then try again',
'hide_all_ip_button' => 'Hide all posts from this IP', 'hide_all_ip_button' => 'Hide all posts from this IP',
'host_name' => 'Host name:', 'host_name' => 'Host name:',
'matches_blocked_ips' => 'Matches blocked IP addresses:', 'matches_blocked_ips' => 'Matches blocked IP addresses:',
...@@ -61,15 +64,16 @@ ...@@ -61,15 +64,16 @@
'message_for_x' => 'Your message for ^:', 'message_for_x' => 'Your message for ^:',
'message_limit' => 'Too many private messages sent - please try again in an hour', 'message_limit' => 'Too many private messages sent - please try again in an hour',
'message_must_login' => 'Please ^1log in^2 or ^3register^4 to send private messages.', 'message_must_login' => 'Please ^1log in^2 or ^3register^4 to send private messages.',
'message_received_x_ago' => 'Received ^ ago:',
'message_recent_history' => 'Recent correspondence with ^', 'message_recent_history' => 'Recent correspondence with ^',
'message_sent_x_ago' => 'Sent ^ ago:',
'message_sent' => 'Your private message below was sent', 'message_sent' => 'Your private message below was sent',
'my_favorites_title' => 'My favorites', 'my_favorites_title' => 'My favorites',
'nav_all_my_updates' => 'All my updates', 'nav_all_my_updates' => 'All my updates',
'nav_my_content' => 'My content', 'nav_my_content' => 'My content',
'nav_my_details' => 'My details', 'nav_my_details' => 'My details',
'nav_my_favorites' => 'My favorites', 'nav_my_favorites' => 'My favorites',
'nav_user_activity' => 'Recent activity',
'nav_user_as' => 'All answers',
'nav_user_qs' => 'All questions',
'no_activity_from_x' => 'No activity from ^', 'no_activity_from_x' => 'No activity from ^',
'no_favorite_categories' => 'No favorite categories', 'no_favorite_categories' => 'No favorite categories',
'no_favorite_qs' => 'No favorite questions', 'no_favorite_qs' => 'No favorite questions',
...@@ -87,6 +91,26 @@ ...@@ -87,6 +91,26 @@
'suggest_favorites_add' => 'To add a question or other item to your favorites, click the ^ at the top of its page.', 'suggest_favorites_add' => 'To add a question or other item to your favorites, click the ^ at the top of its page.',
'suggest_update_favorites' => 'For more updates, add items to ^1your favorites^2.', 'suggest_update_favorites' => 'For more updates, add items to ^1your favorites^2.',
'unblock_ip_button' => 'Unblock IP address', 'unblock_ip_button' => 'Unblock IP address',
'your_a_commented' => 'your answer commented',
'your_a_edited' => 'your answer edited',
'your_a_hidden' => 'your answer hidden',
'your_a_questioned' => 'asked on your answer',
'your_a_reshown' => 'your answer reshown',
'your_a_selected' => 'your answer selected',
'your_c_edited' => 'your comment edited',
'your_c_followed' => 'your comment followed',
'your_c_hidden' => 'your comment hidden',
'your_c_moved' => 'your comment moved',
'your_c_reshown' => 'your comment reshown',
'your_q_answered' => 'your question answered',
'your_q_closed' => 'your question closed',
'your_q_commented' => 'your question commented',
'your_q_edited' => 'your question edited',
'your_q_hidden' => 'your question hidden',
'your_q_recategorized' => 'your question recategorized',
'your_q_reopened' => 'your question reopened',
'your_q_reshown' => 'your question reshown',
'your_q_retagged' => 'your question retagged',
); );
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
*/ */
return array( return array(
'allow_anon_name' => 'Request a name for anonymous posts:',
'allow_change_usernames' => 'Allow users with posts to change their username:', 'allow_change_usernames' => 'Allow users with posts to change their username:',
'allow_close_questions' => 'Allow questions to be manually closed:', 'allow_close_questions' => 'Allow questions to be manually closed:',
'allow_login_email_only' => 'Only log in by email address (not username):', 'allow_login_email_only' => 'Only log in by email address (not username):',
...@@ -32,11 +33,14 @@ ...@@ -32,11 +33,14 @@
'allow_no_category' => 'Allow questions with no category', 'allow_no_category' => 'Allow questions with no category',
'allow_no_sub_category' => 'Allow questions with a category but no sub-category', 'allow_no_sub_category' => 'Allow questions with a category but no sub-category',
'allow_private_messages' => 'Enable private messaging between users:', 'allow_private_messages' => 'Enable private messaging between users:',
'allow_user_walls' => 'Enable wall posts on user profiles:',
'allow_self_answer' => 'Allow users to answer their own question:', 'allow_self_answer' => 'Allow users to answer their own question:',
'allow_view_q_bots' => 'Allow search engines to view question pages', 'allow_view_q_bots' => 'Allow search engines to view question pages',
'approve_user_required' => 'All new users must be approved:',
'avatar_allow_gravatar' => 'Allow ^1Gravatar^2 avatars:', 'avatar_allow_gravatar' => 'Allow ^1Gravatar^2 avatars:',
'avatar_allow_upload' => 'Allow users to upload avatars:', 'avatar_allow_upload' => 'Allow users to upload avatars:',
'avatar_default_show' => 'Default avatar:', 'avatar_default_show' => 'Default avatar:',
'avatar_message_list_size' => 'Avatar size on message lists:',
'avatar_profile_size' => 'Avatar size on user profile page:', 'avatar_profile_size' => 'Avatar size on user profile page:',
'avatar_q_list_size' => 'Avatar size on question lists:', 'avatar_q_list_size' => 'Avatar size on question lists:',
'avatar_q_page_a_size' => 'Avatar size on answers:', 'avatar_q_page_a_size' => 'Avatar size on answers:',
...@@ -51,13 +55,14 @@ ...@@ -51,13 +55,14 @@
'captcha_on_feedback' => 'Use captcha on feedback form:', 'captcha_on_feedback' => 'Use captcha on feedback form:',
'captcha_on_register' => 'Use captcha for user registration:', 'captcha_on_register' => 'Use captcha for user registration:',
'captcha_on_reset_password' => 'Use captcha on reset password form:', 'captcha_on_reset_password' => 'Use captcha on reset password form:',
'captcha_on_unapproved' => 'Use captcha if user not yet approved:',
'captcha_on_unconfirmed' => 'Use captcha if email not confirmed:', 'captcha_on_unconfirmed' => 'Use captcha if email not confirmed:',
'columns_tags' => 'Columns on Tags page:', 'columns_tags' => 'Columns on Tags page:',
'columns_users' => 'Columns on Users page:', 'columns_users' => 'Columns on Users page:',
'comment_on_as' => 'Allow comments on answers:', 'comment_on_as' => 'Allow comments on answers:',
'comment_on_qs' => 'Allow comments on questions:', 'comment_on_qs' => 'Allow comments on questions:',
'confirm_user_emails' => 'Request confirmation of user emails:', 'confirm_user_emails' => 'Request confirmation of user emails:',
'confirm_user_required' => 'New users must complete confirmation:', 'confirm_user_required' => 'All new users must confirm their email:',
'custom_home_content' => 'Home page content - HTML allowed:', 'custom_home_content' => 'Home page content - HTML allowed:',
'custom_home_heading' => 'Home page heading:', 'custom_home_heading' => 'Home page heading:',
'default_privacy' => 'Privacy: Your email address will not be shared or sold to third parties.', 'default_privacy' => 'Privacy: Your email address will not be shared or sold to third parties.',
...@@ -124,7 +129,7 @@ ...@@ -124,7 +129,7 @@
'max_rate_ip_cs' => 'Rate limit for posting comments:', 'max_rate_ip_cs' => 'Rate limit for posting comments:',
'max_rate_ip_flags' => 'Rate limit for flagging posts:', 'max_rate_ip_flags' => 'Rate limit for flagging posts:',
'max_rate_ip_logins' => 'Rate limit for logging in:', 'max_rate_ip_logins' => 'Rate limit for logging in:',
'max_rate_ip_messages' => 'Rate limit for sending private messages:', 'max_rate_ip_messages' => 'Rate limit for private and wall messages:',
'max_rate_ip_qs' => 'Rate limit for asking questions:', 'max_rate_ip_qs' => 'Rate limit for asking questions:',
'max_rate_ip_registers' => 'Rate limit for user registrations:', 'max_rate_ip_registers' => 'Rate limit for user registrations:',
'max_rate_ip_uploads' => 'Rate limit for uploading files:', 'max_rate_ip_uploads' => 'Rate limit for uploading files:',
...@@ -143,9 +148,13 @@ ...@@ -143,9 +148,13 @@
'min_num_q_tags' => 'Minimum number of tags:', 'min_num_q_tags' => 'Minimum number of tags:',
'moderate_anon_post' => 'Use moderation for anonymous posts:', 'moderate_anon_post' => 'Use moderation for anonymous posts:',
'moderate_by_points' => 'Use moderation for users with few points:', 'moderate_by_points' => 'Use moderation for users with few points:',
'moderate_edited_again' => 'Re-moderate posts after editing:',
'moderate_notify_admin' => 'Email me when a post needs moderation:', 'moderate_notify_admin' => 'Email me when a post needs moderation:',
'moderate_points_limit' => 'Use moderation for users with less than:', 'moderate_points_limit' => 'Use moderation for users with less than:',
'moderate_unapproved' => 'Use moderation if user not yet approved:',
'moderate_unconfirmed' => 'Use moderation if email not confirmed:', 'moderate_unconfirmed' => 'Use moderation if email not confirmed:',
'moderate_update_time' => 'Time to show on moderated posts:',
'moderate_users' => 'Enable moderation (approval) of users:',
'neat_urls' => 'URL structure:', 'neat_urls' => 'URL structure:',
'notify_admin_q_post' => 'Email this address when a question is posted', 'notify_admin_q_post' => 'Email this address when a question is posted',
'notify_users_default' => 'Check email notification box by default:', 'notify_users_default' => 'Check email notification box by default:',
...@@ -162,11 +171,13 @@ ...@@ -162,11 +171,13 @@
'page_size_tag_qs' => 'Questions on each tag page:', 'page_size_tag_qs' => 'Questions on each tag page:',
'page_size_tags' => 'Length of Tags page:', 'page_size_tags' => 'Length of Tags page:',
'page_size_una_qs' => 'Length of Unanswered page:', 'page_size_una_qs' => 'Length of Unanswered page:',
'page_size_user_posts' => 'Posts on each user page:',
'page_size_users' => 'Length of Users page:', 'page_size_users' => 'Length of Users page:',
'pages_prev_next' => 'Links to previous/next pages:', 'pages_prev_next' => 'Links to previous/next pages:',
'permit_admins' => 'Administrators', 'permit_admins' => 'Administrators',
'permit_all' => 'Anybody', 'permit_all' => 'Anybody',
'permit_approve_users' => 'Approving registered users:',
'permit_approved' => 'Approved users only',
'permit_approved_points' => 'Approved users with enough points',
'permit_block' => 'Blocking or unblocking user or IPs:', 'permit_block' => 'Blocking or unblocking user or IPs:',
'permit_confirmed' => 'Registered users with email confirmed', 'permit_confirmed' => 'Registered users with email confirmed',
'permit_create_admins' => 'Creating administrators:', 'permit_create_admins' => 'Creating administrators:',
...@@ -213,6 +224,7 @@ ...@@ -213,6 +224,7 @@
'points_vote_up_q' => 'Voting up a question:', 'points_vote_up_q' => 'Voting up a question:',
'q_urls_remove_accents' => 'Remove accents from question URLs:', 'q_urls_remove_accents' => 'Remove accents from question URLs:',
'q_urls_title_length' => 'Question title length in URLs:', 'q_urls_title_length' => 'Question title length in URLs:',
'register_notify_admin' => 'Email me when a new user registers:',
'search_module' => 'Use search module:', 'search_module' => 'Use search module:',
'show_a_form_immediate' => 'Show answer form immediately:', 'show_a_form_immediate' => 'Show answer form immediately:',
'show_always' => 'Always', 'show_always' => 'Always',
...@@ -242,6 +254,7 @@ ...@@ -242,6 +254,7 @@
'show_user_points' => 'Show points next to usernames:', 'show_user_points' => 'Show points next to usernames:',
'show_user_titles' => 'Show titles next to usernames:', 'show_user_titles' => 'Show titles next to usernames:',
'show_view_counts' => 'Show view count in question lists:', 'show_view_counts' => 'Show view count in question lists:',
'show_view_count_q_page' => 'Show view count on question pages:',
'show_when_created' => 'Show age of user posts:', 'show_when_created' => 'Show age of user posts:',
'site_language' => 'Site language:', 'site_language' => 'Site language:',
'site_maintenance' => 'Take site down for temporary maintenance', 'site_maintenance' => 'Take site down for temporary maintenance',
...@@ -263,6 +276,8 @@ ...@@ -263,6 +276,8 @@
'suspend_register_users' => 'Temporarily suspend new user registrations:', 'suspend_register_users' => 'Temporarily suspend new user registrations:',
'tag_separator_comma' => 'Use comma as the only tag separator:', 'tag_separator_comma' => 'Use comma as the only tag separator:',
'tags_or_categories' => 'Question classification:', 'tags_or_categories' => 'Question classification:',
'time_approved' => 'Time approved',
'time_written' => 'Time written',
'votes_separated' => 'Show separate up and down votes:', 'votes_separated' => 'Show separate up and down votes:',
'voting_on_as' => 'Allow voting on answers:', 'voting_on_as' => 'Allow voting on answers:',
'voting_on_q_page_only' => 'Allow voting on question page only:', 'voting_on_q_page_only' => 'Allow voting on question page only:',
......
...@@ -31,32 +31,48 @@ ...@@ -31,32 +31,48 @@
'1_with_best_chosen' => ' (1 with best answer chosen)', '1_with_best_chosen' => ' (1 with best answer chosen)',
'activity_by_x' => 'Activity by ^', 'activity_by_x' => 'Activity by ^',
'answers' => 'Answers:', 'answers' => 'Answers:',
'answers_by_x' => 'Answers by ^',
'bonus_points' => 'Bonus points:', 'bonus_points' => 'Bonus points:',
'comments' => 'Comments:', 'comments' => 'Comments:',
'delete_wall_post_popup' => 'Delete this wall post',
'extra_privileges' => 'Extra privileges:', 'extra_privileges' => 'Extra privileges:',
'gave_out' => 'Gave out:', 'gave_out' => 'Gave out:',
'wall_for_x' => 'Wall for ^',
'my_account_title' => 'My account details', 'my_account_title' => 'My account details',
'no_answers_by_x' => 'No answers by ^',
'no_posts_by_x' => 'No posts by ^', 'no_posts_by_x' => 'No posts by ^',
'no_questions_by_x' => 'No questions by ^',
'permit_anon_view_ips' => 'Viewing IPs of anonymous posts', 'permit_anon_view_ips' => 'Viewing IPs of anonymous posts',
'permit_close_q' => 'Closing any question', 'permit_close_q' => 'Closing any question',
'permit_delete_hidden' => 'Deleting hidden posts', 'permit_delete_hidden' => 'Deleting hidden posts',
'permit_edit_a' => 'Editing any answer', 'permit_edit_a' => 'Editing any answer',
'permit_edit_c' => 'Editing any comment', 'permit_edit_c' => 'Editing any comment',
'permit_edit_q' => 'Editing any question', 'permit_edit_q' => 'Editing any question',
'permit_edit_silent' => 'Editing posts silently',
'permit_flag' => 'Flagging posts', 'permit_flag' => 'Flagging posts',
'permit_hide_show' => 'Hiding or showing any post', 'permit_hide_show' => 'Hiding or showing any post',
'permit_moderate' => 'Approving or rejecting posts', 'permit_moderate' => 'Approving or rejecting posts',
'permit_post_a' => 'Answering questions', 'permit_post_a' => 'Answering questions',
'permit_post_c' => 'Adding comments', 'permit_post_c' => 'Adding comments',
'permit_post_q' => 'Asking questions', 'permit_post_q' => 'Asking questions',
'permit_post_wall' => 'Posting on user walls',
'permit_recat' => 'Recategorizing any question', 'permit_recat' => 'Recategorizing any question',
'permit_retag' => 'Retagging any question', 'permit_retag' => 'Retagging any question',
'permit_select_a' => 'Selecting answer for any question', 'permit_select_a' => 'Selecting answer for any question',
'permit_view_q_page' => 'Viewing question pages', 'permit_view_q_page' => 'Viewing question pages',
'permit_view_voters_flaggers' => 'Viewing who voted or flagged posts',
'permit_vote_a' => 'Voting on answers', 'permit_vote_a' => 'Voting on answers',
'permit_vote_down' => 'Voting posts down', 'permit_vote_down' => 'Voting posts down',
'permit_vote_q' => 'Voting on questions', 'permit_vote_q' => 'Voting on questions',
'post_wall_button' => 'Add wall post',
'post_wall_blocked' => 'This user has disallowed new posts on their wall',
'post_wall_empty' => 'Please enter something to post on this wall',
'post_wall_limit' => 'Too many wall posts created - please try again in an hour',
'post_wall_must_be_approved' => 'Your account must be approved to post on this wall.',
'post_wall_must_login' => 'Please ^1log in^2 or ^3register^4 to post on this wall.',
'post_wall_must_confirm' => 'Please ^5confirm your email address^6 to post on this wall.',
'questions' => 'Questions:', 'questions' => 'Questions:',
'questions_by_x' => 'Questions by ^',
'ranked_x' => ' (ranked #^)', 'ranked_x' => ' (ranked #^)',
'received' => 'Received:', 'received' => 'Received:',
'recent_activity_by_x' => 'Recent activity by ^', 'recent_activity_by_x' => 'Recent activity by ^',
......
...@@ -38,8 +38,10 @@ ...@@ -38,8 +38,10 @@
'add_answer_button' => 'Add answer', 'add_answer_button' => 'Add answer',
'add_comment_button' => 'Add comment', 'add_comment_button' => 'Add comment',
'add_q_favorites' => 'Add this question to my favorites', 'add_q_favorites' => 'Add this question to my favorites',
'anon_name_label' => 'Your name to display (optional):',
'answer_button' => 'answer', 'answer_button' => 'answer',
'answer_limit' => 'Too many answers received - please try again in an hour', 'answer_limit' => 'Too many answers received - please try again in an hour',
'answer_must_be_approved' => 'Your account must be approved before you answer a question.',
'answer_must_confirm' => 'Please ^5confirm your email address^6 to answer this question.', 'answer_must_confirm' => 'Please ^5confirm your email address^6 to answer this question.',
'answer_must_login' => 'Please ^1log in^2 or ^3register^4 to answer this question.', 'answer_must_login' => 'Please ^1log in^2 or ^3register^4 to answer this question.',
'answer_q_popup' => 'Answer this question', 'answer_q_popup' => 'Answer this question',
...@@ -48,6 +50,7 @@ ...@@ -48,6 +50,7 @@
'ask_follow_from_a' => 'Your question will be related to this answer:', 'ask_follow_from_a' => 'Your question will be related to this answer:',
'ask_follow_title' => 'Ask a related question', 'ask_follow_title' => 'Ask a related question',
'ask_limit' => 'Too many questions received - please try again in an hour', 'ask_limit' => 'Too many questions received - please try again in an hour',
'ask_must_be_approved' => 'Your account must be approved before you ask a question.',
'ask_must_confirm' => 'Please ^5confirm your email address^6 to ask a question.', 'ask_must_confirm' => 'Please ^5confirm your email address^6 to ask a question.',
'ask_must_login' => 'Please ^1log in^2 or ^3register^4 to ask a question.', 'ask_must_login' => 'Please ^1log in^2 or ^3register^4 to ask a question.',
'ask_same_q' => 'Before proceeding, please check your question was not asked already:', 'ask_same_q' => 'Before proceeding, please check your question was not asked already:',
...@@ -59,6 +62,7 @@ ...@@ -59,6 +62,7 @@
'c_your_waiting_approval' => 'Your comment will be checked and approved shortly.', 'c_your_waiting_approval' => 'Your comment will be checked and approved shortly.',
'category_js_note' => 'To select any category, please enable Javascript in your web browser.', 'category_js_note' => 'To select any category, please enable Javascript in your web browser.',
'category_required' => 'Please choose a category', 'category_required' => 'Please choose a category',
'category_ask_not_allowed' => 'You do not have permission to ask questions in this category',
'claim_button' => 'I wrote this', 'claim_button' => 'I wrote this',
'clear_flags_button' => 'clear flags', 'clear_flags_button' => 'clear flags',
'clear_flags_popup' => 'Remove flags by all users', 'clear_flags_popup' => 'Remove flags by all users',
...@@ -76,6 +80,7 @@ ...@@ -76,6 +80,7 @@
'comment_a_popup' => 'Add a comment on this answer', 'comment_a_popup' => 'Add a comment on this answer',
'comment_button' => 'comment', 'comment_button' => 'comment',
'comment_limit' => 'Too many comments received - please try again in an hour', 'comment_limit' => 'Too many comments received - please try again in an hour',
'comment_must_be_approved' => 'Your account must be approved before you add a comment.',
'comment_must_confirm' => 'Please ^5confirm your email address^6 to add a comment.', 'comment_must_confirm' => 'Please ^5confirm your email address^6 to add a comment.',
'comment_must_login' => 'Please ^1log in^2 or ^3register^4 to add a comment.', 'comment_must_login' => 'Please ^1log in^2 or ^3register^4 to add a comment.',
'comment_on_a' => 'On answer: ', 'comment_on_a' => 'On answer: ',
...@@ -144,6 +149,7 @@ ...@@ -144,6 +149,7 @@
'retag_cat_popup' => 'Change this question\'s category or tags', 'retag_cat_popup' => 'Change this question\'s category or tags',
'retag_popup' => 'Change this question\'s tags', 'retag_popup' => 'Change this question\'s tags',
'retag_q_title' => 'Retag question', 'retag_q_title' => 'Retag question',
'save_silent_label' => 'Save silently to hide that this was edited',
'select_popup' => 'Click to select as best answer', 'select_popup' => 'Click to select as best answer',
'select_text' => 'Best answer', 'select_text' => 'Best answer',
'show_1_comment' => 'Show 1 comment', 'show_1_comment' => 'Show 1 comment',
......
...@@ -27,12 +27,19 @@ ...@@ -27,12 +27,19 @@
return array( return array(
'about' => 'About', 'about' => 'About',
'add_user_x_favorites' => 'Add user ^ to my favorites', 'add_user_x_favorites' => 'Add user ^ to my favorites',
'approve_required' => 'Please wait for your account to be approved or ^1add more information^2.',
'approve_title' => 'User approval pending',
'approve_user_button' => 'Approve User',
'approved_user' => 'Approved user',
'avatar_default' => 'Default', 'avatar_default' => 'Default',
'avatar_gravatar' => 'Show my ^1Gravatar^2', 'avatar_gravatar' => 'Show my ^1Gravatar^2',
'avatar_label' => 'Avatar:', 'avatar_label' => 'Avatar:',
'avatar_none' => 'None', 'avatar_none' => 'None',
'block_user_button' => 'Block User', 'block_user_button' => 'Block User',
'blocked_users' => 'Blocked users', 'blocked_users' => 'Blocked users',
'category_level_add' => ' - ^1add per-category type^2',
'category_level_in' => 'in the category below:',
'category_level_label' => 'Per-category type:',
'change_email_link' => ' - ^1change email^2', 'change_email_link' => ' - ^1change email^2',
'change_password' => 'Change Password', 'change_password' => 'Change Password',
'confirm_complete' => 'Thank you - your email address has been confirmed', 'confirm_complete' => 'Thank you - your email address has been confirmed',
...@@ -42,7 +49,7 @@ ...@@ -42,7 +49,7 @@
'confirm_wrong_log_in' => 'Code not correct - please ^1log in^2 to send a new link', 'confirm_wrong_log_in' => 'Code not correct - please ^1log in^2 to send a new link',
'confirm_wrong_resend' => 'Code not correct - please click below to send a new link', 'confirm_wrong_resend' => 'Code not correct - please click below to send a new link',
'delete_user_button' => 'Delete User', 'delete_user_button' => 'Delete User',
'edit_user_button' => 'Edit this User', 'edit_user_button' => 'Edit User',
'email_confirmed' => 'Confirmed', 'email_confirmed' => 'Confirmed',
'email_exists' => 'Email already belongs to an account', 'email_exists' => 'Email already belongs to an account',
'email_handle_label' => 'Email or Username:', 'email_handle_label' => 'Email or Username:',
...@@ -63,6 +70,8 @@ ...@@ -63,6 +70,8 @@
'level_admin' => 'Administrator', 'level_admin' => 'Administrator',
'level_editor' => 'Editor', 'level_editor' => 'Editor',
'level_expert' => 'Expert', 'level_expert' => 'Expert',
'level_for_category' => '^1 for ^2',
'level_in_general' => 'in general',
'level_moderator' => 'Moderator', 'level_moderator' => 'Moderator',
'level_super' => 'Super Administrator', 'level_super' => 'Super Administrator',
'location' => 'Location', 'location' => 'Location',
...@@ -80,7 +89,9 @@ ...@@ -80,7 +89,9 @@
'no_permission' => 'You do not have permission to perform this operation', 'no_permission' => 'You do not have permission to perform this operation',
'old_password' => 'Old password:', 'old_password' => 'Old password:',
'only_shown_admins' => '(only shown to admins)', 'only_shown_admins' => '(only shown to admins)',
'only_shown_moderators' => '(only shown to moderators)', 'only_shown_editors' => '(only shown to editors and above)',
'only_shown_experts' => '(only shown to experts and above)',
'only_shown_moderators' => '(only shown to moderators and admins)',
'password_changed' => 'Password changed', 'password_changed' => 'Password changed',
'password_label' => 'Password:', 'password_label' => 'Password:',
'password_min' => 'Password must be at least ^ characters', 'password_min' => 'Password must be at least ^ characters',
...@@ -89,13 +100,16 @@ ...@@ -89,13 +100,16 @@
'password_sent' => 'Your new password was emailed to you', 'password_sent' => 'Your new password was emailed to you',
'password_to_set' => 'Please set on your account page', 'password_to_set' => 'Please set on your account page',
'password_wrong' => 'Password not correct', 'password_wrong' => 'Password not correct',
'private_messages_explanation' => 'Allow users to email me (without seeing my address)', 'private_messages_explanation' => 'Allow users to email you (without seeing your address)',
'private_messages' => 'Private messages:', 'private_messages' => 'Private messages:',
'profile_saved' => 'Profile saved', 'profile_saved' => 'Profile saved',
'wall_posts' => 'Wall posts:',
'wall_posts_explanation' => 'Allow users to post on your wall (you will also be emailed)',
'register_button' => 'Register', 'register_button' => 'Register',
'register_limit' => 'Too many registrations - please try again in an hour', 'register_limit' => 'Too many registrations - please try again in an hour',
'register_suspended' => 'Registration of new users has been temporarily suspended. Please try again soon.', 'register_suspended' => 'Registration of new users has been temporarily suspended. Please try again soon.',
'register_title' => 'Register as a new user', 'register_title' => 'Register as a new user',
'registered_label' => 'Registered:',
'registered_user' => 'Registered user', 'registered_user' => 'Registered user',
'remember_label' => 'Remember me on this computer', 'remember_label' => 'Remember me on this computer',
'remember' => 'Remember', 'remember' => 'Remember',
......
<?php
/*
Question2Answer (c) Gideon Greenspan
http://www.question2answer.org/
File: qa-include/qa-layer-voters-flaggers.php
Version: See define()s at top of qa-include/qa-base.php
Description: Theme layer class for viewing voters and flaggers
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
More about this license: http://www.question2answer.org/license.php
*/
class qa_html_theme_layer extends qa_html_theme_base {
var $qa_voters_flaggers_queue=array();
var $qa_voters_flaggers_cache=array();
// Utility functions for this layer
function queue_post_voters_flaggers($post)
{
if (!qa_user_post_permit_error('permit_view_voters_flaggers', $post)) {
$postids=array(@$post['postid'], @$post['opostid']); // opostid can be relevant for flags
foreach ($postids as $postid)
if (isset($postid) && !isset($this->qa_voters_flaggers_cache[$postid]))
$this->qa_voters_flaggers_queue[$postid]=true;
}
}
function queue_raw_posts_voters_flaggers($posts)
{
if (is_array($posts))
foreach ($posts as $post)
if (isset($post['raw']))
$this->queue_post_voters_flaggers($post['raw']);
}
function retrieve_queued_voters_flaggers()
{
if (count($this->qa_voters_flaggers_queue)) {
require_once QA_INCLUDE_DIR.'qa-db-votes.php';
$postids=array_keys($this->qa_voters_flaggers_queue);
foreach ($postids as $postid)
$this->qa_voters_flaggers_cache[$postid]=array();
$newvotersflaggers=qa_db_uservoteflag_posts_get($postids);
if (QA_FINAL_EXTERNAL_USERS) {
$keyuserids=array();
foreach ($newvotersflaggers as $voterflagger)
$keyuserids[$voterflagger['userid']]=true;
$useridhandles=qa_get_public_from_userids(array_keys($keyuserids));
foreach ($newvotersflaggers as $index => $voterflagger)
$newvotersflaggers[$index]['handle']=@$useridhandles[$voterflagger['userid']];
}
foreach ($newvotersflaggers as $voterflagger)
$this->qa_voters_flaggers_cache[$voterflagger['postid']][]=$voterflagger;
$this->qa_voters_flaggers_queue=array();
}
}
function get_post_voters_flaggers($post, $postid)
{
require_once QA_INCLUDE_DIR.'qa-util-sort.php';
if (!isset($this->qa_voters_flaggers_cache[$postid])) {
$this->queue_post_voters_flaggers($post);
$this->retrieve_queued_voters_flaggers();
}
$votersflaggers=@$this->qa_voters_flaggers_cache[$postid];
if (isset($votersflaggers))
qa_sort_by($votersflaggers, 'handle');
return $votersflaggers;
}
// Collect up all required postids for the entire page to save DB queries - common case where whole page output
function main()
{
foreach ($this->content as $key => $part) {
if (strpos($key, 'q_list')===0)
$this->queue_raw_posts_voters_flaggers(@$part['qs']);
elseif (strpos($key, 'q_view')===0) {
$this->queue_post_voters_flaggers($part['raw']);
$this->queue_raw_posts_voters_flaggers($part['c_list']['cs']);
} elseif (strpos($key, 'a_list')===0) {
if (!empty($part)) {
$this->queue_raw_posts_voters_flaggers($part['as']);
foreach ($part['as'] as $a_item)
$this->queue_raw_posts_voters_flaggers(@$a_item['c_list']['cs']);
}
}
}
qa_html_theme_base::main();
}
// Other functions which also collect up required postids for lists to save DB queries - helps with widget output and Ajax calls
function q_list_items($q_items)
{
$this->queue_raw_posts_voters_flaggers($q_items);
qa_html_theme_base::q_list_items($q_items);
}
function a_list_items($a_items)
{
$this->queue_raw_posts_voters_flaggers($a_items);
qa_html_theme_base::a_list_items($a_items);
}
function c_list_items($c_items)
{
$this->queue_raw_posts_voters_flaggers($c_items);
qa_html_theme_base::c_list_items($c_items);
}
// Actual output of the voters and flaggers
function vote_count($post)
{
$votersflaggers=$this->get_post_voters_flaggers($post['raw'], $post['raw']['postid']);
$tooltip='';
if (isset($votersflaggers)) {
$uphandles='';
$downhandles='';
foreach ($votersflaggers as $voterflagger) {
if ($voterflagger['vote']>0)
$uphandles.=(strlen($uphandles) ? ', ' : '').qa_html($voterflagger['handle']);
if ($voterflagger['vote']<0)
$downhandles.=(strlen($downhandles) ? ', ' : '').qa_html($voterflagger['handle']);
$tooltip=trim((strlen($uphandles) ? ('&uarr; '.$uphandles) : '')."\n\n".(strlen($downhandles) ? ('&darr; '.$downhandles) : ''));
}
}
if (strlen($tooltip))
$this->output('<SPAN TITLE="'.$tooltip.'">');
qa_html_theme_base::vote_count($post);
if (strlen($tooltip))
$this->output('</SPAN>');
}
function post_meta_flags($post, $class)
{
$postid=@$post['raw']['opostid'];
if (!isset($postid))
$postid=@$post['raw']['postid'];
$tooltip='';
if (isset($postid)) {
$votersflaggers=$this->get_post_voters_flaggers($post, $postid);
if (isset($votersflaggers))
foreach ($votersflaggers as $voterflagger)
if ($voterflagger['flag']>0)
$tooltip.=(strlen($tooltip) ? ', ' : '').qa_html($voterflagger['handle']);
}
if (strlen($tooltip))
$this->output('<SPAN TITLE="&#9873; '.$tooltip.'">');
qa_html_theme_base::post_meta_flags($post, $class);
if (strlen($tooltip))
$this->output('</SPAN>');
}
}
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -70,82 +70,91 @@ ...@@ -70,82 +70,91 @@
$inhandle=$changehandle ? qa_post_text('handle') : $useraccount['handle']; $inhandle=$changehandle ? qa_post_text('handle') : $useraccount['handle'];
$inemail=qa_post_text('email'); $inemail=qa_post_text('email');
$inmessages=qa_post_text('messages'); $inmessages=qa_post_text('messages');
$inwallposts=qa_post_text('wall');
$inmailings=qa_post_text('mailings'); $inmailings=qa_post_text('mailings');
$inavatar=qa_post_text('avatar'); $inavatar=qa_post_text('avatar');
$errors=qa_handle_email_filter($inhandle, $inemail, $useraccount);
if (!isset($errors['handle']))
qa_db_user_set($userid, 'handle', $inhandle);
if (!isset($errors['email'])) $inprofile=array();
if ($inemail != $useraccount['email']) { foreach ($userfields as $userfield)
qa_db_user_set($userid, 'email', $inemail); $inprofile[$userfield['fieldid']]=qa_post_text('field_'.$userfield['fieldid']);
qa_db_user_set_flag($userid, QA_USER_FLAGS_EMAIL_CONFIRMED, false);
$isconfirmed=false;
if ($doconfirms)
qa_send_new_confirm($userid);
}
if (qa_opt('allow_private_messages'))
qa_db_user_set_flag($userid, QA_USER_FLAGS_NO_MESSAGES, !$inmessages);
if (qa_opt('mailing_enabled')) if (!qa_check_form_security_code('account', qa_post_text('code')))
qa_db_user_set_flag($userid, QA_USER_FLAGS_NO_MAILINGS, !$inmailings); $errors['page']=qa_lang_html('misc/form_security_again');
qa_db_user_set_flag($userid, QA_USER_FLAGS_SHOW_AVATAR, ($inavatar=='uploaded')); else {
qa_db_user_set_flag($userid, QA_USER_FLAGS_SHOW_GRAVATAR, ($inavatar=='gravatar')); $errors=qa_handle_email_filter($inhandle, $inemail, $useraccount);
if (is_array(@$_FILES['file']) && $_FILES['file']['size']) { if (!isset($errors['handle']))
require_once QA_INCLUDE_DIR.'qa-app-limits.php'; qa_db_user_set($userid, 'handle', $inhandle);
if (!isset($errors['email']))
if ($inemail != $useraccount['email']) {
qa_db_user_set($userid, 'email', $inemail);
qa_db_user_set_flag($userid, QA_USER_FLAGS_EMAIL_CONFIRMED, false);
$isconfirmed=false;
if ($doconfirms)
qa_send_new_confirm($userid);
}
if (qa_opt('allow_private_messages'))
qa_db_user_set_flag($userid, QA_USER_FLAGS_NO_MESSAGES, !$inmessages);
switch (qa_user_permit_error(null, QA_LIMIT_UPLOADS)) if (qa_opt('allow_user_walls'))
{ qa_db_user_set_flag($userid, QA_USER_FLAGS_NO_WALL_POSTS, !$inwallposts);
case 'limit':
$errors['avatar']=qa_lang('main/upload_limit'); if (qa_opt('mailing_enabled'))
break; qa_db_user_set_flag($userid, QA_USER_FLAGS_NO_MAILINGS, !$inmailings);
qa_db_user_set_flag($userid, QA_USER_FLAGS_SHOW_AVATAR, ($inavatar=='uploaded'));
qa_db_user_set_flag($userid, QA_USER_FLAGS_SHOW_GRAVATAR, ($inavatar=='gravatar'));
if (is_array(@$_FILES['file']) && $_FILES['file']['size']) {
require_once QA_INCLUDE_DIR.'qa-app-limits.php';
default: switch (qa_user_permit_error(null, QA_LIMIT_UPLOADS))
$errors['avatar']=qa_lang('users/no_permission'); {
break; case 'limit':
$errors['avatar']=qa_lang('main/upload_limit');
break;
case false: default:
qa_limits_increment($userid, QA_LIMIT_UPLOADS); $errors['avatar']=qa_lang('users/no_permission');
break;
$toobig=qa_image_file_too_big($_FILES['file']['tmp_name'], qa_opt('avatar_store_size'));
case false:
if ($toobig) qa_limits_increment($userid, QA_LIMIT_UPLOADS);
$errors['avatar']=qa_lang_sub('main/image_too_big_x_pc', (int)($toobig*100));
elseif (!qa_set_user_avatar($userid, file_get_contents($_FILES['file']['tmp_name']), $useraccount['avatarblobid'])) $toobig=qa_image_file_too_big($_FILES['file']['tmp_name'], qa_opt('avatar_store_size'));
$errors['avatar']=qa_lang_sub('main/image_not_read', implode(', ', qa_gd_image_formats()));
break; if ($toobig)
$errors['avatar']=qa_lang_sub('main/image_too_big_x_pc', (int)($toobig*100));
elseif (!qa_set_user_avatar($userid, file_get_contents($_FILES['file']['tmp_name']), $useraccount['avatarblobid']))
$errors['avatar']=qa_lang_sub('main/image_not_read', implode(', ', qa_gd_image_formats()));
break;
}
} }
}
$inprofile=array();
foreach ($userfields as $userfield)
$inprofile[$userfield['fieldid']]=qa_post_text('field_'.$userfield['fieldid']);
$filtermodules=qa_load_modules_with('filter', 'filter_profile');
foreach ($filtermodules as $filtermodule)
$filtermodule->filter_profile($inprofile, $errors, $useraccount, $userprofile);
foreach ($userfields as $userfield) $filtermodules=qa_load_modules_with('filter', 'filter_profile');
if (!isset($errors[$userfield['fieldid']])) foreach ($filtermodules as $filtermodule)
qa_db_user_profile_set($userid, $userfield['title'], $inprofile[$userfield['fieldid']]); $filtermodule->filter_profile($inprofile, $errors, $useraccount, $userprofile);
list($useraccount, $userprofile)=qa_db_select_with_pending( foreach ($userfields as $userfield)
qa_db_user_account_selectspec($userid, true), if (!isset($errors[$userfield['fieldid']]))
qa_db_user_profile_selectspec($userid, true) qa_db_user_profile_set($userid, $userfield['title'], $inprofile[$userfield['fieldid']]);
);
list($useraccount, $userprofile)=qa_db_select_with_pending(
qa_report_event('u_save', $userid, $useraccount['handle'], qa_cookie_get()); qa_db_user_account_selectspec($userid, true),
qa_db_user_profile_selectspec($userid, true)
if (empty($errors)) );
qa_redirect('account', array('state' => 'profile-saved'));
qa_report_event('u_save', $userid, $useraccount['handle'], qa_cookie_get());
qa_logged_in_user_flush();
if (empty($errors))
qa_redirect('account', array('state' => 'profile-saved'));
qa_logged_in_user_flush();
}
} }
...@@ -158,25 +167,30 @@ ...@@ -158,25 +167,30 @@
$innewpassword1=qa_post_text('newpassword1'); $innewpassword1=qa_post_text('newpassword1');
$innewpassword2=qa_post_text('newpassword2'); $innewpassword2=qa_post_text('newpassword2');
$errors=array(); if (!qa_check_form_security_code('password', qa_post_text('code')))
$errors['page']=qa_lang_html('misc/form_security_again');
if ($haspassword && (strtolower(qa_db_calc_passcheck($inoldpassword, $useraccount['passsalt'])) != strtolower($useraccount['passcheck']))) else {
$errors['oldpassword']=qa_lang('users/password_wrong'); $errors=array();
$useraccount['password']=$inoldpassword;
$errors=$errors+qa_password_validate($innewpassword1, $useraccount); // array union
if ($innewpassword1 != $innewpassword2)
$errors['newpassword2']=qa_lang('users/password_mismatch');
if (empty($errors)) { if ($haspassword && (strtolower(qa_db_calc_passcheck($inoldpassword, $useraccount['passsalt'])) != strtolower($useraccount['passcheck'])))
qa_db_user_set_password($userid, $innewpassword1); $errors['oldpassword']=qa_lang('users/password_wrong');
qa_db_user_set($userid, 'sessioncode', ''); // stop old 'Remember me' style logins from still working
qa_set_logged_in_user($userid, $useraccount['handle'], false, $useraccount['sessionsource']); // reinstate this specific session $useraccount['password']=$inoldpassword;
$errors=$errors+qa_password_validate($innewpassword1, $useraccount); // array union
qa_report_event('u_password', $userid, $useraccount['handle'], qa_cookie_get());
if ($innewpassword1 != $innewpassword2)
qa_redirect('account', array('state' => 'password-changed')); $errors['newpassword2']=qa_lang('users/password_mismatch');
if (empty($errors)) {
qa_db_user_set_password($userid, $innewpassword1);
qa_db_user_set($userid, 'sessioncode', ''); // stop old 'Remember me' style logins from still working
qa_set_logged_in_user($userid, $useraccount['handle'], false, $useraccount['sessionsource']); // reinstate this specific session
qa_report_event('u_password', $userid, $useraccount['handle'], qa_cookie_get());
qa_redirect('account', array('state' => 'password-changed'));
}
} }
} }
...@@ -185,7 +199,8 @@ ...@@ -185,7 +199,8 @@
$qa_content=qa_content_prepare(); $qa_content=qa_content_prepare();
$qa_content['title']=qa_lang_html('profile/my_account_title'); $qa_content['title']=qa_lang_html('profile/my_account_title');
$qa_content['error']=@$errors['page'];
$qa_content['form_profile']=array( $qa_content['form_profile']=array(
'tags' => 'ENCTYPE="multipart/form-data" METHOD="POST" ACTION="'.qa_self_html().'"', 'tags' => 'ENCTYPE="multipart/form-data" METHOD="POST" ACTION="'.qa_self_html().'"',
...@@ -229,6 +244,14 @@ ...@@ -229,6 +244,14 @@
'note' => qa_lang_html('users/private_messages_explanation'), 'note' => qa_lang_html('users/private_messages_explanation'),
), ),
'wall' => array(
'label' => qa_lang_html('users/wall_posts'),
'tags' => 'NAME="wall"',
'type' => 'checkbox',
'value' => !($useraccount['flags'] & QA_USER_FLAGS_NO_WALL_POSTS),
'note' => qa_lang_html('users/wall_posts_explanation'),
),
'mailings' => array( 'mailings' => array(
'label' => qa_lang_html('users/mass_mailings'), 'label' => qa_lang_html('users/mass_mailings'),
'tags' => 'NAME="mailings"', 'tags' => 'NAME="mailings"',
...@@ -248,7 +271,8 @@ ...@@ -248,7 +271,8 @@
), ),
'hidden' => array( 'hidden' => array(
'dosaveprofile' => '1' 'dosaveprofile' => '1',
'code' => qa_get_form_security_code('account'),
), ),
); );
...@@ -258,6 +282,9 @@ ...@@ -258,6 +282,9 @@
if (!qa_opt('allow_private_messages')) if (!qa_opt('allow_private_messages'))
unset($qa_content['form_profile']['fields']['messages']); unset($qa_content['form_profile']['fields']['messages']);
if (!qa_opt('allow_user_walls'))
unset($qa_content['form_profile']['fields']['wall']);
if (!qa_opt('mailing_enabled')) if (!qa_opt('mailing_enabled'))
unset($qa_content['form_profile']['fields']['mailings']); unset($qa_content['form_profile']['fields']['mailings']);
...@@ -381,6 +408,7 @@ ...@@ -381,6 +408,7 @@
'hidden' => array( 'hidden' => array(
'dochangepassword' => '1', 'dochangepassword' => '1',
'code' => qa_get_form_security_code('password'),
), ),
); );
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
require_once QA_INCLUDE_DIR.'qa-db-selects.php'; require_once QA_INCLUDE_DIR.'qa-db-selects.php';
require_once QA_INCLUDE_DIR.'qa-app-format.php'; require_once QA_INCLUDE_DIR.'qa-app-format.php';
require_once QA_INCLUDE_DIR.'qa-app-updates.php';
require_once QA_INCLUDE_DIR.'qa-app-q-list.php'; require_once QA_INCLUDE_DIR.'qa-app-q-list.php';
$categoryslugs=qa_request_parts(1); $categoryslugs=qa_request_parts(1);
...@@ -42,14 +41,13 @@ ...@@ -42,14 +41,13 @@
// Get lists of recent activity in all its forms, plus category information // Get lists of recent activity in all its forms, plus category information
@list($questions1, $questions2, $questions3, $questions4, $categories, $categoryid, $favorite)=qa_db_select_with_pending( list($questions1, $questions2, $questions3, $questions4, $categories, $categoryid)=qa_db_select_with_pending(
qa_db_qs_selectspec($userid, 'created', 0, $categoryslugs, null, false, false, qa_opt_if_loaded('page_size_activity')), qa_db_qs_selectspec($userid, 'created', 0, $categoryslugs, null, false, false, qa_opt_if_loaded('page_size_activity')),
qa_db_recent_a_qs_selectspec($userid, 0, $categoryslugs), qa_db_recent_a_qs_selectspec($userid, 0, $categoryslugs),
qa_db_recent_c_qs_selectspec($userid, 0, $categoryslugs), qa_db_recent_c_qs_selectspec($userid, 0, $categoryslugs),
qa_db_recent_edit_qs_selectspec($userid, 0, $categoryslugs), qa_db_recent_edit_qs_selectspec($userid, 0, $categoryslugs),
qa_db_category_nav_selectspec($categoryslugs, false, false, true), qa_db_category_nav_selectspec($categoryslugs, false, false, true),
$countslugs ? qa_db_slugs_to_category_id_selectspec($categoryslugs) : null, $countslugs ? qa_db_slugs_to_category_id_selectspec($categoryslugs) : null
($countslugs && isset($userid)) ? qa_db_is_favorite_selectspec($userid, QA_ENTITY_CATEGORY, $categoryslugs) : null
); );
if ($countslugs) { if ($countslugs) {
...@@ -82,8 +80,7 @@ ...@@ -82,8 +80,7 @@
qa_opt('feed_for_activity') ? 'activity' : null, // prefix for RSS feed paths (null to hide) qa_opt('feed_for_activity') ? 'activity' : null, // prefix for RSS feed paths (null to hide)
qa_html_suggest_qs_tags(qa_using_tags(), qa_category_path_request($categories, $categoryid)), // suggest what to do next qa_html_suggest_qs_tags(qa_using_tags(), qa_category_path_request($categories, $categoryid)), // suggest what to do next
null, // page link params null, // page link params
null, // category nav params null // category nav params
$favorite // has user favorited this category
); );
......
<?php
/*
Question2Answer (c) Gideon Greenspan
http://www.question2answer.org/
File: qa-include/qa-page-admin-approve.php
Version: See define()s at top of qa-include/qa-base.php
Description: Controller for admin page showing new users waiting for approval
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
More about this license: http://www.question2answer.org/license.php
*/
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../');
exit;
}
require_once QA_INCLUDE_DIR.'qa-app-admin.php';
require_once QA_INCLUDE_DIR.'qa-db-admin.php';
// Check we're not using single-sign on integration
if (QA_FINAL_EXTERNAL_USERS)
qa_fatal_error('User accounts are handled by external code');
// Find most flagged questions, answers, comments
$userid=qa_get_logged_in_userid();
$users=qa_db_get_unapproved_users(qa_opt('page_size_users'));
$userfields=qa_db_select_with_pending(qa_db_userfields_selectspec());
// Check admin privileges (do late to allow one DB query)
if (qa_get_logged_in_level()<QA_USER_LEVEL_MODERATOR) {
$qa_content=qa_content_prepare();
$qa_content['error']=qa_lang_html('users/no_permission');
return $qa_content;
}
// Check to see if any were approved or blocked here
$pageerror=qa_admin_check_clicks();
// Prepare content for theme
$qa_content=qa_content_prepare();
$qa_content['title']=qa_lang_html('admin/approve_users_title');
$qa_content['error']=isset($pageerror) ? $pageerror : qa_admin_page_error();
$qa_content['message_list']=array(
'form' => array(
'tags' => 'METHOD="POST" ACTION="'.qa_self_html().'"',
'hidden' => array(
'code' => qa_get_form_security_code('admin/click'),
),
),
'messages' => array(),
);
if (count($users)) {
foreach ($users as $user) {
$message=array();
$message['tags']='ID="p'.qa_html($user['userid']).'"'; // use p prefix for qa_admin_click() in qa-admin.js
$message['content']=qa_lang_html('users/registered_label').' '.
strtr(qa_lang_html('users/x_ago_from_y'), array(
'^1' => qa_time_to_string(qa_opt('db_time')-$user['created']),
'^2' => qa_ip_anchor_html($user['createip']),
)).'<br/>';
$htmlemail=qa_html($user['email']);
$message['content'].=qa_lang_html('users/email_label').' <A HREF="mailto:'.$htmlemail.'">'.$htmlemail.'</A>';
foreach ($userfields as $userfield)
if (strlen(@$user['profile'][$userfield['title']]))
$message['content'].='<br/>'.qa_html($userfield['content'].': '.$user['profile'][$userfield['title']]);
$message['meta_order']=qa_lang_html('main/meta_order');
$message['who']['data']=qa_get_one_user_html($user['handle']);
$message['form']=array(
'style' => 'light',
'buttons' => array(
'approve' => array(
'tags' => 'NAME="admin_'.$user['userid'].'_userapprove" onclick="return qa_admin_click(this);"',
'label' => qa_lang_html('question/approve_button'),
),
'block' => array(
'tags' => 'NAME="admin_'.$user['userid'].'_userblock" onclick="return qa_admin_click(this);"',
'label' => qa_lang_html('admin/block_button'),
),
),
);
$qa_content['message_list']['messages'][]=$message;
}
} else
$qa_content['title']=qa_lang_html('admin/no_unapproved_found');
$qa_content['navigation']['sub']=qa_admin_sub_navigation();
$qa_content['script_rel'][]='qa-content/qa-admin.js?'.QA_VERSION;
return $qa_content;
/*
Omit PHP closing tag to help avoid accidental output
*/
\ No newline at end of file
...@@ -80,14 +80,20 @@ ...@@ -80,14 +80,20 @@
$hassubcategory=true; $hassubcategory=true;
// Process saving options // Process saving options
$savedoptions=false; $savedoptions=false;
$securityexpired=false;
if (qa_clicked('dosaveoptions')) { if (qa_clicked('dosaveoptions')) {
qa_set_option('allow_no_category', (int)qa_post_text('option_allow_no_category')); if (!qa_check_form_security_code('admin/categories', qa_post_text('code')))
qa_set_option('allow_no_sub_category', (int)qa_post_text('option_allow_no_sub_category')); $securityexpired=true;
$savedoptions=true;
else {
qa_set_option('allow_no_category', (int)qa_post_text('option_allow_no_category'));
qa_set_option('allow_no_sub_category', (int)qa_post_text('option_allow_no_sub_category'));
$savedoptions=true;
}
} }
...@@ -102,13 +108,20 @@ ...@@ -102,13 +108,20 @@
qa_redirect(qa_request(), array('edit' => @$editcategory['parentid'])); qa_redirect(qa_request(), array('edit' => @$editcategory['parentid']));
} elseif (qa_clicked('dosetmissing')) { } elseif (qa_clicked('dosetmissing')) {
$inreassign=qa_get_category_field_value('reassign'); if (!qa_check_form_security_code('admin/categories', qa_post_text('code')))
qa_db_category_reassign($editcategory['categoryid'], $inreassign); $securityexpired=true;
qa_redirect(qa_request(), array('recalc' => 1, 'edit' => $editcategory['categoryid']));
else {
$inreassign=qa_get_category_field_value('reassign');
qa_db_category_reassign($editcategory['categoryid'], $inreassign);
qa_redirect(qa_request(), array('recalc' => 1, 'edit' => $editcategory['categoryid']));
}
} elseif (qa_clicked('dosavecategory')) { } elseif (qa_clicked('dosavecategory')) {
if (!qa_check_form_security_code('admin/categories', qa_post_text('code')))
if (qa_post_text('dodelete')) { $securityexpired=true;
elseif (qa_post_text('dodelete')) {
if (!$hassubcategory) { if (!$hassubcategory) {
$inreassign=qa_get_category_field_value('reassign'); $inreassign=qa_get_category_field_value('reassign');
...@@ -230,8 +243,7 @@ ...@@ -230,8 +243,7 @@
$qa_content=qa_content_prepare(); $qa_content=qa_content_prepare();
$qa_content['title']=qa_lang_html('admin/admin_title').' - '.qa_lang_html('admin/categories_title'); $qa_content['title']=qa_lang_html('admin/admin_title').' - '.qa_lang_html('admin/categories_title');
$qa_content['error']=$securityexpired ? qa_lang_html('admin/form_security_expired') : qa_admin_page_error();
$qa_content['error']=qa_admin_page_error();
if ($setmissing) { if ($setmissing) {
$qa_content['form']=array( $qa_content['form']=array(
...@@ -263,6 +275,7 @@ ...@@ -263,6 +275,7 @@
'dosetmissing' => '1', // for IE 'dosetmissing' => '1', // for IE
'edit' => @$editcategory['categoryid'], 'edit' => @$editcategory['categoryid'],
'missing' => '1', 'missing' => '1',
'code' => qa_get_form_security_code('admin/categories'),
), ),
); );
...@@ -328,6 +341,7 @@ ...@@ -328,6 +341,7 @@
'edit' => @$editcategory['categoryid'], 'edit' => @$editcategory['categoryid'],
'parent' => @$editcategory['parentid'], 'parent' => @$editcategory['parentid'],
'setparent' => (int)$setparent, 'setparent' => (int)$setparent,
'code' => qa_get_form_security_code('admin/categories'),
), ),
); );
...@@ -534,6 +548,10 @@ ...@@ -534,6 +548,10 @@
'label' => qa_lang_html('admin/add_category_button'), 'label' => qa_lang_html('admin/add_category_button'),
), ),
), ),
'hidden' => array(
'code' => qa_get_form_security_code('admin/categories'),
),
); );
if (count($categories)) { if (count($categories)) {
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
// Check admin privileges (do late to allow one DB query) // Check admin privileges (do late to allow one DB query)
if (qa_user_permit_error('permit_hide_show')) { if (qa_user_maximum_permit_error('permit_hide_show')) {
$qa_content=qa_content_prepare(); $qa_content=qa_content_prepare();
$qa_content['error']=qa_lang_html('users/no_permission'); $qa_content['error']=qa_lang_html('users/no_permission');
return $qa_content; return $qa_content;
...@@ -54,7 +54,15 @@ ...@@ -54,7 +54,15 @@
// Check to see if any were cleared or hidden here // Check to see if any were cleared or hidden here
qa_admin_check_clicks(); $pageerror=qa_admin_check_clicks();
// Remove questions the user has no permission to hide/show
if (qa_user_permit_error('permit_hide_show')) // if user not allowed to show/hide all posts
foreach ($questions as $index => $question)
if (qa_user_post_permit_error('permit_hide_show', $question))
unset($questions[$index]);
// Get information for users // Get information for users
...@@ -67,12 +75,15 @@ ...@@ -67,12 +75,15 @@
$qa_content=qa_content_prepare(); $qa_content=qa_content_prepare();
$qa_content['title']=qa_lang_html('admin/most_flagged_title'); $qa_content['title']=qa_lang_html('admin/most_flagged_title');
$qa_content['error']=isset($pageerror) ? $pageerror : qa_admin_page_error();
$qa_content['error']=qa_admin_page_error();
$qa_content['q_list']=array( $qa_content['q_list']=array(
'form' => array( 'form' => array(
'tags' => 'METHOD="POST" ACTION="'.qa_self_html().'"', 'tags' => 'METHOD="POST" ACTION="'.qa_self_html().'"',
'hidden' => array(
'code' => qa_get_form_security_code('admin/click'),
),
), ),
'qs' => array(), 'qs' => array(),
...@@ -84,7 +95,7 @@ ...@@ -84,7 +95,7 @@
$postid=qa_html(isset($question['opostid']) ? $question['opostid'] : $question['postid']); $postid=qa_html(isset($question['opostid']) ? $question['opostid'] : $question['postid']);
$elementid='p'.$postid; $elementid='p'.$postid;
$htmloptions=qa_post_html_defaults('Q'); $htmloptions=qa_post_html_options($question);
$htmloptions['voteview']=false; $htmloptions['voteview']=false;
$htmloptions['tagsview']=($question['obasetype']=='Q'); $htmloptions['tagsview']=($question['obasetype']=='Q');
$htmloptions['answersview']=false; $htmloptions['answersview']=false;
......
...@@ -48,10 +48,7 @@ ...@@ -48,10 +48,7 @@
// Check admin privileges (do late to allow one DB query) // Check admin privileges (do late to allow one DB query)
$allowhideshow=!qa_user_permit_error('permit_hide_show'); if (qa_user_maximum_permit_error('permit_hide_show') && qa_user_maximum_permit_error('permit_delete_hidden')) {
$allowdeletehidden=!qa_user_permit_error('permit_delete_hidden');
if (!($allowhideshow || $allowdeletehidden)) {
$qa_content=qa_content_prepare(); $qa_content=qa_content_prepare();
$qa_content['error']=qa_lang_html('users/no_permission'); $qa_content['error']=qa_lang_html('users/no_permission');
return $qa_content; return $qa_content;
...@@ -60,13 +57,21 @@ ...@@ -60,13 +57,21 @@
// Check to see if any have been reshown or deleted // Check to see if any have been reshown or deleted
qa_admin_check_clicks(); $pageerror=qa_admin_check_clicks();
// Combine sets of questions, get information for users // Combine sets of questions and remove those this user has no permissions for
$questions=qa_any_sort_by_date(array_merge($hiddenquestions, $hiddenanswers, $hiddencomments)); $questions=qa_any_sort_by_date(array_merge($hiddenquestions, $hiddenanswers, $hiddencomments));
if (qa_user_permit_error('permit_hide_show') && qa_user_permit_error('permit_delete_hidden')) // not allowed to see all hidden posts
foreach ($questions as $index => $question)
if (qa_user_post_permit_error('permit_hide_show', $question) && qa_user_post_permit_error('permit_delete_hidden', $question))
unset($questions[$index]);
// Get information for users
$usershtml=qa_userids_handles_html(qa_any_get_userids_handles($questions)); $usershtml=qa_userids_handles_html(qa_any_get_userids_handles($questions));
...@@ -84,12 +89,15 @@ ...@@ -84,12 +89,15 @@
$qa_content=qa_content_prepare(); $qa_content=qa_content_prepare();
$qa_content['title']=qa_lang_html('admin/recent_hidden_title'); $qa_content['title']=qa_lang_html('admin/recent_hidden_title');
$qa_content['error']=isset($pageerror) ? $pageerror : qa_admin_page_error();
$qa_content['error']=qa_admin_page_error();
$qa_content['q_list']=array( $qa_content['q_list']=array(
'form' => array( 'form' => array(
'tags' => 'METHOD="POST" ACTION="'.qa_self_html().'"', 'tags' => 'METHOD="POST" ACTION="'.qa_self_html().'"',
'hidden' => array(
'code' => qa_get_form_security_code('admin/click'),
),
), ),
'qs' => array(), 'qs' => array(),
...@@ -99,7 +107,7 @@ ...@@ -99,7 +107,7 @@
foreach ($questions as $key => $question) { foreach ($questions as $key => $question) {
$elementid='p'.$qhiddenpostid[$key]; $elementid='p'.$qhiddenpostid[$key];
$htmloptions=qa_post_html_defaults('Q'); $htmloptions=qa_post_html_options($question);
$htmloptions['voteview']=false; $htmloptions['voteview']=false;
$htmloptions['tagsview']=!isset($question['opostid']); $htmloptions['tagsview']=!isset($question['opostid']);
$htmloptions['answersview']=false; $htmloptions['answersview']=false;
...@@ -120,13 +128,13 @@ ...@@ -120,13 +128,13 @@
$buttons=array(); $buttons=array();
if ($allowhideshow) if (!qa_user_post_permit_error('permit_hide_show', $question))
$buttons['reshow']=array( $buttons['reshow']=array(
'tags' => 'NAME="admin_'.qa_html($qhiddenpostid[$key]).'_reshow" onclick="return qa_admin_click(this);"', 'tags' => 'NAME="admin_'.qa_html($qhiddenpostid[$key]).'_reshow" onclick="return qa_admin_click(this);"',
'label' => qa_lang_html('question/reshow_button'), 'label' => qa_lang_html('question/reshow_button'),
); );
if ($allowdeletehidden && !$dependcounts[$qhiddenpostid[$key]]) if ((!qa_user_post_permit_error('permit_delete_hidden', $question)) && !$dependcounts[$qhiddenpostid[$key]])
$buttons['delete']=array( $buttons['delete']=array(
'tags' => 'NAME="admin_'.qa_html($qhiddenpostid[$key]).'_delete" onclick="return qa_admin_click(this);"', 'tags' => 'NAME="admin_'.qa_html($qhiddenpostid[$key]).'_delete" onclick="return qa_admin_click(this);"',
'label' => qa_lang_html('question/delete_button'), 'label' => qa_lang_html('question/delete_button'),
......
This source diff could not be displayed because it is too large. You can view the blob instead.
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