Быстрый лёгкий надёжный форумный движок
Вы не вошли.
Рассмотрим такую ситуацию: некий пользователь нарушил порядок. Не настолько чтобы его забанили и удалили, а просто доставляет неудобства. Например игнорирует поиск и регулярно пишет не в тот раздел.
Хорошо бы ему сделать замечание так, чтобы он увидел.
* Для всех: выводить яркий блок с замечанием возле проблемного сообщенияи
* Для пользователя лично: при входе пользователя в систему выдавать ему поп-ап, что есть непрочитанные замечания - со ссылкой.
* Замечания не обсуждаются, это руководство к действию. "Личные сообщения" не подходят для этой задачи.
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
Яростно плюсую! Очень нужно!
Offline
Добавляем в таблицу постов логическое поле "замечание включено".
Сразу же возникает вопрос: Должен ли тут записываться человек, который выставил замечание? Т.е. еще одно поле добавится.
Или делаем доступность выставления замечания через редактирование поста? Для админов и модераторов. А при сохранении такого поста после редактирования выскачит форма ввода текста замечания, если выставлена галка "замечание включено".
А саму таблицу замечаний можно поаналогии с Просигналить сделать, только пользователи видят только свои замечания.
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
Можно без поля "замечание включено". Или я чего-то не догнал.
Если сделать таблицу замечаний (notes) аналогично таблице posts, записывать в notes.topic_id и notes.id копии полей из posts?
Запрос для viewtopic усложняем еще одним join чтобы добыть замечания
SELECT p.*, n.message AS note
FROM posts AS p
LEFT JOIN notes AS n ON n.id=p.id
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
Т.е. предлагаешь тут же юзеру выводить замечание внизу поста!?
Можно и так, но не появятся ли от этого дополнительные общие тормоза т.к. у каждого пользователя будет проверка при просмотре тем.
Я же предлагал в теме просто значек предупреждения из поля таблицы постов, а сами предупреждения отдельно совершенно.
т.е. вот так вот наглядно тебе не нравится?
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
Накладные расходы минимальные, эффект максимальный: Если предупреждение будет привязано к конкретному посту, будет видно что именно не так, будет возможность сделать несколько замечаний в одной теме одному или разным пользователям. Для вычисления прочитанности замечания можно использовать тот же механизм, что определяет прочитанность темы. В таблицу постов не надо ничего добавлять.
По стилевому оформлению: можно выводить текст замечания внутри блока с сообщением, вводим доп. класс CSS .note
<div class="postright">
<h3>Re: Проблема</h3>
<div class="postmsg">
<p>Не работает
</p>
<div class="note">
<p>Мы не телепаты. Конкретизируй!</p>
</div>
</div>
</div>
viewtopic, место считывания постов. (сокращаю лишнее)
// Retrieve the posts (and their respective poster/online status)
$result = $db->query('SELECT u.email, u.title, ... p.id, p.poster AS username, ... n.message AS note FROM '.$db->prefix.'posts AS p LEFT JOIN '.$db->prefix.'notes AS n ON n.id=p.id ...', true) or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
while ($cur_post = $db->fetch_assoc($result))
{
viewtopic, место подготовки текста поста
$cur_post['message'] = parse_message($cur_post['message'], $cur_post['hide_smilies']);
if ($cur_post['note'])
$cur_post['message'] .= '<div class="note">' . parse_message($cur_post['note'], false) . '</div>';
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
Теперь как определить читал пользователь замечание или нет. Примерно также как определяется прочитанность темы. Есть функция get_tracked_topics(). Все, что нам надо про нее знать — она возвращает двумерный массив:
$tracked_topics['forums'] = {
id_раздела => время_прочтения — пользователь делал "Пометить доску как прочтённую"
}
$tracked_topics['topics'] = {
id_темы => время_прочтения — пользователь заходил в тему
}
Хотите подробнее — ищите свово tracked_topics в viewforum.php, там увидите как оно используется.
Нам надо
получить массив замечаний к постам, где автор - этот пользователь
сравнить время замечаний с tracked_topics
Запрос (сокращаю лишнее). Здесь INNER JOIN notes, а не LEFT JOIN как в предыдущем посте!!!
Возвращаем информацию о замечаниях текущему пользователю. Ограничиваю срок давности, мы не должны всякий раз заглядывать на годы назад, пусть будет срок не старше 1 месяца.
"SELECT t.forum_id, p.topic_id, p.id, n.posted
FROM posts AS p ...
INNER JOIN notes AS n ...
INNER JOIN topics AS t ...
WHERE p.poster_id = " . $pun_user['id'] . "
AND n.posted > " . time() - 2592000
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
Это в официальном FluxBB будет? Если нет очень хотелось бы увидеть в сборке...
Offline
Мы не решаем такие вопросы, можем только предложить. Для начала надо создать работоспособный мод.
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
up. напоминаю себе, что надо реализовать мод здесь
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
up. напоминаю себе, что надо реализовать мод здесь
Все-таки его сделаешь?
Не веришь? :) Мужик сказал - мужик сделал!
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
Теперь подумаем как оформить форму для ввода замечания. Мне кажется можно просто взять стандартный edit.php и добавить туда проверку "редактирует не владелец, а модератор" и новое поле.
Модератор уже имеет право вносить правки в чужие сообщения (ну например он может удалить рекламную ссылку, если считает необходимым). Добавим в форму <input type="text" ...> для замечания. textarea будет слишком жирно, IMHO.
Если редактировал модератор и если строка непустая, в момент сохранения сообщения будем делать REPLACE для таблицы notes. Если пустая — DELETE.
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
Теперь подумаем как оформить форму для ввода замечания. Мне кажется можно просто взять стандартный edit.php и добавить туда проверку "редактирует не владелец, а модератор" и новое поле.
Согласен.
Но тут надо и проверку изменения самого сообщения делать, чтобы лишний раз не писать, что сообщение отредактировано...
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
Угу. Можно сделать так: чтобы заново не считывать оригинальное сообщение для проверки, можно проверять контрольную сумму от message. Эту контрольную сумму вставлять в hidden поле формы.
Фигню сказал. Данные всё равно считываются. Незачем считать чексум. Надо просто сравнивать $message и $cur_post['message'] и т.п.
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
Как оно работает видно в посте выше
Прежде чем оформить мод, предлагаю погонять так. Выолните такой запрос в phpmyadmin:
CREATE TABLE `prefix_warnings` (
`id` INT( 10 ) NOT NULL ,
`poster` VARCHAR( 200 ) NOT NULL ,
`poster_id` INT( 10 ) NOT NULL ,
`posted` INT( 10 ) NOT NULL ,
`message` TEXT NOT NULL ,
PRIMARY KEY ( `id` )
) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
Конечно "prefix_" замените на своё, возможно ENGINE = MYISAM на innodb, это уж у кого как.
Затем, примените такой патч к viewtopic.php:
--- C:/TEMP/fluxbb142/viewtopic.php Mon Aug 09 12:07:42 2010
+++ Z:/home/test1.ru/flux/viewtopic.php Sat Oct 30 14:48:27 2010
@@ -204,6 +204,14 @@
for ($i = 0;$cur_post_id = $db->result($result, $i);$i++)
$post_ids[] = $cur_post_id;
+// Retrieve moderator's warnings
+$result = $db->query('SELECT w.id, w.message FROM '.$db->prefix.'warnings AS w WHERE w.id IN ('.implode(',', $post_ids).')', true) or error('Unable to fetch warnings', __FILE__, __LINE__, $db->error());
+$warnings = array();
+while ($warning = $db->fetch_assoc($result))
+{
+ $warnings[$warning['id']] = $warning['message'];
+}
+
// Retrieve the posts (and their respective poster/online status)
$result = $db->query('SELECT u.email, u.title, u.url, u.location, u.signature, u.email_setting, u.num_posts, u.registered, u.admin_note, p.id, p.poster AS username, p.poster_id, p.poster_ip, p.poster_email, p.message, p.hide_smilies, p.posted, p.edited, p.edited_by, g.g_id, g.g_user_title, o.user_id AS is_online FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'users AS u ON u.id=p.poster_id INNER JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id LEFT JOIN '.$db->prefix.'online AS o ON (o.user_id=u.id AND o.user_id!=1 AND o.idle=0) WHERE p.id IN ('.implode(',', $post_ids).') ORDER BY p.id', true) or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
while ($cur_post = $db->fetch_assoc($result))
@@ -322,6 +330,8 @@
// Perform the main parsing of the message (BBCode, smilies, censor words etc)
$cur_post['message'] = parse_message($cur_post['message'], $cur_post['hide_smilies']);
+ // Parse moderator's warning if any
+ $cur_post['warning'] = isset($warnings[$cur_post['id']]) ? parse_message($warnings[$cur_post['id']], false) : null;
// Do signature parsing/caching
if ($pun_config['o_signatures'] == '1' && $cur_post['signature'] != '' && $pun_user['show_sig'] != '0')
@@ -356,6 +366,11 @@
<?php echo $cur_post['message']."\n" ?>
<?php if ($cur_post['edited'] != '') echo "\t\t\t\t\t\t".'<p class="postedit"><em>'.$lang_topic['Last edit'].' '.pun_htmlspecialchars($cur_post['edited_by']).' ('.format_time($cur_post['edited']).')</em></p>'."\n"; ?>
</div>
+<?php if (!is_null($cur_post['warning'])): ?>
+ <div class="postwarn">
+ <?php echo $cur_post['warning']."\n" ?>
+ </div>
+<?php endif; ?>
<?php if ($signature != '') echo "\t\t\t\t\t".'<div class="postsignature postmsg"><hr />'.$signature.'</div>'."\n"; ?>
</div>
</div>
Изменить edit.php
--- C:/TEMP/fluxbb142/edit.php Mon Aug 09 12:07:42 2010
+++ Z:/home/test1.ru/flux/edit.php Sat Oct 30 15:48:32 2010
@@ -19,7 +19,7 @@
message($lang_common['Bad request']);
// Fetch some info about the post, the topic and the forum
-$result = $db->query('SELECT f.id AS fid, f.forum_name, f.moderators, f.redirect_url, fp.post_replies, fp.post_topics, t.id AS tid, t.subject, t.posted, t.first_post_id, t.closed, p.poster, p.poster_id, p.message, p.hide_smilies FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON t.id=p.topic_id INNER JOIN '.$db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND p.id='.$id) or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+$result = $db->query('SELECT f.id AS fid, f.forum_name, f.moderators, f.redirect_url, fp.post_replies, fp.post_topics, t.id AS tid, t.subject, t.posted, t.first_post_id, t.closed, p.poster, p.poster_id, p.message, p.hide_smilies, w.message AS warning FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON t.id=p.topic_id INNER JOIN '.$db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$db->prefix.'warnings AS w ON p.id=w.id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND p.id='.$id) or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
if (!$db->num_rows($result))
message($lang_common['Bad request']);
@@ -67,6 +67,8 @@
$errors[] = $lang_post['Too long subject'];
else if ($pun_config['p_subject_all_caps'] == '0' && is_all_uppercase($subject) && !$pun_user['is_admmod'])
$errors[] = $lang_post['All caps subject'];
+ } else {
+ $subject = $cur_post['subject'];
}
// Clean up message from POST
@@ -93,11 +95,13 @@
// Did everything go according to plan?
if (empty($errors) && !isset($_POST['preview']))
{
+ $is_modified = $subject != $cur_post['subject'] || $message != $cur_post['message'] || $hide_smilies != $cur_post['hide_smilies'];
+
$edited_sql = (!isset($_POST['silent']) || !$is_admmod) ? $edited_sql = ', edited='.time().', edited_by=\''.$db->escape($pun_user['username']).'\'' : '';
require PUN_ROOT.'include/search_idx.php';
- if ($can_edit_subject)
+ if ($is_modified && $can_edit_subject)
{
// Update the topic and any redirect topics
$db->query('UPDATE '.$db->prefix.'topics SET subject=\''.$db->escape($subject).'\' WHERE id='.$cur_post['tid'].' OR moved_to='.$cur_post['tid']) or error('Unable to update topic', __FILE__, __LINE__, $db->error());
@@ -108,8 +112,24 @@
else
update_search_index('edit', $id, $message);
- // Update the post
- $db->query('UPDATE '.$db->prefix.'posts SET message=\''.$db->escape($message).'\', hide_smilies='.$hide_smilies.$edited_sql.' WHERE id='.$id) or error('Unable to update post', __FILE__, __LINE__, $db->error());
+ if ($is_admmod)
+ {
+ $warning = pun_linebreaks(pun_trim($_POST['warning']));
+ if ($warning != $cur_post['warning'])
+ {
+ $db->query('DELETE FROM '.$db->prefix.'warnings WHERE id='.$id) or error('Unable to remove warning', __FILE__, __LINE__, $db->error());
+ if (strlen($_POST['warning']) > 0 )
+ {
+ $db->query('INSERT INTO '.$db->prefix.'warnings (id, poster, poster_id, posted, message) VALUES('.$id.', \''.$db->escape($pun_user['username']).'\', '.$pun_user['id'].', '.time().', \''.$db->escape($_POST['warning']).'\')') or error('Unable to insert warning', __FILE__, __LINE__, $db->error());
+ }
+ }
+ }
+
+ if ($is_modified)
+ {
+ // Update the post
+ $db->query('UPDATE '.$db->prefix.'posts SET message=\''.$db->escape($message).'\', hide_smilies='.$hide_smilies.$edited_sql.' WHERE id='.$id) or error('Unable to update post', __FILE__, __LINE__, $db->error());
+ }
redirect('viewtopic.php?pid='.$id.'#p'.$id, $lang_post['Edit redirect']);
}
@@ -207,6 +227,13 @@
<li><span><a href="help.php#img" onclick="window.open(this.href); return false;"><?php echo $lang_common['img tag'] ?></a> <?php echo ($pun_config['p_message_img_tag'] == '1') ? $lang_common['on'] : $lang_common['off']; ?></span></li>
<li><span><a href="help.php#smilies" onclick="window.open(this.href); return false;"><?php echo $lang_common['Smilies'] ?></a> <?php echo ($pun_config['o_smilies'] == '1') ? $lang_common['on'] : $lang_common['off']; ?></span></li>
</ul>
+<?php if ($is_admmod): ?> <label><strong><?php echo $lang_common['Moderator'] ?></strong><br />
+ <input class="longinput" type="text" name="warning" size="80" maxlength="70" tabindex="<?php echo $cur_index++ ?>" value="<?php echo pun_htmlspecialchars(isset($_POST['warning']) ? $_POST['warning'] : $cur_post['warning']) ?>" /><br /></label>
+<?php elseif ($cur_post['warning'] != ''): ?>
+ <div class="postwarn">
+ <?php echo $cur_post['warning']."\n" ?>
+ </div>
+<?php endif; ?>
</div>
</fieldset>
<?php
Поправьте стиль Air.css
--- C:/TEMP/fluxbb142/style/Air.css Mon Aug 09 12:07:42 2010
+++ Z:/home/test1.ru/flux/style/Air.css Sat Oct 30 14:46:07 2010
@@ -1603,4 +1603,12 @@
.pun .inew .icon {
border-color: #91b3d9 #87a8d1 #6c85bb #7292c3;
+}
+
+/* Extra markup
+----------------------------------------------------------------*/
+.pun .postwarn {
+ border-left: 4px solid #e99;
+ background-color: #fee;
+ padding-left: 1em;
}
\ No newline at end of file
Скачать:
Файлы патчей: http://rapidshare.com/files/427925156/mod_warnings.zip
или готовые файлы: http://rapidshare.com/files/427925454/m … _files.zip
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
Новая версия стиля для "замечания" (установлено здесь):
/* Moderator's warnings
----------------------------------------------------------------*/
.pun .postwarn {
background: none repeat scroll 0 0 #fff0f0;
border-style: solid;
border-width: 1px 1px 1px 3px;
border-color: #e99;
margin: 0.75em 0 0.75em 2em;
padding: 0 0.75em;
}
.pun .postwarn:before {
content: "M";
position: absolute;
margin-left: -2em;
margin-top: 0.3em;
font-size: 150%;
font-weight: bold;
color: #e99;
}
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
И вот ещё придумал поиск предупреждений пользователю (action=show_user_warn):
Глянем что там у Visman? - потом уберу. или сам, как админ отредактируй. кстати! я добавил фичу чтобы в момент сохранения после edit проверялось действительно ли были изменения.
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
Т.е. сообщение модератора будут видеть все юзеры, а не администрация и тот, кому оно предназначено.
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
Конечно. Я так задумывал с самого начала. Единственно что хочу заточить под конкретного пользователя - это оповещение, аналогичное "есть новые сигналы", а там ссылка как я привел выше.
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
Отлично. Как обычно утащим свежие решения в punbb
В дальнейшем можно блокировать юзеров автоматически на основе количества таких предупреждений, где-то был мод.
Offline
artoodetoo, в viewtopic.php ты сначала предлагал добавить к основному запросу запрос к таблице предупреждений, а сделал его отдельным. Так быстрее?
По поводу оповещения: создаем в базе юзеров дополнительное поле для флага, при правке модератором сообщения и добавлении предупреждения автору сообщения в это поле выставляется true, при открытии этим юзером форума выскакивает предупреждение, что у Вас новое предупреждение и ссылка .../forum/search.php?action=show_user_warn (без user_id будут открываться предупреждения данного юзера).
Редактировался Visman (2010-10-31 10:37:41)
Я такое всплывание подсказки о новом сообщении хочу добавить в ЛС, но с силами пока не собрался ;)
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
artoodetoo, в viewtopic.php ты сначала предлагал добавить к основному запросу запрос к таблице предупреждений, а сделал его отдельным. Так быстрее?
Не уверен насчет скорости, надо проверять. Я вначале предполагал, что будут возможны несколько замечаний на один пост, при таком раскладе без отдельного запроса никак. Получилось попроще, а запрос остался.
По поводу оповещения: создаем в базе юзеров дополнительное поле для флага, при правке модератором сообщения и добавлении предупреждения автору сообщения в это поле выставляется true, при открытии этим юзером форума выскакивает предупреждение, что у Вас новое предупреждение и ссылка .../forum/search.php?action=show_user_warn (без user_id будут открываться предупреждения данного юзера).
Может быть не true, а время. Тогда будет возможность показать все, но выделить свежие замечания в поисковой выдаче.
Ммм... тогда получается надо две метки времени: время последнего замечание и время последнего вызова поиска замечаний.
Маленький оффтопик:
Мне часто хочется завести отдельную таблицу пользовательских счетчиков, чтобы профиль не пух и чтобы кеш запросов в MySql не сбрасывался при обновлении счетчика. Поясню. MySql имеет свой кеш результатов запросов. Повторный запрос к тем же данным выполняется быстрее, т.к. вероятно нужные данные находятся в ОЗУ. Но стоит одной из таблиц заджойненной в запросе измениться, как кеш сбрасывается. И неважно попадает изменяемая запись в выдачу или нет.
Например самые частый запрос на форуме это вывод темы + юзеринфо писателей. Стоит нам изменить любой счетчик пользователя (время последнего логина), как кеш сбрасывается.
Другой запрос: вывод списка тем внутри одной доски. Если включены счетчики просмотров, то мы крайне редко будем получать закешированные данные.
В нагруженных системах счетчики выносят из сновных таблиц. Можно реализовать их на файлах, на shared mem, NoSql или, на крайняк просто в отдельных таблицах MySql + отложенная запись, ведь это некритичные данные. Если раз в год счетчик просмотров не запишется из-за сбоя - ну и фиг с ним.
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
artoodetoo, зачем новые предупреждения выделять? Я думаю это уже лишнее.
Предупреждения будут выдаваться в обратном порядке на странице поиска и этого достаточно.
А если у юзера разом появится куча предупреждений, то он их все равно не увидит так как администрация форума отправит его в бан на вечно.
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
artoodetoo, добавил к себе в сборку и гоняю теперь на тестовом форуме.
Стиль чуть поменял
/* ---------- Moderator's warnings ---------------------------- */
.pun .postwarn {
border-style: solid;
border-width: 0 0 0 3px;
border-color: #e99;
margin: 0.75em 1em 0em 2em;
padding: 0 0.75em;
}
.pun .postwarn cite {
font-weight: bold;
}
.pun .postwarn:before {
content: "M";
position: absolute;
margin-left: -2em;
font-size: 150%;
font-weight: bold;
color: #e99;
}
иначе в старых стилях в высоких сообщениях с модерским комментом слева разрыв появляется.
З.Ы. Еще нужно добавить в поиск вывод всех сообщений с предупреждениями как тут и всплывающее окно о новом предупреждении.
З.З.Ы.
Дырка
<?php echo $cur_post['warning']."\n" ?>
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
artoodetoo, как порядок организовал в _https://fluxbb.qb7.ru/forum/search.php?action=show_user_warn&user_id=...
По дате предупреждения или дате сообщения?
---------
Up
Куда бы еще ссылки эти приделать? И как их коротко обозвать?
Редактировался Visman (2010-11-13 15:27:08)
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline