Commit dbe6904d by Scott

Merge dev (1.7.2-alpha) into 1.8

parents 2e172b12 0bf0f2d6
1.7.0 1.7.1
\ No newline at end of file \ No newline at end of file
...@@ -1466,15 +1466,10 @@ ...@@ -1466,15 +1466,10 @@
foreach ($keysourceids as $key => $dummy) { foreach ($keysourceids as $key => $dummy) {
$funcscript[]="\tvar e=document.getElementById(".qa_js($key).");"; $funcscript[]="\tvar e=document.getElementById(".qa_js($key).");";
$funcscript[]="\tvar ".$key."=e && (e.checked || (e.options && e.options[e.selectedIndex].value));"; $funcscript[]="\tvar ".$key."=e && (e.checked || (e.options && e.options[e.selectedIndex].value));";
$loadscript[]="var e=document.getElementById(".qa_js($key).");";
$loadscript[]="if (e) {"; $loadscript[]="jQuery(".qa_js('#'.$key).").click(function() {";
$loadscript[]="\t".$key."_oldonclick=e.onclick;"; $loadscript[]="\t".$function."(false);";
$loadscript[]="\te.onclick=function() {"; $loadscript[]="});";
$loadscript[]="\t\t".$function."(false);";
$loadscript[]="\t\tif (typeof ".$key."_oldonclick=='function')";
$loadscript[]="\t\t\t".$key."_oldonclick();";
$loadscript[]="\t};";
$loadscript[]="}";
} }
foreach ($effects as $target => $sources) { foreach ($effects as $target => $sources) {
......
...@@ -437,6 +437,8 @@ ...@@ -437,6 +437,8 @@
if ($oldquestion['type']!='Q_HIDDEN') if ($oldquestion['type']!='Q_HIDDEN')
qa_fatal_error('Tried to delete a non-hidden question'); qa_fatal_error('Tried to delete a non-hidden question');
qa_report_event('q_delete_before', $userid, $handle, $cookieid, $params);
if (isset($oldclosepost) && ($oldclosepost['parentid']==$oldquestion['postid'])) { if (isset($oldclosepost) && ($oldclosepost['parentid']==$oldquestion['postid'])) {
qa_db_post_set_closed($oldquestion['postid'], null); // for foreign key constraint qa_db_post_set_closed($oldquestion['postid'], null); // for foreign key constraint
qa_post_unindex($oldclosepost['postid']); qa_post_unindex($oldclosepost['postid']);
...@@ -451,8 +453,6 @@ ...@@ -451,8 +453,6 @@
'oldquestion' => $oldquestion, 'oldquestion' => $oldquestion,
); );
qa_report_event('q_delete_before', $userid, $handle, $cookieid, $params);
qa_post_unindex($oldquestion['postid']); qa_post_unindex($oldquestion['postid']);
qa_db_post_delete($oldquestion['postid']); // also deletes any related voteds due to foreign key cascading qa_db_post_delete($oldquestion['postid']); // also deletes any related voteds due to foreign key cascading
qa_update_counts_for_q(null); qa_update_counts_for_q(null);
......
...@@ -1026,8 +1026,8 @@ ...@@ -1026,8 +1026,8 @@
{ {
return array( return array(
'columns' => array('wordid', 'word', 'tagcount'), 'columns' => array('wordid', 'word', 'tagcount'),
'source' => '^words WHERE word=$', 'source' => '^words WHERE word=$ AND word=$ COLLATE utf8_bin',
'arguments' => array($tag), 'arguments' => array($tag, qa_strtolower($tag)),
'single' => true, 'single' => true,
); );
} }
......
...@@ -1235,7 +1235,6 @@ ...@@ -1235,7 +1235,6 @@
$editors = qa_list_modules('editor'); $editors = qa_list_modules('editor');
$selectoptions = array(); $selectoptions = array();
$optionslinks = false;
foreach ($editors as $editor) { foreach ($editors as $editor) {
$selectoptions[qa_html($editor)] = strlen($editor) ? qa_html($editor) : qa_lang_html('admin/basic_editor'); $selectoptions[qa_html($editor)] = strlen($editor) ? qa_html($editor) : qa_lang_html('admin/basic_editor');
......
...@@ -112,8 +112,6 @@ ...@@ -112,8 +112,6 @@
qa_set_template('custom'); qa_set_template('custom');
$qa_content=qa_content_prepare(); $qa_content=qa_content_prepare();
$qa_content['title']=qa_html(qa_opt('custom_home_heading')); $qa_content['title']=qa_html(qa_opt('custom_home_heading'));
if (qa_opt('show_home_description'))
$qa_content['description']=qa_html(qa_opt('home_description'));
$qa_content['custom']=qa_opt('custom_home_content'); $qa_content['custom']=qa_opt('custom_home_content');
return $qa_content; return $qa_content;
} }
...@@ -162,9 +160,6 @@ ...@@ -162,9 +160,6 @@
null // category nav params null // category nav params
); );
if ( (!$explicitqa) && (!$countslugs) && qa_opt('show_home_description') )
$qa_content['description']=qa_html(qa_opt('home_description'));
return $qa_content; return $qa_content;
......
...@@ -333,6 +333,7 @@ ...@@ -333,6 +333,7 @@
$errors['content']=qa_lang_html('misc/form_security_again'); $errors['content']=qa_lang_html('misc/form_security_again');
else { else {
// call any filter plugins
$filtermodules=qa_load_modules_with('filter', 'filter_answer'); $filtermodules=qa_load_modules_with('filter', 'filter_answer');
foreach ($filtermodules as $filtermodule) { foreach ($filtermodules as $filtermodule) {
$oldin=$in; $oldin=$in;
...@@ -340,9 +341,11 @@ ...@@ -340,9 +341,11 @@
qa_update_post_text($in, $oldin); qa_update_post_text($in, $oldin);
} }
// check CAPTCHA
if ($usecaptcha) if ($usecaptcha)
qa_captcha_validate_post($errors); qa_captcha_validate_post($errors);
// check for duplicate posts
if (empty($errors)) { if (empty($errors)) {
$testwords=implode(' ', qa_string_to_words($in['content'])); $testwords=implode(' ', qa_string_to_words($in['content']));
...@@ -352,12 +355,24 @@ ...@@ -352,12 +355,24 @@
$errors['content']=qa_lang_html('question/duplicate_content'); $errors['content']=qa_lang_html('question/duplicate_content');
} }
$userid = qa_get_logged_in_userid();
// if this is an additional answer, check we can add it
if (empty($errors) && !qa_opt('allow_multi_answers')) {
foreach ($answers as $answer) {
if (qa_post_is_by_user($answer, $userid, qa_cookie_get())) {
$errors[] = '';
break;
}
}
}
// create the answer
if (empty($errors)) { if (empty($errors)) {
$userid=qa_get_logged_in_userid(); $handle = qa_get_logged_in_handle();
$handle=qa_get_logged_in_handle(); $cookieid = isset($userid) ? qa_cookie_get() : qa_cookie_get_create(); // create a new cookie if necessary
$cookieid=isset($userid) ? qa_cookie_get() : qa_cookie_get_create(); // create a new cookie if necessary
$answerid=qa_answer_create($userid, $handle, $cookieid, $in['content'], $in['format'], $in['text'], $in['notify'], $in['email'], $answerid = qa_answer_create($userid, $handle, $cookieid, $in['content'], $in['format'], $in['text'], $in['notify'], $in['email'],
$question, $in['queued'], $in['name']); $question, $in['queued'], $in['name']);
return $answerid; return $answerid;
......
...@@ -194,17 +194,6 @@ ...@@ -194,17 +194,6 @@
)); ));
} }
// show T&Cs checkbox
if ($show_terms) {
$qa_content['form']['fields']['terms'] = array(
'type' => 'checkbox',
'label' => trim(qa_opt('register_terms')),
'tags' => 'name="terms" id="terms"',
'value' => qa_html(@$interms),
'error' => qa_html(@$errors['terms']),
);
}
foreach ($userfields as $userfield) { foreach ($userfields as $userfield) {
$value = @$inprofile[$userfield['fieldid']]; $value = @$inprofile[$userfield['fieldid']];
...@@ -224,6 +213,17 @@ ...@@ -224,6 +213,17 @@
if (qa_opt('captcha_on_register')) if (qa_opt('captcha_on_register'))
qa_set_up_captcha_field($qa_content, $qa_content['form']['fields'], @$errors); qa_set_up_captcha_field($qa_content, $qa_content['form']['fields'], @$errors);
// show T&Cs checkbox
if ($show_terms) {
$qa_content['form']['fields']['terms'] = array(
'type' => 'checkbox',
'label' => trim(qa_opt('register_terms')),
'tags' => 'name="terms" id="terms"',
'value' => qa_html(@$interms),
'error' => qa_html(@$errors['terms']),
);
}
$loginmodules = qa_load_modules_with('login', 'login_html'); $loginmodules = qa_load_modules_with('login', 'login_html');
foreach ($loginmodules as $module) { foreach ($loginmodules as $module) {
......
...@@ -27,47 +27,64 @@ class qa_filter_basic ...@@ -27,47 +27,64 @@ class qa_filter_basic
{ {
public function filter_email(&$email, $olduser) public function filter_email(&$email, $olduser)
{ {
if (!strlen($email)) if (!strlen($email)) {
return qa_lang('users/email_required'); return qa_lang('users/email_required');
}
if (!qa_email_validate($email)) if (!qa_email_validate($email)) {
return qa_lang('users/email_invalid'); return qa_lang('users/email_invalid');
}
if (qa_strlen($email)>QA_DB_MAX_EMAIL_LENGTH) if (qa_strlen($email) > QA_DB_MAX_EMAIL_LENGTH) {
return qa_lang_sub('main/max_length_x', QA_DB_MAX_EMAIL_LENGTH); return qa_lang_sub('main/max_length_x', QA_DB_MAX_EMAIL_LENGTH);
} }
}
public function filter_handle(&$handle, $olduser) public function filter_handle(&$handle, $olduser)
{ {
if (!strlen($handle)) if (!strlen($handle)) {
return qa_lang('users/handle_empty'); return qa_lang('users/handle_empty');
}
if (preg_match('/[\\@\\+\\/]/', $handle)) if (preg_match('/[\\@\\+\\/]/', $handle)) {
return qa_lang_sub('users/handle_has_bad', '@ + /'); return qa_lang_sub('users/handle_has_bad', '@ + /');
}
if (qa_strlen($handle)>QA_DB_MAX_HANDLE_LENGTH) if (qa_strlen($handle) > QA_DB_MAX_HANDLE_LENGTH) {
return qa_lang_sub('main/max_length_x', QA_DB_MAX_HANDLE_LENGTH); return qa_lang_sub('main/max_length_x', QA_DB_MAX_HANDLE_LENGTH);
} }
}
public function filter_question(&$question, &$errors, $oldquestion) public function filter_question(&$question, &$errors, $oldquestion)
{ {
$this->validate_length($errors, 'title', @$question['title'], qa_opt('min_len_q_title'), if ($oldquestion === null) {
max(qa_opt('min_len_q_title'), min(qa_opt('max_len_q_title'), QA_DB_MAX_TITLE_LENGTH))); // a new post requires these fields be set
$question['title'] = isset($question['title']) ? $question['title'] : '';
$question['content'] = isset($question['content']) ? $question['content'] : '';
$question['text'] = isset($question['text']) ? $question['text'] : '';
$question['tags'] = isset($question['tags']) ? $question['tags'] : array();
}
$this->validate_length($errors, 'content', @$question['content'], 0, QA_DB_MAX_CONTENT_LENGTH); // for storage $qminlength = qa_opt('min_len_q_title');
$qmaxlength = max($qminlength, min(qa_opt('max_len_q_title'), QA_DB_MAX_TITLE_LENGTH));
$this->validate_field_length($errors, $question, 'title', $qminlength, $qmaxlength);
$this->validate_length($errors, 'content', @$question['text'], qa_opt('min_len_q_content'), null); // for display $this->validate_field_length($errors, $question, 'content', 0, QA_DB_MAX_CONTENT_LENGTH); // for storage
$this->validate_field_length($errors, $question, 'text', qa_opt('min_len_q_content'), null); // for display
if (isset($question['tags'])) { if (isset($question['tags'])) {
$counttags=count($question['tags']); $counttags = count($question['tags']);
$mintags=min(qa_opt('min_num_q_tags'), qa_opt('max_num_q_tags')); $maxtags = qa_opt('max_num_q_tags');
$mintags = min(qa_opt('min_num_q_tags'), $maxtags);
if ($counttags<$mintags) if ($counttags < $mintags) {
$errors['tags']=qa_lang_sub('question/min_tags_x', $mintags); $errors['tags'] = qa_lang_sub('question/min_tags_x', $mintags);
elseif ($counttags>qa_opt('max_num_q_tags')) }
$errors['tags']=qa_lang_sub('question/max_tags_x', qa_opt('max_num_q_tags')); elseif ($counttags > $maxtags) {
else $errors['tags'] = qa_lang_sub('question/max_tags_x', $maxtags);
$this->validate_length($errors, 'tags', qa_tags_to_tagstring($question['tags']), 0, QA_DB_MAX_TAGS_LENGTH); // for storage }
else {
$tagstring = qa_tags_to_tagstring($question['tags']);
if (qa_strlen($tagstring) > QA_DB_MAX_TAGS_LENGTH) { // for storage
$errors['tags'] = qa_lang_sub('main/max_length_x', $maxlength);
}
}
} }
$this->validate_post_email($errors, $question); $this->validate_post_email($errors, $question);
...@@ -75,32 +92,34 @@ class qa_filter_basic ...@@ -75,32 +92,34 @@ class qa_filter_basic
public function filter_answer(&$answer, &$errors, $question, $oldanswer) public function filter_answer(&$answer, &$errors, $question, $oldanswer)
{ {
$this->validate_length($errors, 'content', @$answer['content'], 0, QA_DB_MAX_CONTENT_LENGTH); // for storage $this->validate_field_length($errors, $answer, 'content', 0, QA_DB_MAX_CONTENT_LENGTH); // for storage
$this->validate_length($errors, 'content', @$answer['text'], qa_opt('min_len_a_content'), null); // for display $this->validate_field_length($errors, $answer, 'text', qa_opt('min_len_a_content'), null, 'content'); // for display
$this->validate_post_email($errors, $answer); $this->validate_post_email($errors, $answer);
} }
public function filter_comment(&$comment, &$errors, $question, $parent, $oldcomment) public function filter_comment(&$comment, &$errors, $question, $parent, $oldcomment)
{ {
$this->validate_length($errors, 'content', @$comment['content'], 0, QA_DB_MAX_CONTENT_LENGTH); // for storage $this->validate_field_length($errors, $comment, 'content', 0, QA_DB_MAX_CONTENT_LENGTH); // for storage
$this->validate_length($errors, 'content', @$comment['text'], qa_opt('min_len_c_content'), null); // for display $this->validate_field_length($errors, $comment, 'text', qa_opt('min_len_a_content'), null, 'content'); // for display
$this->validate_post_email($errors, $comment); $this->validate_post_email($errors, $comment);
} }
public function filter_profile(&$profile, &$errors, $user, $oldprofile) public function filter_profile(&$profile, &$errors, $user, $oldprofile)
{ {
foreach ($profile as $field => $value) foreach (array_keys($profile) as $field) {
$this->validate_length($errors, $field, $value, 0, QA_DB_MAX_PROFILE_CONTENT_LENGTH); // ensure fields are not NULL
$profile[$field] = (string) $profile[$field];
$this->validate_field_length($errors, $profile, $field, 0, QA_DB_MAX_CONTENT_LENGTH);
}
} }
// The definitions below are not part of a standard filter module, but just used within this one // The definitions below are not part of a standard filter module, but just used within this one
/** /**
* Add textual element $field to $errors if length of $input is not between $minlength and $maxlength. * Add textual element $field to $errors if length of $input is not between $minlength and $maxlength.
* *
* @deprecated This function will become private in Q2A 1.8. It is specific to this plugin and * @deprecated This function is no longer used and will removed in the future.
* should not be used by outside code.
*/ */
public function validate_length(&$errors, $field, $input, $minlength, $maxlength) public function validate_length(&$errors, $field, $input, $minlength, $maxlength)
{ {
...@@ -113,6 +132,34 @@ class qa_filter_basic ...@@ -113,6 +132,34 @@ class qa_filter_basic
} }
/** /**
* Check that a field meets the length requirements. If we're editing the post we can ignore missing fields.
*
* @param array $errors Array of errors, with keys matching $post
* @param array $post The post containing the field we want to validate
* @param string $key The element of $post to validate
* @param int $minlength
* @param int $maxlength
*/
private function validate_field_length(&$errors, &$post, $key, $minlength, $maxlength, $errorKey=null)
{
if (!$errorKey) {
$errorKey = $key;
}
// skip the field is key not set (for example, 'title' when recategorizing questions)
if (array_key_exists($key, $post)) {
$length = qa_strlen($post[$key]);
if ($length < $minlength) {
$errors[$errorKey] = $minlength == 1 ? qa_lang('main/field_required') : qa_lang_sub('main/min_length_x', $minlength);
}
else if (isset($maxlength) && ($length > $maxlength)) {
$errors[$errorKey] = qa_lang_sub('main/max_length_x', $maxlength);
}
}
}
/**
* Wrapper function for validating a post's email address. * Wrapper function for validating a post's email address.
* *
* @deprecated This function will become private in Q2A 1.8. It is specific to this plugin and * @deprecated This function will become private in Q2A 1.8. It is specific to this plugin and
...@@ -121,9 +168,10 @@ class qa_filter_basic ...@@ -121,9 +168,10 @@ class qa_filter_basic
public function validate_post_email(&$errors, $post) public function validate_post_email(&$errors, $post)
{ {
if (@$post['notify'] && strlen(@$post['email'])) { if (@$post['notify'] && strlen(@$post['email'])) {
$error=$this->filter_email($post['email'], null); $error = $this->filter_email($post['email'], null);
if (isset($error)) if (isset($error)) {
$errors['email']=$error; $errors['email'] = $error;
}
} }
} }
} }
...@@ -522,6 +522,11 @@ ...@@ -522,6 +522,11 @@
'widgets' => array(), 'widgets' => array(),
); );
// add meta description if we're on the home page
if ($request === '' || $request === array_search('', qa_get_request_map())) {
$qa_content['description'] = qa_html(qa_opt('home_description'));
}
if (qa_opt('show_custom_in_head')) if (qa_opt('show_custom_in_head'))
$qa_content['head_lines'][]=qa_opt('custom_in_head'); $qa_content['head_lines'][]=qa_opt('custom_in_head');
......
...@@ -751,7 +751,7 @@ class qa_html_theme_base ...@@ -751,7 +751,7 @@ class qa_html_theme_base
} }
// add closed note in title // add closed note in title
if (!empty($q_view['closed'])) if (!empty($q_view['closed']['state']))
$this->output(' ['.$q_view['closed']['state'].']'); $this->output(' ['.$q_view['closed']['state'].']');
} }
...@@ -1637,7 +1637,7 @@ class qa_html_theme_base ...@@ -1637,7 +1637,7 @@ class qa_html_theme_base
'<div class="qa-q-item-title">', '<div class="qa-q-item-title">',
'<a href="'.$q_item['url'].'">'.$q_item['title'].'</a>', '<a href="'.$q_item['url'].'">'.$q_item['title'].'</a>',
// add closed note in title // add closed note in title
empty($q_item['closed']) ? '' : ' ['.$q_item['closed']['state'].']', empty($q_item['closed']['state']) ? '' : ' ['.$q_item['closed']['state'].']',
'</div>' '</div>'
); );
} }
......
...@@ -22,14 +22,11 @@ ...@@ -22,14 +22,11 @@
class qa_facebook_login_page class qa_facebook_login_page
{ {
private $directory; private $directory;
private $urltoroot;
public function load_module($directory, $urltoroot) public function load_module($directory, $urltoroot)
{ {
$this->directory=$directory; $this->directory=$directory;
$this->urltoroot=$urltoroot;
} }
public function match_request($request) public function match_request($request)
......
...@@ -33,4 +33,7 @@ CKEDITOR.editorConfig = function( config ) { ...@@ -33,4 +33,7 @@ CKEDITOR.editorConfig = function( config ) {
// Use native spell checking (note: Ctrl+right-click is required for native context menu) // Use native spell checking (note: Ctrl+right-click is required for native context menu)
config.disableNativeSpellChecker = false; config.disableNativeSpellChecker = false;
// Prevent blank paragraphs
config.fillEmptyBlocks = false;
}; };
...@@ -137,8 +137,6 @@ class qa_xml_sitemap ...@@ -137,8 +137,6 @@ class qa_xml_sitemap
{ {
@ini_set('display_errors', 0); // we don't want to show PHP errors inside XML @ini_set('display_errors', 0); // we don't want to show PHP errors inside XML
$siteurl=qa_opt('site_url');
header('Content-type: text/xml; charset=utf-8'); header('Content-type: text/xml; charset=utf-8');
echo '<?xml version="1.0" encoding="UTF-8"?>'."\n"; echo '<?xml version="1.0" encoding="UTF-8"?>'."\n";
...@@ -262,9 +260,6 @@ class qa_xml_sitemap ...@@ -262,9 +260,6 @@ class qa_xml_sitemap
} }
} }
// Finish up...
echo "</urlset>\n"; echo "</urlset>\n";
return null; return null;
......
...@@ -2030,7 +2030,7 @@ input[type="submit"], button { ...@@ -2030,7 +2030,7 @@ input[type="submit"], button {
margin-top: 0; margin-top: 0;
} }
#level .qa-form-wide-static a { #level .qa-form-wide-static a:first-child {
background-color: #27ae60; background-color: #27ae60;
background-image: url('images/icons/mail-white.png'); background-image: url('images/icons/mail-white.png');
background-repeat: no-repeat; background-repeat: no-repeat;
...@@ -2040,7 +2040,7 @@ input[type="submit"], button { ...@@ -2040,7 +2040,7 @@ input[type="submit"], button {
display: inline-block; display: inline-block;
color: #fff; color: #fff;
} }
#level .qa-form-wide-static a:hover, #level .qa-form-wide-static a:focus { #level .qa-form-wide-static a:hover:first-child, #level .qa-form-wide-static a:focus:first-child {
background-color: #2ecc71; background-color: #2ecc71;
background-image: url('images/icons/mail-white.png'); background-image: url('images/icons/mail-white.png');
border: 1px solid #25a25a; border: 1px solid #25a25a;
......
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