Fix one design failure in phpBB3. Do not count non-approved posts to the user_posts. Before, a user was able to circumvent basically any protection based on post counts.

At the same time implement the queue_trigger feature.

git-svn-id: file:///svn/phpbb/branches/phpBB-3_0_0@8805 89ea8834-ac86-4346-8a33-228a782c2dd0
This commit is contained in:
Meik Sievertsen 2008-09-02 06:36:24 +00:00
parent 7f813a9ef6
commit 5c4870fcce
8 changed files with 72 additions and 28 deletions

View file

@ -1647,7 +1647,8 @@ class acp_forums
$sql = 'SELECT poster_id $sql = 'SELECT poster_id
FROM ' . POSTS_TABLE . ' FROM ' . POSTS_TABLE . '
WHERE forum_id = ' . $forum_id . ' WHERE forum_id = ' . $forum_id . '
AND post_postcount = 1'; AND post_postcount = 1
AND post_approved = 1';
$result = $db->sql_query($sql); $result = $db->sql_query($sql);
$post_counts = array(); $post_counts = array();
@ -1768,6 +1769,7 @@ class acp_forums
WHERE user_id = ' . $poster_id . ' WHERE user_id = ' . $poster_id . '
AND user_posts < ' . $substract; AND user_posts < ' . $substract;
$db->sql_query($sql); $db->sql_query($sql);
$sql = 'UPDATE ' . USERS_TABLE . ' $sql = 'UPDATE ' . USERS_TABLE . '
SET user_posts = user_posts - ' . $substract . ' SET user_posts = user_posts - ' . $substract . '
WHERE user_id = ' . $poster_id . ' WHERE user_id = ' . $poster_id . '

View file

@ -186,7 +186,7 @@ class acp_main
$sql = 'SELECT COUNT(p.post_id) AS num_posts, u.user_id $sql = 'SELECT COUNT(p.post_id) AS num_posts, u.user_id
FROM ' . USERS_TABLE . ' u FROM ' . USERS_TABLE . ' u
LEFT JOIN ' . POSTS_TABLE . ' p ON (u.user_id = p.poster_id AND p.post_postcount = 1) LEFT JOIN ' . POSTS_TABLE . ' p ON (u.user_id = p.poster_id AND p.post_postcount = 1 AND p.post_approved = 1)
GROUP BY u.user_id'; GROUP BY u.user_id';
$result = $db->sql_query($sql); $result = $db->sql_query($sql);

View file

@ -670,7 +670,7 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
$topic_ids[] = $row['topic_id']; $topic_ids[] = $row['topic_id'];
$forum_ids[] = $row['forum_id']; $forum_ids[] = $row['forum_id'];
if ($row['post_postcount'] && $post_count_sync) if ($row['post_postcount'] && $post_count_sync && $row['post_approved'])
{ {
$post_counts[$row['poster_id']] = (!empty($post_counts[$row['poster_id']])) ? $post_counts[$row['poster_id']] + 1 : 1; $post_counts[$row['poster_id']] = (!empty($post_counts[$row['poster_id']])) ? $post_counts[$row['poster_id']] + 1 : 1;
} }
@ -709,6 +709,7 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
WHERE user_id = ' . $poster_id . ' WHERE user_id = ' . $poster_id . '
AND user_posts < ' . $substract; AND user_posts < ' . $substract;
$db->sql_query($sql); $db->sql_query($sql);
$sql = 'UPDATE ' . USERS_TABLE . ' $sql = 'UPDATE ' . USERS_TABLE . '
SET user_posts = user_posts - ' . $substract . ' SET user_posts = user_posts - ' . $substract . '
WHERE user_id = ' . $poster_id . ' WHERE user_id = ' . $poster_id . '

View file

@ -1744,6 +1744,7 @@ function sync_post_count($offset, $limit)
$sql = 'SELECT COUNT(post_id) AS num_posts, poster_id $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id
FROM ' . POSTS_TABLE . ' FROM ' . POSTS_TABLE . '
WHERE post_postcount = 1 WHERE post_postcount = 1
AND post_approved = 1
GROUP BY poster_id GROUP BY poster_id
ORDER BY poster_id'; ORDER BY poster_id';
$result = $db->sql_query_limit($sql, $limit, $offset); $result = $db->sql_query_limit($sql, $limit, $offset);

View file

