Быстрый лёгкий надёжный форумный движок
Вы не вошли.
Собираюсь написать систему лайков для форума, которая была бы подобна фейсбуковской. А то хочется поблагодарить Висмана, а простой и удобной кнопки нет
Хочу типа фейсбуковых лайков — голосовать можно только "за". Хотя бы без последних украшательств, то есть просто лайк без выбора эмоции.
если ты зарегистрирован, можешь лайкнуть сообщение,
можешь передумать и убрать свой лайк,
все видят сколько лайков набрало сообщение,
ты видишь лайкал ли ты сам это сообщение
graceful degradation, если JS вдруг недоступен, кнопка всё равно должна работать, пусть с перегрузкой страницы.
В posts добавить колонку num_likes с числом лайков. Это позволит без джойнов выводить цифры в ленте сообщений.
Отдельная таблица post_likes с уникальным составным ключём (user_id, post_id) чтобы определять голосовал ли пользователь за сообщение.
Думается мне, что "лайкать" будут часто, а "разлакивать" очень редко. Поэтому слегка оптимизирую наиболее частый кейс. Не буду делать предварительный select чтобы узнать лайкал ли уже пользователь это сообщение. База сама подскажет через возвращаемое число добавленных записей.
$db->query("INSERT IGNORE INTO post_likes(user_id, post_id, created_on) VALUES($uid, $pid, $now)");
if ($db->affected_rows()) {
// Yes, I like it
$db->query("UPDATE posts SET num_likes = num_likes + 1 WHERE id = $pid");
} else {
// No, I changed my mind
$db->query("UPDATE posts SET num_likes = num_likes - 1 WHERE id = $pid");
$db->query("DELETE FROM post_likes WHERE user_id = $uid AND post_id = $pid");
}
Продолжение следует…
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
Итак, для вывода количества лайков в каждом сообщении нам не надо добавлять джойны. Достаточно впилить одну колонку в таблицу posts. Но выше я включил фичу, что пользователь будет видеть статус лайкал ли он сам конкретное сообщение. То есть нам таки понадобится обращение к post_likes при выводе ленты.
Я думаю можно это сделать один раз, когда у нас будет накоплен список сообщений на странице. Причем только в случае если пользователь не Guest.
$pids = implode(',', $post_ids);
$result = $db->query("SELECT post_id FROM post_likes WHERE user_id = $uid AND post_id IN($pids)");
Итоговый список будем использовать для добавления класса active в кнопки Like.
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
Применил мод к нашему форуму. Если вы зарегистрированный пользователь, обратите внимание на строку под каждым сообщением. Там должна появиться ссылка "Понравилось"/"Разонравилось".
Лайкайте!!! Задавайте вопросы, предлагайте улучшения (я всё равно сделаю по своему).
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
@artoodetoo, счас народ красивостей просить будет
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
Не знаю когда соберусь с силами чтобы оформить мод как принято. Пока некогда.
Как есть скачать можно отсюда (пробелы уберите):
https: // dl.dropboxusercontent.com/u/11837706/flux-likes-20160108.zip
https : //www.dropbox.com/s/2022e93oux82nes/flux-likes-20160108.zip?dl=0
во viewtopic все изменения можно найти diff-ом либо посиком подстроки "vote"
в стили добавил только один селектор .postnumvotes
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
Не знаю когда соберусь с силами чтобы оформить мод как принято. Пока некогда.
Как есть скачать можно отсюда (пробелы уберите):https: // dl.dropboxusercontent.com/u/11837706/flux-likes-20160108.zip
во viewtopic все изменения можно найти diff-ом либо посиком подстроки "vote"
в стили добавил только один селектор .postnumvotes
Этого мода явно не хватало, к тому же сама реализация в стилях это дело техники, главное что теперь можно выводить самый топовый пост, или про100 сделал вывод сообщений по рейтингу.
Вообще уже есть где фантазию проявить
По аналогии можно сделать дизлайк и посты при множестве дизлайков будут помечены как спам или по крону будут удаляться...
Offline
По аналогии можно сделать дизлайк и....
И тут начинается война
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
Добавил csrf_token и иконку.
Думаю как бы органично впилить лайки в поиск и пользовательский профиль.
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
Добавил csrf_token и иконку.
Думаю как бы органично впилить лайки в поиск и пользовательский профиль.
Может сделать опцию возможности ставить лайки только на тему, для первого поста?
$voted = array_search($cur_post['id'], $voted_ids) !== false;
if (!empty($cur_post['num_votes']) && $pun_config['o_postlike'] == '1' && $cur_topic['first_post_id'] {
if ($voted)
$post_actions[] = '<li class="postnumvotes">'.sprintf($lang_vote['Num Votes w. You'], $cur_post['num_votes']).'</li>';
else
$post_actions[] = '<li class="postnumvotes">'.sprintf($lang_vote['Num Votes'], $cur_post['num_votes']).'</li>';
}
else if($pun_config['o_postlike'] == '2' && !empty($cur_post['num_votes'])) {
if ($voted)
$post_actions[] = '<li class="postnumvotes">'.sprintf($lang_vote['Num Votes w. You'], $cur_post['num_votes']).'</li>';
else
$post_actions[] = '<li class="postnumvotes">'.sprintf($lang_vote['Num Votes'], $cur_post['num_votes']).'</li>';
}
Offline
Может сделать опцию возможности ставить лайки только на тему, для первого поста?
Да, в этом есть смысл.
Есть такая идея: считать лайк первого сообщения особым образом — лайкать саму тему. Как на StackOverflow: есть баллы за вопросы и есть баллы за ответы. Если сделать так, то можно будет сортировать темы по лайкам.
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
@artoodetoo,
По ссылке https: //dl.dropboxusercontent.com/u/11837706/flux-likes-20160108.zip файла больше нет.
Если не сложно, перезалейте пожалуйста.
я делал ссылку некликабельной. наверное есть причины :) не надо это "исправлять" пожалуйста
Offline
https: //www.dropbox.com/s/2022e93oux82nes/flux-likes-20160108.zip?dl=0
There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.
Offline
спасибо
Offline
При переходе в темы получаю такую неприятность
File: \viewtopic.php
Line: 232
FluxBB reported: Unable to fetch vote info
Database reported: Table 'fbb.post_votes' doesn't exist (Errno: 1146)
Догадываюсь что нужно создать таблицу.Как правильно это сделать?
Offline
@serpech, видимо такая табличка нужна
CREATE TABLE `fx15_post_votes` (
`post_id` int(10) unsigned NOT NULL DEFAULT '0',
`user_id` int(10) unsigned NOT NULL DEFAULT '0',
`voted` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`user_id`, `post_id`)
);
ALTER TABLE `prefix_posts`
ADD COLUMN `num_votes` mediumint(8) unsigned NOT NULL DEFAULT '0';
Вместо fx15_ и prefix_ нужно подставить префикс своих таблиц и выполнить оба запроса в phpMyAdmin на базе форума.
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
Спасибо!Работает прекрасно.
Offline
@serpech, видимо такая табличка нужна
...
А подскажите на счет вашей сборки viewtopic.php как поправить?
Понятно что этот блок:
$voted = array_search($cur_post['id'], $voted_ids) !== false;
if (!empty($cur_post['num_votes'])) {
if ($voted)
$post_actions[] = '<li class="postnumvotes">'.sprintf($lang_vote['Num Votes w. You'], $cur_post['num_votes']).'</li>';
else
$post_actions[] = '<li class="postnumvotes">'.sprintf($lang_vote['Num Votes'], $cur_post['num_votes']).'</li>';
}
if (!$pun_user['is_guest']) {
if ($voted)
$post_actions[] = '<li class="postvote"><span><a href="vote.php?pid='.$cur_post['id'].'">'.$lang_vote['Vote Down'].'</a></span></li>';
else
$post_actions[] = '<li class="postvote"><span><a href="vote.php?pid='.$cur_post['id'].'">'.$lang_vote['Vote Up'].'</a></span></li>';
}
и этого блока
if (empty($post_ids))
error('The post table and topic table seem to be out of sync!', __FILE__, __LINE__);
// Добавить после
// Retrieve the post voted by user
$voted_ids = array();
if (!$pun_user['is_guest'])
{
$result = $db->query('SELECT pv.post_id FROM '.$db->prefix.'post_votes AS pv WHERE pv.user_id='.$pun_user['id'].' AND pv.post_id IN ('.implode(',', $post_ids).')', true) or error('Unable to fetch vote info', __FILE__, __LINE__, $db->error());
while ($row = $db->fetch_assoc($result))
$voted_ids[] = $row['post_id'];
}
Ланг файлы подключаем в последний момент
// Load the viewtopic.php language file
require PUN_ROOT.'lang/'.$pun_user['language'].'/topic.php';
//require PUN_ROOT.'lang/'.$pun_user['language'].'/vote.php';
я так понял нужен ещё
$result = $db->query( .. p.num_votes
Редактировался Aлександр (2020-02-10 17:46:30)
Offline
@Aлександр, если вопрос ко мне, то надо сначала @artoodetoo растрясти на полный код, который на этом сайте стоит, а то у меня его нет в наличии, на гитхабе тоже не нашел. Ссылки на дропбокс устаревшие.
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
@Aлександр, Ссылки на дропбокс устаревшие.
https://www.dropbox.com/s/2022e93oux82n … 8.zip?dl=0
Рабочие
Offline
@Aлександр, посмотрю сейчас и отпишусь чуть позже.
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
@Aлександр, примерно, что надо:
1. Выполнить запросы http://fluxbb.qb7.ru/forum/viewtopic.ph … 077#p30077
Для файла viewtopic.php
2. после
require PUN_ROOT.'lang/'.$pun_user['language'].'/topic.php';
добавить
require PUN_ROOT.'lang/'.$pun_user['language'].'/vote.php';
3. после
// Poll MOD - Visman
if (in_array($cur_topic['first_post_id'], $post_ids))
poll_display_topic($id, $pun_user['id'], $p, true);
// Poll MOD - Visman
добавить
// Retrieve the post voted by user
$voted_ids = array();
if (!$pun_user['is_guest'])
{
$result = $db->query('SELECT pv.post_id FROM '.$db->prefix.'post_votes AS pv WHERE pv.user_id='.$pun_user['id'].' AND pv.post_id IN ('.implode(',', $post_ids).')', true) or error('Unable to fetch vote info', __FILE__, __LINE__, $db->error());
while ($row = $db->fetch_assoc($result))
$voted_ids[] = $row['post_id'];
}
4. в этот запрос
$result = $db->query('SELECT u.warning_all, u.gender, u.email, u.title, u.url, u.location, u.signature, u.email_setting, u.num_posts, u.registered, u.admin_note, u.messages_enable, 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, p.edit_post, p.user_agent, g.g_id, g.g_user_title, g.g_promote_next_group, g.g_pm 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 WHERE p.id IN ('.implode(',', $post_ids).') ORDER BY p.id', true) or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
добавить поле
, p.num_votes
5. перед
// Perform the main parsing of the message (BBCode, smilies, censor words etc)
добавить
$voted = array_search($cur_post['id'], $voted_ids) !== false;
if (!empty($cur_post['num_votes'])) {
if ($voted)
$post_actions[] = '<li class="postnumvotes">'.sprintf($lang_vote['Num Votes w. You'], $cur_post['num_votes']).'</li>';
else
$post_actions[] = '<li class="postnumvotes">'.sprintf($lang_vote['Num Votes'], $cur_post['num_votes']).'</li>';
}
if (!$pun_user['is_guest']) {
if ($voted)
$post_actions[] = '<li class="postvote"><span><a href="vote.php?pid='.$cur_post['id'].'&csrf_hash='.csrf_hash('vote'.$cur_post['id']).'">'.$lang_vote['Vote Down'].'</a></span></li>';
else
$post_actions[] = '<li class="postvote"><span><a href="vote.php?pid='.$cur_post['id'].'&csrf_hash='.csrf_hash('vote'.$cur_post['id']).'">'.$lang_vote['Vote Up'].'</a></span></li>';
}
Для файла vote.php
6. После
$pid = isset($_GET['pid']) ? intval($_GET['pid']) : 0;
добавить
confirm_referrer('vote'.$pid);
В 5 и 6 шаге добавлен csrf_hash для исклюения накрутки или скрутки голосов. + не даст проголосовать за недоступные посты.
Код не проверен.
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
И возможно лучше
$voted_ids[] = $row['post_id'];
заменить на
$voted_ids[$row['post_id']] = $row['post_id'];
а условие
$voted = array_search($cur_post['id'], $voted_ids) !== false;
на
$voted = isset($voted_ids[$cur_post['id']]);
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
В принципе я 1 в 1 всё это делал
и получаю ошибку
File: /viewtopic.php
Line: 368
FluxBB reported: Unable to fetch post info
Database reported: Unknown column 'p.num_votes' in 'field list' (Errno: 1054)
$result = $db->query('SELECT u.warning_all, u.gender, u.email, u.title, u.url, u.location, u.signature, u.email_setting, u.num_posts, u.registered, u.admin_note, u.messages_enable, 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, p.edit_post, p.user_agent, g.g_id, g.g_user_title, g.g_promote_next_group, g.g_pm, p.num_votes 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 WHERE p.id IN ('.implode(',', $post_ids).') ORDER BY p.id', true) or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
естественно таблицу post_votes (без префикса) создал и добавил в posts колонку num_votes
CREATE TABLE `post_votes` (
`post_id` int(10) unsigned NOT NULL DEFAULT '0',
`user_id` int(10) unsigned NOT NULL DEFAULT '0',
`voted` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`user_id`, `post_id`)
);
ALTER TABLE `posts`
ADD COLUMN `num_votes` mediumint(8) unsigned NOT NULL DEFAULT '0';
Редактировался Aлександр (2020-02-10 20:17:51)
Offline
@Aлександр, добавьте поле num_votes в таблицу posts тогда не запросом, а через phpMyAdmin, через редактирование структуры таблицы.
Моя сборка FluxBB 1.5, ForkBB · сообщество
Offline
я всё правильно сделал проблему кажется понял ))))
я создал таблицу posts и всё не мог понять почему мне пишет эту ошибку ведь я всё сделал правильно и ошибка понятная. Но как оказалось я думал что fluxbbposts это цельная таблица самого движка (просто давно не работал с форумом) а это блин префикс fluxbb а когда делал запросы не обратил на это внимание, тупо смотрел в таблицу posts не замечая что она к форуму не относиться
Редактировался Aлександр (2020-02-10 20:37:09)
Offline