import of submitted forum extension

This commit is contained in:
Shish 2009-10-09 13:10:39 +01:00
parent daa19b8b6a
commit 325ecb5cbb
2 changed files with 625 additions and 0 deletions

395
contrib/forum/main.php Normal file
View File

@ -0,0 +1,395 @@
<?php
/**
* Name: [Beta] Forum
* Author: Sein Kraft <mail@seinkraft.info>
* Alpha <alpha@furries.com.ar>
* License: GPLv2
* Description: Rough forum extension
* Documentation:
*/
class Forum extends SimpleExtension {
public function onInitExt($event) {
global $config, $database;
// shortcut to latest
if ($config->get_int("forum_version") < 1)
{
$database->create_table("forum_threads", "
id SCORE_AIPK,
sticky SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N,
title VARCHAR(255) NOT NULL,
user_id INTEGER NOT NULL,
date DATETIME NOT NULL,
uptodate DATETIME NOT NULL,
INDEX (date)
");
$database->create_table("forum_posts",
" id SCORE_AIPK,
thread_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
date DATETIME NOT NULL,
message TEXT,
INDEX (date),
FOREIGN KEY (thread_id) REFERENCES forum_threads (id) ON UPDATE CASCADE ON DELETE CASCADE
");
$config->set_int("forum_version", 1);
$config->set_int("forumTitleSubString", 25);
$config->set_int("forumThreadsPerPage", 15);
$config->set_int("forumPostsPerPage", 15);
$config->set_int("forumMaxCharsPerPost", 512);
log_info("forum", "extension installed");
}
}
public function onSetupBuilding(SetupBuildingEvent $event) {
$sb = new SetupBlock("Forum");
$sb->add_int_option("forumTitleSubString", "Title max long: ");
$sb->add_int_option("forumThreadsPerPage", "<br>Threads per page: ");
$sb->add_int_option("forumPostsPerPage", "<br>Posts per page: ");
$sb->add_int_option("forumMaxCharsPerPost", "<br>Max chars per post: ");
$event->panel->add_block($sb);
}
public function onUserPageBuilding($event) {
global $page, $user, $database;
$threads_count = $database->db->GetOne("SELECT COUNT(*) FROM forum_threads WHERE user_id=?", array($event->display_user->id));
$posts_count = $database->db->GetOne("SELECT COUNT(*) FROM forum_posts WHERE user_id=?", array($event->display_user->id));
$days_old = ((time() - strtotime($event->display_user->join_date)) / 86400) + 1;
$threads_rate = sprintf("%.1f", ($threads_count / $days_old));
$posts_rate = sprintf("%.1f", ($posts_count / $days_old));
$event->add_stats("Forum threads: $threads_count, $threads_rate per day");
$event->add_stats("Forum posts: $posts_count, $posts_rate per day");
}
public function onPageRequest($event) {
global $page, $user;
if($event->page_matches("forum")) {
switch($event->get_arg(0)) {
case "index":
{
$this->show_last_threads($page, $event, $user->is_admin());
if(!$user->is_anonymous()) $this->theme->display_new_thread_composer($page);
break;
}
case "view":
{
$threadID = int_escape($event->get_arg(1));
$pageNumber = int_escape($event->get_arg(2));
$this->show_posts($event, $user->is_admin());
if($user->is_admin()) $this->theme->add_actions_block($page, $threadID);
if(!$user->is_anonymous()) $this->theme->display_new_post_composer($page, $threadID);
break;
}
case "new":
{
global $page;
$this->theme->display_new_thread_composer($page);
break;
}
case "create":
{
$redirectTo = "forum/index";
if (!$user->is_anonymous())
{
list($hasErrors, $errors) = $this->valid_values_for_new_thread();
if($hasErrors)
{
$this->theme->display_error($page, "Error", $errors);
$this->theme->display_new_thread_composer($page, $_POST["message"], $_POST["title"], false);
break;
}
$newThreadID = $this->save_new_thread($user);
$this->save_new_post($newThreadID, $user);
$redirectTo = "forum/view/".$newThreadID."/1";
}
$page->set_mode("redirect");
$page->set_redirect(make_link($redirectTo));
break;
}
case "delete":
$threadID = int_escape($event->get_arg(1));
$postID = int_escape($event->get_arg(2));
if ($user->is_admin()) {$this->delete_post($postID);}
$page->set_mode("redirect");
$page->set_redirect(make_link("forum/view/".$threadID));
break;
case "nuke":
$threadID = int_escape($event->get_arg(1));
if ($user->is_admin())
$this->delete_thread($threadID);
$page->set_mode("redirect");
$page->set_redirect(make_link("forum/index"));
break;
case "answer":
if (!$user->is_anonymous())
{
list($hasErrors, $errors) = $this->valid_values_for_new_post();
if ($hasErrors)
{
$this->theme->display_error($page, "Error", $errors);
$this->theme->display_new_post_composer($page, $_POST["threadID"], $_POST["message"], $_POST["title"], false);
break;
}
$threadID = int_escape($_POST["threadID"]);
$this->save_new_post($threadID, $user);
}
$page->set_mode("redirect");
$page->set_redirect(make_link("forum/view/".$threadID."/1"));
break;
default:
{
$page->set_mode("redirect");
$page->set_redirect(make_link("forum/index"));
//$this->theme->display_error($page, "Invalid action", "You should check forum/index.");
break;
}
}
}
}
private function get_total_pages_for_thread($threadID)
{
global $database, $config;
$result = $database->get_row("SELECT COUNT(1) AS count FROM forum_posts WHERE thread_id = ?", array($threadID));
return ceil($result["count"] / $config->get_int("forumPostsPerPage"));
}
private function valid_values_for_new_thread()
{
$hasErrors = false;
$errors = "";
if (!array_key_exists("title", $_POST))
{
$hasErrors = true;
$errors .= "<div id='error'>No title supplied.</div>";
}
else if (strlen($_POST["title"]) == 0)
{
$hasErrors = true;
$errors .= "<div id='error'>You cannot have an empty title.</div>";
}
else if (strlen(mysql_real_escape_string(htmlspecialchars($_POST["title"]))) > 255)
{
$hasErrors = true;
$errors .= "<div id='error'>Your title is too long.</div>";
}
if (!array_key_exists("message", $_POST))
{
$hasErrors = true;
$errors .= "<div id='error'>No message supplied.</div>";
}
else if (strlen($_POST["message"]) == 0)
{
$hasErrors = true;
$errors .= "<div id='error'>You cannot have an empty message.</div>";
}
return array($hasErrors, $errors);
}
private function valid_values_for_new_post()
{
$hasErrors = false;
$errors = "";
if (!array_key_exists("threadID", $_POST))
{
$hasErrors = true;
$errors = "<div id='error'>No thread ID supplied.</div>";
}
else if (strlen($_POST["threadID"]) == 0)
{
$hasErrors = true;
$errors = "<div id='error'>No thread ID supplied.</div>";
}
else if (is_numeric($_POST["threadID"]))
if (!array_key_exists("message", $_POST))
{
$hasErrors = true;
$errors .= "<div id='error'>No message supplied.</div>";
}
else if (strlen($_POST["message"]) == 0)
{
$hasErrors = true;
$errors .= "<div id='error'>You cannot have an empty message.</div>";
}
return array($hasErrors, $errors);
}
private function get_thread_title($threadID)
{
global $database;
$result = $database->get_row("SELECT t.title FROM forum_threads AS t WHERE t.id = ? ", array($threadID));
return $result["title"];
}
private function show_last_threads(Page $page, $event, $showAdminOptions = false)
{
global $config, $database;
$pageNumber = $event->get_arg(1);
if(is_null($pageNumber) || !is_numeric($pageNumber))
$pageNumber = 0;
else if ($pageNumber <= 0)
$pageNumber = 0;
else
$pageNumber--;
$threadsPerPage = $config->get_int('forumThreadsPerPage', 15);
$threads = $database->get_all(
"SELECT f.id, f.sticky, f.title, f.date, f.uptodate, u.name AS user_name, u.email AS user_email, u.admin AS user_admin, sum(1) - 1 AS response_count ".
"FROM forum_threads AS f ".
"INNER JOIN users AS u ".
"ON f.user_id = u.id ".
"INNER JOIN forum_posts AS p ".
"ON p.thread_id = f.id ".
"GROUP BY f.id, f.sticky, f.title, f.date, u.name, u.email, u.admin ".
"ORDER BY f.sticky DESC, f.uptodate DESC LIMIT ?, ?"
, array($pageNumber * $threadsPerPage, $threadsPerPage)
);
$totalPages = ceil($database->db->GetOne("SELECT COUNT(*) FROM forum_threads") / $threadsPerPage);
$this->theme->display_thread_list($page, $threads, $showAdminOptions, $pageNumber + 1, $totalPages);
}
private function show_posts($event, $showAdminOptions = false)
{
global $config, $database, $user;
$threadID = $event->get_arg(1);
$pageNumber = $event->get_arg(2);
if(is_null($pageNumber) || !is_numeric($pageNumber))
$pageNumber = 0;
else if ($pageNumber <= 0)
$pageNumber = 0;
else
$pageNumber--;
$postsPerPage = $config->get_int('forumPostsPerPage', 15);
$posts = $database->get_all(
"SELECT p.id, p.date, p.message, u.name as user_name, u.email AS user_email, u.admin AS user_admin ".
"FROM forum_posts AS p ".
"INNER JOIN users AS u ".
"ON p.user_id = u.id ".
"WHERE thread_id = ? ".
"ORDER BY p.date ASC ".
"LIMIT ?, ? "
, array($threadID, $pageNumber * $postsPerPage, $postsPerPage)
);
$totalPages = ceil($database->db->GetOne("SELECT COUNT(*) FROM forum_posts WHERE thread_id = ?", array($threadID)) / $postsPerPage);
$threadTitle = $this->get_thread_title($threadID);
$this->theme->display_thread($posts, $showAdminOptions, $threadTitle, $threadID, $pageNumber + 1, $totalPages);
}
private function save_new_thread($user)
{
$title = mysql_real_escape_string(htmlspecialchars($_POST["title"]));
$sticky = html_escape($_POST["sticky"]);
if($sticky == ""){
$sticky = "N";
}
global $database;
$database->execute("
INSERT INTO forum_threads
(title, sticky, user_id, date, uptodate)
VALUES
(?, ?, ?, now(), now())",
array($title, $sticky, $user->id));
$result = $database->get_row("SELECT LAST_INSERT_ID() AS threadID", array());
log_info("forum", "Thread {$result["threadID"]} created by {$user->name}");
return $result["threadID"];
}
private function save_new_post($threadID, $user)
{
global $config;
$userID = $user->id;
$message = mysql_real_escape_string(htmlspecialchars($_POST["message"]));
$max_characters = $config->get_int('forumMaxCharsPerPost');
$message = substr($message, 0, $max_characters);
global $database;
$database->execute("INSERT INTO forum_posts
(thread_id, user_id, date, message)
VALUES
(?, ?, now(), ?)"
, array($threadID, $userID, $message));
$result = $database->get_row("SELECT LAST_INSERT_ID() AS postID", array());
log_info("forum", "Post {$result["postID"]} created by {$user->name}");
$database->execute("UPDATE forum_threads SET uptodate=now() WHERE id=?", array ($threadID));
}
private function retrieve_posts($threadID, $pageNumber)
{
global $database, $config;
$postsPerPage = $config->get_int('forumPostsPerPage', 15);
return $database->get_all(
"SELECT p.id, p.date, p.message, u.name as user_name, u.email AS user_email, u.admin AS user_admin ".
"FROM forum_posts AS p ".
"INNER JOIN users AS u ".
"ON p.user_id = u.id ".
"WHERE thread_id = ? ".
"ORDER BY p.date ASC ".
"LIMIT ?, ? "
, array($threadID, ($pageNumber - 1) * $postsPerPage, $postsPerPage));
}
private function delete_thread($threadID)
{
global $database;
$database->execute("DELETE FROM forum_threads WHERE id = ?", array($threadID));
$database->execute("DELETE FROM forum_posts WHERE thread_id = ?", array($threadID));
}
private function delete_post($postID)
{
global $database;
$database->execute("DELETE FROM forum_posts WHERE id = ?", array($postID));
}
}
?>

230
contrib/forum/theme.php Normal file
View File

@ -0,0 +1,230 @@
<?php
class ForumTheme extends Themelet {
public function display_thread_list(Page $page, $threads, $showAdminOptions, $pageNumber, $totalPages)
{
if (count($threads) == 0)
$html = "There are no threads to show.";
else
$html = $this->make_thread_list($threads, $showAdminOptions);
$page->set_title(html_escape("Forum"));
$page->set_heading(html_escape("Forum"));
$page->add_block(new Block("Forum", $html, "main", 10));
$this->display_paginator($page, "forum/index", null, $pageNumber, $totalPages);
}
public function display_new_thread_composer(Page $page, $threadText = null, $threadTitle = null)
{
global $config, $user;
$max_characters = $config->get_int('forumMaxCharsPerPost');
$postUrl = make_link("forum/create");
$html = '<form action="'.$postUrl.'" method="POST">';
if (!is_null($threadTitle))
$threadTitle = html_escape($threadTitle);
if(!is_null($threadText))
$threadText = html_escape($threadText);
$html .= "
<table style='width: 500px;'>
<tr><td>Title:</td><td><input type='text' name='title' value='$threadTitle'></td></tr>
<tr><td>Message:</td><td><textarea id='message' name='message' >$threadText</textarea></td></tr>
<tr><td></td><td><small>Max characters alowed: $max_characters.</small></td></tr>";
if($user->is_admin()){
$html .= "<tr><td colspan='2'><label for='sticky'>Sticky:</label><input name='sticky' type='checkbox' value='Y' /></td></tr>";
}
$html .= "<tr><td colspan='2'><input type='submit' value='Submit' /></td></tr>
</table>
</form>
";
$blockTitle = "Write a new thread";
$page->set_title(html_escape($blockTitle));
$page->set_heading(html_escape($blockTitle));
$page->add_block(new Block($blockTitle, $html, "main", 20));
}
public function display_new_post_composer(Page $page, $threadID)
{
global $config;
$max_characters = $config->get_int('forumMaxCharsPerPost');
$postUrl = make_link("forum/answer");
$html = '<form action="'.$postUrl.'" method="POST">';
$html .= '<input type="hidden" name="threadID" value="'.$threadID.'" />';
$html .= "
<table style='width: 500px;'>
<tr><td>Message:</td><td><textarea id='message' name='message' ></textarea>
<tr><td></td><td><small>Max characters alowed: $max_characters.</small></td></tr>
</td></tr>";
$html .= "<tr><td colspan='2'><input type='submit' value='Submit' /></td></tr>
</table>
</form>
";
$blockTitle = "Answer to this thread";
$page->add_block(new Block($blockTitle, $html, "main", 30));
}
public function display_thread($posts, $showAdminOptions, $threadTitle, $threadID, $pageNumber, $totalPages)
{
global $config, $page/*, $user*/;
$theme_name = $config->get_string('theme');
$data_href = $config->get_string('base_href');
$base_href = $config->get_string('base_href');
$html = "";
$n = 0;
$html = "<table id='postList' class='zebra'>".
"<thead><tr>".
"<th>User</th>".
"<th>Message</th>".
"</tr></thead>";
foreach ($posts as $post)
{
$message = $post["message"];
$tfe = new TextFormattingEvent($message);
send_event($tfe);
$message = $tfe->formatted;
$message = str_replace('\n\r', '<br>', $message);
$message = str_replace('\r\n', '<br>', $message);
$message = str_replace('\n', '<br>', $message);
$message = str_replace('\r', '<br>', $message);
$user = "<a href='".make_link("user/".$post["user_name"]."")."'>".$post["user_name"]."</a>";
$email = $post["user_email"];
$default = "$data_href/themes/$theme_name/images/gravatar.jpg";
$size = 50;
$gravatar = "<img id='gravatar' height='".$size."' width='".$size."' src='http://www.gravatar.com/avatar/".md5(strtolower($email))."?&d=".urlencode($default)."&s=".$size."'>";
$oe = ($n++ % 2 == 0) ? "even" : "odd";
if ($post["user_admin"] == "Y") {
$rank = "<sup>admin</sup>";
} else {
$rank = "<small>user</small>";
}
$postID = $post['id'];
//if($user->is_admin()){
//$delete_link = "<a href=".make_link("forum/delete/".$threadID."/".$postID).">Delete</a>";
//} else {
//$delete_link = "";
//}
if($showAdminOptions){
$delete_link = "<a href=".make_link("forum/delete/".$threadID."/".$postID).">Delete</a>";
}else{
$delete_link = "";
}
$html .= "<tr class='$oe'>".
"<td class='forum_user'>".$user."<br>".$rank."<br>".$gravatar."</td>".
"<td class='forum_message'>".$message."</td>"."</tr>
<tr class='$oe'>
<td class='forum_subuser'><small>".autodate($post["date"])."</small></td>
<td class='forum_submessage'>".$delete_link."</td>
</tr>";
}
$html .= "</tbody></table>";
$this->display_paginator($page, "forum/view/".$threadID, null, $pageNumber, $totalPages);
$page->set_title(html_escape($threadTitle));
$page->set_heading(html_escape($threadTitle));
$page->add_block(new Block("Thread", $html, "main", 20));
}
public function add_actions_block(Page $page, $threadID)
{
$html = '<a href="'.make_link("forum/nuke/".$threadID).'">Delete this thread and its posts.</a>';
$page->add_block(new Block("Admin Actions", $html, "main", 40));
}
private function make_thread_list($threads, $showAdminOptions)
{
$html = "<table id='threadList' class='zebra'>".
"<thead><tr>".
"<th>Title</th>".
"<th>Author</th>".
"<th>Updated</th>".
"<th>Responses</th>";
if($showAdminOptions)
{
$html .= "<th>Actions</th>";
}
$html .= "</tr></thead><tbody>";
$n = 0;
foreach($threads as $thread)
{
$oe = ($n++ % 2 == 0) ? "even" : "odd";
global $config;
$titleSubString = $config->get_int('forumTitleSubString');
if ($titleSubString < strlen($thread["title"]))
{
$title = substr($thread["title"], 0, $titleSubString);
$title = $title."...";
} else {
$title = $thread["title"];
}
if($thread["sticky"] == "Y"){
$sticky = "Sticky: ";
} else {
$sticky = "";
}
$html .= "<tr class='$oe'>".
'<td class="left">'.$sticky.'<a href="'.make_link("forum/view/".$thread["id"]).'">'.$title."</a></td>".
'<td><a href="'.make_link("user/".$thread["user_name"]).'">'.$thread["user_name"]."</a></td>".
"<td>".autodate($thread["uptodate"])."</td>".
"<td>".$thread["response_count"]."</td>";
if ($showAdminOptions)
$html .= '<td><a href="'.make_link("forum/nuke/".$thread["id"]).'" title="Delete '.$title.'">Delete</a></td>';
$html .= "</tr>";
}
$html .= "</tbody></table>";
return $html;
}
}
?>