@ -1605,10 +1605,18 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
$data['post_approved'] = $topic_row['post_approved']; $data['post_approved'] = $topic_row['post_approved'];
} }
// This variable indicates if the user is able to post or put into the queue - it is used later for all code decisions regarding approval
$post_approval = 1;
// Check the permissions for post approval, as well as the queue trigger where users are put on approval with a post count lower than specified. Moderators are not affected.
if (($config['enable_queue_trigger'] && $user->data['user_posts'] < $config['queue_trigger_posts'] && !$auth->acl_get('m_approve', $data['forum_id'])) || !$auth->acl_get('f_noapprove', $data['forum_id']))
{
$post_approval = 0;
}
// Start the transaction here // Start the transaction here
$db->sql_transaction('begin'); $db->sql_transaction('begin');
// Collect Information // Collect Information
switch ($post_mode) switch ($post_mode)
{ {
@ -1620,7 +1628,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
'icon_id' => $data['icon_id'], 'icon_id' => $data['icon_id'],
'poster_ip' => $user->ip, 'poster_ip' => $user->ip,
'post_time' => $current_time, 'post_time' => $current_time,
'post_approved' => (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id'])) ? 0 : 1, 'post_approved' => $post_approval,
'enable_bbcode' => $data['enable_bbcode'], 'enable_bbcode' => $data['enable_bbcode'],
'enable_smilies' => $data['enable_smilies'], 'enable_smilies' => $data['enable_smilies'],
'enable_magic_url' => $data['enable_urls'], 'enable_magic_url' => $data['enable_urls'],
@ -1686,7 +1694,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
'forum_id' => ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id'], 'forum_id' => ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id'],
'poster_id' => $data['poster_id'], 'poster_id' => $data['poster_id'],
'icon_id' => $data['icon_id'], 'icon_id' => $data['icon_id'],
'post_approved' => (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id'])) ? 0 : $data['post_approved'], 'post_approved' => (!$post_approval) ? 0 : $data['post_approved'],
'enable_bbcode' => $data['enable_bbcode'], 'enable_bbcode' => $data['enable_bbcode'],
'enable_smilies' => $data['enable_smilies'], 'enable_smilies' => $data['enable_smilies'],
'enable_magic_url' => $data['enable_urls'], 'enable_magic_url' => $data['enable_urls'],
@ -1720,7 +1728,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
'topic_time' => $current_time, 'topic_time' => $current_time,
'forum_id' => ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id'], 'forum_id' => ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id'],
'icon_id' => $data['icon_id'], 'icon_id' => $data['icon_id'],
'topic_approved' => (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id'])) ? 0 : 1, 'topic_approved' => $post_approval,
'topic_title' => $subject, 'topic_title' => $subject,
'topic_first_poster_name' => (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''), 'topic_first_poster_name' => (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''),
'topic_first_poster_colour' => $user->data['user_colour'], 'topic_first_poster_colour' => $user->data['user_colour'],
@ -1740,24 +1748,23 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
); );
} }
$sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id'])) ? ', user_posts = user_posts + 1' : ''); $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id']) && $post_approval) ? ', user_posts = user_posts + 1' : '');
if ($topic_type != POST_GLOBAL) if ($topic_type != POST_GLOBAL)
{ {
if ($auth->acl_get('f_noapprove', $data['forum_id']) || $auth->acl_get('m_approve', $data['forum_id'])) if ($post_approval)
{ {
$sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts + 1'; $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts + 1';
} }
$sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_real = forum_topics_real + 1' . (($auth->acl_get('f_noapprove', $data['forum_id']) || $auth->acl_get('m_approve', $data['forum_id'])) ? ', forum_topics = forum_topics + 1' : ''); $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_real = forum_topics_real + 1' . (($post_approval) ? ', forum_topics = forum_topics + 1' : '');
} }
break; break;
case 'reply': case 'reply':
$sql_data[TOPICS_TABLE]['stat'][] = 'topic_replies_real = topic_replies_real + 1, topic_bumped = 0, topic_bumper = 0' . (($auth->acl_get('f_noapprove', $data['forum_id']) || $auth->acl_get('m_approve', $data['forum_id'])) ? ', topic_replies = topic_replies + 1' : '') . ((!empty($data['attachment_data']) || (isset($data['topic_attachment']) && $data['topic_attachment'])) ? ', topic_attachment = 1' : ''); $sql_data[TOPICS_TABLE]['stat'][] = 'topic_replies_real = topic_replies_real + 1, topic_bumped = 0, topic_bumper = 0' . (($post_approval) ? ', topic_replies = topic_replies + 1' : '') . ((!empty($data['attachment_data']) || (isset($data['topic_attachment']) && $data['topic_attachment'])) ? ', topic_attachment = 1' : '');
$sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id']) && $post_approval) ? ', user_posts = user_posts + 1' : '');
$sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id'])) ? ', user_posts = user_posts + 1' : ''); if ($post_approval && $topic_type != POST_GLOBAL)
if (($auth->acl_get('f_noapprove', $data['forum_id']) || $auth->acl_get('m_approve', $data['forum_id'])) && $topic_type != POST_GLOBAL)
{ {
$sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts + 1'; $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts + 1';
} }
@ -1769,7 +1776,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
$sql_data[TOPICS_TABLE]['sql'] = array( $sql_data[TOPICS_TABLE]['sql'] = array(
'forum_id' => ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id'], 'forum_id' => ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id'],
'icon_id' => $data['icon_id'], 'icon_id' => $data['icon_id'],
'topic_approved' => (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id'])) ? 0 : $data['topic_approved'], 'topic_approved' => (!$post_approval) ? 0 : $data['topic_approved'],
'topic_title' => $subject, 'topic_title' => $subject,
'topic_first_poster_name' => $username, 'topic_first_poster_name' => $username,
'topic_type' => $topic_type, 'topic_type' => $topic_type,
@ -1784,7 +1791,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
); );
// Correctly set back the topic replies and forum posts... only if the topic was approved before and now gets disapproved // Correctly set back the topic replies and forum posts... only if the topic was approved before and now gets disapproved
if (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id']) && $data['topic_approved']) if (!$post_approval && $data['topic_approved'])
{ {
// Do we need to grab some topic informations? // Do we need to grab some topic informations?
if (!sizeof($topic_row)) if (!sizeof($topic_row))
@ -1806,6 +1813,12 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
set_config('num_topics', $config['num_topics'] - 1, true); set_config('num_topics', $config['num_topics'] - 1, true);
set_config('num_posts', $config['num_posts'] - ($topic_row['topic_replies'] + 1), true); set_config('num_posts', $config['num_posts'] - ($topic_row['topic_replies'] + 1), true);
// Only decrement this post, since this is the one non-approved now
if ($auth->acl_get('f_postcount', $data['forum_id']))
{
$sql_data[USERS_TABLE]['stat'][] = 'user_posts = user_posts - 1';
}
} }
break; break;
@ -1814,12 +1827,17 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
case 'edit_last_post': case 'edit_last_post':
// Correctly set back the topic replies and forum posts... but only if the post was approved before. // Correctly set back the topic replies and forum posts... but only if the post was approved before.
if (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id']) && $data['post_approved']) if (!$post_approval && $data['post_approved'])
{ {
$sql_data[TOPICS_TABLE]['stat'][] = 'topic_replies = topic_replies - 1'; $sql_data[TOPICS_TABLE]['stat'][] = 'topic_replies = topic_replies - 1';
$sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts - 1'; $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts - 1';
set_config('num_posts', $config['num_posts'] - 1, true); set_config('num_posts', $config['num_posts'] - 1, true);
if ($auth->acl_get('f_postcount', $data['forum_id']))
{
$sql_data[USERS_TABLE]['stat'][] = 'user_posts = user_posts - 1';
}
} }
break; break;
@ -2295,7 +2313,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
} }
// Update total post count, do not consider moderated posts/topics // Update total post count, do not consider moderated posts/topics
if ($auth->acl_get('f_noapprove', $data['forum_id']) || $auth->acl_get('m_approve', $data['forum_id'])) if ($post_approval)
{ {
if ($post_mode == 'post') if ($post_mode == 'post')
{ {
@ -2310,7 +2328,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
} }
// Update forum stats // Update forum stats
$where_sql = array(POSTS_TABLE => 'post_id = ' . $data['post_id'], TOPICS_TABLE => 'topic_id = ' . $data['topic_id'], FORUMS_TABLE => 'forum_id = ' . $data['forum_id'], USERS_TABLE => 'user_id = ' . $user->data['user_id']); $where_sql = array(POSTS_TABLE => 'post_id = ' . $data['post_id'], TOPICS_TABLE => 'topic_id = ' . $data['topic_id'], FORUMS_TABLE => 'forum_id = ' . $data['forum_id'], USERS_TABLE => 'user_id = ' . $poster_id);
foreach ($sql_data as $table => $update_ary) foreach ($sql_data as $table => $update_ary)
{ {
@ -2427,14 +2445,14 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
} }
// Send Notifications // Send Notifications
if ($mode != 'edit' && $mode != 'delete' && ($auth->acl_get('f_noapprove', $data['forum_id']) || $auth->acl_get('m_approve', $data['forum_id']))) if ($mode != 'edit' && $mode != 'delete' && $post_approval)
{ {
user_notification($mode, $subject, $data['topic_title'], $data['forum_name'], $data['forum_id'], $data['topic_id'], $data['post_id']); user_notification($mode, $subject, $data['topic_title'], $data['forum_name'], $data['forum_id'], $data['topic_id'], $data['post_id']);
} }
$params = $add_anchor = ''; $params = $add_anchor = '';
if ($auth->acl_get('f_noapprove', $data['forum_id']) || $auth->acl_get('m_approve', $data['forum_id'])) if ($post_approval)
{ {
$params .= '&amp;t=' . $data['topic_id']; $params .= '&amp;t=' . $data['topic_id'];

View file

@ -415,8 +415,8 @@ function change_poster(&$post_info, $userdata)
sync('forum', 'forum_id', $post_info['forum_id'], false, false); sync('forum', 'forum_id', $post_info['forum_id'], false, false);
} }
// Adjust post counts // Adjust post counts... only if the post is approved (else, it was not added the users post count anyway)
if ($post_info['post_postcount']) if ($post_info['post_postcount'] && $post_info['post_approved'])
{ {
$sql = 'UPDATE ' . USERS_TABLE . ' $sql = 'UPDATE ' . USERS_TABLE . '
SET user_posts = user_posts - 1 SET user_posts = user_posts - 1

View file

@ -481,6 +481,7 @@ function approve_post($post_id_list, $id, $mode)
$total_topics = $total_posts = 0; $total_topics = $total_posts = 0;
$forum_topics_posts = $topic_approve_sql = $topic_replies_sql = $post_approve_sql = $topic_id_list = $forum_id_list = $approve_log = array(); $forum_topics_posts = $topic_approve_sql = $topic_replies_sql = $post_approve_sql = $topic_id_list = $forum_id_list = $approve_log = array();
$user_posts_sql = array();
$update_forum_information = false; $update_forum_information = false;
@ -493,6 +494,9 @@ function approve_post($post_id_list, $id, $mode)
$forum_id_list[$post_data['forum_id']] = 1; $forum_id_list[$post_data['forum_id']] = 1;
} }
// User post update (we do not care about topic or post, since user posts are strictly connected to posts
$user_posts_sql[$post_data['poster_id']] = (empty($user_posts_sql[$post_data['poster_id']])) ? 1 : $user_posts_sql[$post_data['poster_id']] + 1;
// Topic or Post. ;) // Topic or Post. ;)
if ($post_data['topic_first_post_id'] == $post_id) if ($post_data['topic_first_post_id'] == $post_id)
{ {
@ -612,6 +616,25 @@ function approve_post($post_id_list, $id, $mode)
} }
} }
if (sizeof($user_posts_sql))
{
// Try to minimize the query count by merging users with the same post count additions
$user_posts_update = array();
foreach ($user_posts_sql as $user_id => $user_posts)
{
$user_posts_update[$user_posts][] = $user_id;
}
foreach ($user_posts_update as $user_posts => $user_id_ary)
{
$sql = 'UPDATE ' . USERS_TABLE . '
SET user_posts = user_posts + ' . $user_posts . '
WHERE ' . $db->sql_in_set('user_id', $user_id_ary);
$db->sql_query($sql);
}
}
if ($total_topics) if ($total_topics)
{ {
set_config('num_topics', $config['num_topics'] + $total_topics, true); set_config('num_topics', $config['num_topics'] + $total_topics, true);

View file

@ -999,10 +999,9 @@ if ($submit || $preview || $refresh)
} }
$redirect_url = submit_post($mode, $post_data['post_subject'], $post_data['username'], $post_data['topic_type'], $poll, $data, $update_message); $redirect_url = submit_post($mode, $post_data['post_subject'], $post_data['username'], $post_data['topic_type'], $poll, $data, $update_message);
$post_need_approval = (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id'])) ? true : false;
// If the post need approval we will wait a lot longer. // Check the permissions for post approval, as well as the queue trigger where users are put on approval with a post count lower than specified. Moderators are not affected.
if ($post_need_approval) if (($config['enable_queue_trigger'] && $user->data['user_posts'] < $config['queue_trigger_posts'] && !$auth->acl_get('m_approve', $data['forum_id'])) || !$auth->acl_get('f_noapprove', $data['forum_id']))
{ {
meta_refresh(10, $redirect_url); meta_refresh(10, $redirect_url);
$message = ($mode == 'edit') ? $user->lang['POST_EDITED_MOD'] : $user->lang['POST_STORED_MOD']; $message = ($mode == 'edit') ? $user->lang['POST_EDITED_MOD'] : $user->lang['POST_STORED_MOD'];