#!perl #------------------------------------------------------------------------------ # mwForum - Web-based discussion forum # Copyright (c) 1999-2005 Markus Wichitill # # 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. #------------------------------------------------------------------------------ use strict; use warnings; no warnings qw(uninitialized redefine); # Imports use MwfMain; #------------------------------------------------------------------------------ # Init my ($m, $cfg, $lng, $user) = MwfMain->new(@_); my $userId = $user->{id}; # Check if access should be denied $m->checkBan($userId) if $cfg->{banViewing}; $m->checkBlock(); # Get CGI parameters my $boardId = $m->paramStr('bid'); # int() later my $jumpTopicId = $m->paramInt('tid'); my $page = $m->paramInt('pg') || 1; # Redirect to main page if board ID is special $m->redirect('forum_show', tgt => $boardId) if $boardId =~ /^cid/; $m->redirect('forum_show') if $boardId eq '0'; $boardId = int($boardId || 0); $m->redirect('blog_show', bid => $boardId, tgt => "tid$jumpTopicId") if $boardId <0 && $jumpTopicId; $m->redirect('blog_show', bid => $boardId) if $boardId < 0; # Get missing boardId from topic $boardId = $m->fetchArray(" SELECT boardId FROM $cfg->{dbPrefix}topics WHERE id = $jumpTopicId") if !$boardId && $jumpTopicId; $boardId or $m->paramError($lng->{errBrdIdMiss}); # Get board/category my $board = $m->fetchHash(" SELECT boards.*, categories.id AS categId, categories.title AS categTitle FROM $cfg->{dbPrefix}boards AS boards INNER JOIN $cfg->{dbPrefix}categories AS categories ON categories.id = boards.categoryId WHERE boards.id = $boardId"); $board or $m->entryError($lng->{errBrdNotFnd}); # Check if user can see and write to board my $boardAdmin = $user->{admin} || $m->boardAdmin($userId, $board->{id}); $boardAdmin || $m->boardVisible($board) or $m->entryError($lng->{errBrdNotFnd}); my $boardWritable = $boardAdmin || $m->boardWritable($board); # Print header $m->printHeader($board->{title}); # Set current page to a requested topics's page my $topicsPP = $m->min($user->{topicsPP}, $cfg->{maxTopicsPP}) || $cfg->{maxTopicsPP}; if ($jumpTopicId) { my $jumpTopicTime = $m->fetchArray(" SELECT lastPostTime FROM $cfg->{dbPrefix}topics WHERE id = $jumpTopicId"); $page = $m->fetchArray(" SELECT COUNT(*) / $topicsPP + 1 FROM $cfg->{dbPrefix}topics WHERE boardId = $boardId AND (sticky OR lastPostTime > $jumpTopicTime)") if $jumpTopicTime; $page = int($page); } # Determine page buttons my @pageButtons = (); my $topicNum = $m->fetchArray(" SELECT COUNT(*) FROM $cfg->{dbPrefix}topics WHERE boardId = $boardId"); my $pageNum = int($topicNum / $topicsPP) + ($topicNum % $topicsPP != 0); if ($pageNum > 1) { my $prevPage = $page - 1; my $nextPage = $page + 1; my $maxPageNum = $m->min($pageNum, 8); for my $i (1 .. $maxPageNum) { push @pageButtons, $m->url('board_show', bid => $boardId, pg => $i), $i, $i == $page ? 0 : 1; } push @pageButtons, undef, "...", 0, $m->url('board_show', bid => $boardId, pg => $pageNum), $pageNum, $pageNum == $page ? 0 : 1 if $maxPageNum + 1 < $pageNum; push @pageButtons, $m->url('board_show', bid => $boardId, pg => $prevPage), 'comPgPrev', $page == 1 ? 0 : 1, $m->url('board_show', bid => $boardId, pg => $nextPage), 'comPgNext', $page == $pageNum ? 0 : 1; } # Print page bar my @bar = (); push @bar, $m->url('topic_add', bid => $boardId), 'brdNewTpc', 1 if $boardWritable; push @bar, $m->url('forum_overview', act => 'new', bid => $boardId), 'comShowNew', 1 if $userId; push @bar, $m->url('forum_overview', act => 'unread', bid => $boardId), 'comShowUnr', 1 if $userId; push @bar, $m->url('forum_overview', act => 'replies', bid => $boardId), 'comShowRpl', 1 if $userId; push @bar, $m->url('forum_overview', act => 'todo', bid => $boardId), 'comShowTdo', 1 if $userId; push @bar, $m->url('board_feeds', bid => $boardId), 'comFeeds', 1 if $cfg->{rssLink} && !$board->{private}; push @bar, $m->url('board_info', bid => $boardId), 'brdInfo', 1; push @bar, $m->url('prevnext', bid => $boardId, dir => 'prev'), 'brdPrev', 1; push @bar, $m->url('prevnext', bid => $boardId, dir => 'next'), 'brdNext', 1; push @bar, $m->url('forum_show', bid => $boardId, tgt => "bid$boardId"), 'comUp', 1; if ($boardAdmin) { my $reportNum = $m->fetchArray(" SELECT COUNT(*) FROM $cfg->{dbPrefix}postReports AS postReports INNER JOIN $cfg->{dbPrefix}posts AS posts ON posts.id = postReports.postId INNER JOIN $cfg->{dbPrefix}boards AS boards ON boards.id = posts.boardId WHERE boards.id = $boardId"); push @bar, undef, undef, 0; if ($user->{admin}) { push @bar, $m->url('board_options', bid => $boardId, ori => 1), 'Options', 1; push @bar, $m->url('board_member', bid => $boardId), 'Members', 1; push @bar, $m->url('board_groups', bid => $boardId, ori => 1), 'Groups', 1; push @bar, $m->url('user_confirm', bid => $boardId, script => 'board_delete', name => $board->{title}), 'Delete', 1; push @bar, $m->url('report_list', bid => $boardId), "Reports ($reportNum)", 1 if $reportNum; } else { push @bar, $m->url('board_member', bid => $boardId, ori => 1), 'brdAdmMbr', 1; push @bar, $m->url('report_list', bid => $boardId), "$lng->{brdAdmRep} ($reportNum)", 1 if $reportNum; } } my $url = $m->url('forum_show', bid => $boardId, tgt => "bid$boardId"); my $categStr = "$board->{categTitle} / "; $url = $m->url('board_show', bid => $boardId, pg => $page); my $boardStr = "$board->{title}"; my $pageStr = $page > 1 ? " ($lng->{comPgTtl} $page)" : ""; my $title = $categStr . $boardStr . $pageStr; $m->printBar($lng->{brdTitle}, $title, \@bar, 0, $page, \@pageButtons); # Get topics including base post user and approval my $offset = ($page - 1) * $topicsPP; my $topics = $m->fetchAllHash(" SELECT topics.*, posts.userId, posts.approved, posts.userNameBak, users.userName FROM $cfg->{dbPrefix}topics AS topics INNER JOIN $cfg->{dbPrefix}posts AS posts ON posts.id = topics.basePostId LEFT JOIN $cfg->{dbPrefix}users AS users ON users.id = posts.userId WHERE topics.boardId = $boardId ORDER BY sticky DESC, lastPostTime DESC LIMIT $offset, $topicsPP"); # Put topics in by-id lookup table and concat their IDs for the next query my %topics = (); my $topicIds = "0"; for my $topic (@$topics) { $topics{$topic->{id}} = $topic; $topicIds .= "," . $topic->{id}; } # Get new post and unread numbers my $lowestUnreadTime = $m->max($user->{fakeReadTime}, $m->{now} - $cfg->{maxUnreadDays} * 86400); if ($userId) { my $topicStats = $m->fetchAllHash(" SELECT topics.id, SUM(posts.postTime > $user->{prevOnTime}) AS newNum, SUM(topics.lastPostTime > $lowestUnreadTime AND (topics.lastPostTime > topicReadTimes.lastReadTime OR topicReadTimes.topicId IS NULL)) AS unreadNum FROM $cfg->{dbPrefix}topics AS topics INNER JOIN $cfg->{dbPrefix}posts AS posts ON posts.topicId = topics.id LEFT JOIN $cfg->{dbPrefix}topicReadTimes AS topicReadTimes ON topicReadTimes.userId = $userId AND topicReadTimes.topicId = topics.id WHERE topics.id IN ($topicIds) AND posts.approved = 1 GROUP BY topics.id"); for my $topic (@$topicStats) { $topics{$topic->{id}}{newNum} = $topic->{newNum}; $topics{$topic->{id}}{unreadNum} = $topic->{unreadNum}; } } # Print long description print "
\n", "
\n", "$board->{longDesc}\n", "
\n", "
\n\n" if $cfg->{boardPageDesc} && $board->{longDesc} && $user->{boardDescs}; # Print table header print "\n", "\n", "\n", "\n", "\n", "\n", "\n"; # Print topics for my $topic (@$topics) { # Skip if invisible next if $board->{approve} && !($topic->{approved} || $boardAdmin || $userId && $userId == $topic->{userId}); # Use #fp target if there're new or unread posts, but not if all of them are new or unread my $fp = $topic->{unreadNum} || $topic->{newNum} && !($topic->{unreadNum} == $topic->{postNum} || $topic->{newNum} == $topic->{postNum}) ? "fp" : ""; # Format output my $lastPostTimeStr = $m->formatTime($topic->{lastPostTime}, $user->{timezone}); my $userNameStr = $topic->{userName} || $topic->{userNameBak} || " - "; my $url = $m->url('user_info', uid => $topic->{userId}); $userNameStr = "$userNameStr"; my $subject = $topic->{sticky} ? "$topic->{subject}" : $topic->{subject}; $url = $m->url('forum_overview', act => 'new', tid => $topic->{id}); my $newNumStr = $topic->{newNum} ? "($topic->{newNum} $lng->{brdNew})" : ""; # Determine variable topic icon attributes my $imgSrc = ""; my $imgTitle = ""; my $imgAlt = ""; if (!$userId) { $imgSrc = "topic_ou" } else { if ($board->{approve} && !$topic->{approved}) { $imgSrc = "topic_i"; $imgTitle = $lng->{brdInvisTT}; $imgAlt = $lng->{brdInvis}; } elsif ($topic->{newNum} && $topic->{unreadNum}) { $imgSrc = "topic_nu"; $imgTitle = $lng->{comNewUnrdTT}; $imgAlt = $lng->{comNewUnrd}; } elsif ($topic->{newNum}) { $imgSrc = "topic_nr"; $imgTitle = $lng->{comNewReadTT}; $imgAlt = $lng->{comNewRead}; } elsif ($topic->{unreadNum}) { $imgSrc = "topic_ou"; $imgTitle = $lng->{comOldUnrdTT}; $imgAlt = $lng->{comOldUnrd}; } else { $imgSrc = "topic_or"; $imgTitle = $lng->{comOldReadTT}; $imgAlt = $lng->{comOldRead}; } } my $imgAttr = "class='ico' src='$cfg->{dataPath}/$imgSrc.gif' title='$imgTitle' alt='$imgAlt'"; # Lock icon my $lockImg = $topic->{locked} ? " $lng->{brdLocked}" : ""; # Poll icon my $pollImg = $topic->{pollId} ? " $lng->{brdPoll}" : ""; # Print topic $url = $m->url('topic_show', tid => $topic->{id}, tgt => $fp); print "\n", "\n", "\n", "\n", "\n", "\n"; } print "
$lng->{brdTopic}$lng->{brdPoster}$lng->{brdPosts}$lng->{brdLastPost}
\n", "\n", "$lockImg$pollImg\n", "$subject\n", "$userNameStr$topic->{postNum} $newNumStr$lastPostTimeStr
\n\n"; # Log action $m->logAction(2, 'board', 'show', $userId, $boardId); # Print footer $m->printFooter(undef, undef, $boardId);