From 96495504631d6a4d466b93a835d7d66853e2e12b Mon Sep 17 00:00:00 2001 From: Michael Save Date: Fri, 13 Apr 2012 02:11:41 +1000 Subject: start on mod interface rewrite --- inc/functions.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'inc/functions.php') diff --git a/inc/functions.php b/inc/functions.php index 66fadd5e..34084bd5 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -277,10 +277,13 @@ function setupBoard($array) { $board = array( 'uri' => $array['uri'], - 'name' => $array['title'], - 'title' => $array['subtitle'] + 'title' => $array['title'], + 'subtitle' => $array['subtitle'] ); + // older versions + $board['name'] = &$board['title']; + $board['dir'] = sprintf($config['board_path'], $board['uri']); $board['url'] = sprintf($config['board_abbreviation'], $board['uri']); -- cgit v1.3 From 2caf04335830b1d3ede2452786dc19825178fd09 Mon Sep 17 00:00:00 2001 From: Michael Save Date: Sun, 15 Apr 2012 10:21:43 +1000 Subject: Bugfix: with DNSBL --- inc/functions.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'inc/functions.php') diff --git a/inc/functions.php b/inc/functions.php index 34084bd5..1d10c09a 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1242,14 +1242,14 @@ function checkDNSBL() { if (in_array($_SERVER['REMOTE_ADDR'], $config['dnsbl_exceptions'])) return; - $ip = ReverseIPOctets($_SERVER['REMOTE_ADDR']); + $ipaddr = ReverseIPOctets($_SERVER['REMOTE_ADDR']); foreach ($config['dnsbl'] as $blacklist) { - if (!is_array($blacklist) == 1) + if (!is_array($blacklist)) $blacklist = array($blacklist); - if (($lookup = str_replace('%', $ip, $blacklist[0])) == $blacklist[0]) - $lookup = $ip . '.' . $blacklist[0]; + if (($lookup = str_replace('%', $ipaddr, $blacklist[0])) == $blacklist[0]) + $lookup = $ipaddr . '.' . $blacklist[0]; if (!$ip = DNS($lookup)) continue; // not in list -- cgit v1.3 From 1d93aa51b09038485a7d8949bd94cfa02d0d4aed Mon Sep 17 00:00:00 2001 From: Michael Save Date: Thu, 19 Apr 2012 01:19:10 +1000 Subject: Bugfix: did not purge all antispam inputs --- inc/functions.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'inc/functions.php') diff --git a/inc/functions.php b/inc/functions.php index 1d10c09a..da22a094 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -860,6 +860,11 @@ function deletePost($id, $error_if_doesnt_exist=true, $rebuild_after=true) { if (!$post['thread']) { // Delete thread HTML page file_unlink($board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], $post['id'])); + + $antispam_query = prepare('DELETE FROM `antispam` WHERE `board` = :board AND `thread` = :thread'); + $antispam_query->bindValue(':board', $board['uri']); + $antispam_query->bindValue(':thread', $post['id']); + $antispam_query->execute() or error(db_error($antispam_query)); } elseif ($query->rowCount() == 1) { // Rebuild thread $rebuild = &$post['thread']; -- cgit v1.3 From 769741407c1f9a9b47f2845d2bca51f16fa52661 Mon Sep 17 00:00:00 2001 From: Michael Save Date: Thu, 19 Apr 2012 23:07:52 +1000 Subject: Bugfix: purge() while in CLI-mode --- inc/functions.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'inc/functions.php') diff --git a/inc/functions.php b/inc/functions.php index da22a094..76eeb5ad 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -338,6 +338,7 @@ function boardTitle($uri) { function purge($uri) { global $config, $debug; + if (preg_match($config['referer_match'], $config['root'])) { $uri = (str_replace('\\', '/', dirname($_SERVER['REQUEST_URI'])) == '/' ? '/' : str_replace('\\', '/', dirname($_SERVER['REQUEST_URI'])) . '/') . $uri; } else { @@ -351,7 +352,7 @@ function purge($uri) { foreach ($config['purge'] as &$purge) { $host = &$purge[0]; $port = &$purge[1]; - $http_host = isset($purge[2]) ? $purge[2] : $_SERVER['HTTP_HOST']; + $http_host = isset($purge[2]) ? $purge[2] : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost'); $request = "PURGE {$uri} HTTP/1.1\r\nHost: {$http_host}\r\nUser-Agent: Tinyboard\r\nConnection: Close\r\n\r\n"; if ($fp = fsockopen($host, $port, $errno, $errstr, $config['purge_timeout'])) { fwrite($fp, $request); @@ -402,7 +403,7 @@ function file_write($path, $data, $simple = false, $skip_purge = false) { if (!fclose($fp)) error('Unable to close file: ' . $path); - if (!$skip_purge && isset($config['purge']) && isset($_SERVER['HTTP_HOST'])) { + if (!$skip_purge && isset($config['purge'])) { // Purge cache if (basename($path) == $config['file_index']) { // Index file (/index.html); purge "/" as well -- cgit v1.3 From 256513b9b96b8af9ca106780f43c0df078cb1f9d Mon Sep 17 00:00:00 2001 From: Michael Save Date: Thu, 19 Apr 2012 23:09:51 +1000 Subject: Bugfix: with previous commit --- inc/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc/functions.php') diff --git a/inc/functions.php b/inc/functions.php index 76eeb5ad..cbb13a91 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -339,7 +339,7 @@ function boardTitle($uri) { function purge($uri) { global $config, $debug; - if (preg_match($config['referer_match'], $config['root'])) { + if (preg_match($config['referer_match'], $config['root']) && isset($_SERVER['REQUEST_URI'])) { $uri = (str_replace('\\', '/', dirname($_SERVER['REQUEST_URI'])) == '/' ? '/' : str_replace('\\', '/', dirname($_SERVER['REQUEST_URI'])) . '/') . $uri; } else { $uri = $config['root'] . $uri; -- cgit v1.3 From 53c53c57ed98aa49d2c9508de9c9b7074d4b0a6a Mon Sep 17 00:00:00 2001 From: Michael Save Date: Tue, 17 Apr 2012 08:06:25 +1000 Subject: Bugfix: with third-party scripts that use create_antibot() --- inc/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc/functions.php') diff --git a/inc/functions.php b/inc/functions.php index cbb13a91..93a30943 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -210,7 +210,7 @@ function _syslog($priority, $message) { } function create_antibot($board, $thread = null) { - require_once 'inc/anti-bot.php'; + require_once dirname(__FILE__) . '/inc/anti-bot.php'; return _create_antibot($board, $thread); } -- cgit v1.3 From b0eda5dcbc05a34ef9139578a5a43494ebdb762b Mon Sep 17 00:00:00 2001 From: Michael Save Date: Tue, 17 Apr 2012 08:16:36 +1000 Subject: Bugfix: with previous commit --- inc/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc/functions.php') diff --git a/inc/functions.php b/inc/functions.php index 93a30943..3ca5f599 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -210,7 +210,7 @@ function _syslog($priority, $message) { } function create_antibot($board, $thread = null) { - require_once dirname(__FILE__) . '/inc/anti-bot.php'; + require_once dirname(__FILE__) . '/anti-bot.php'; return _create_antibot($board, $thread); } -- cgit v1.3 From fa13f0ef35c8da2e01618c5289ecbb082bb54e73 Mon Sep 17 00:00:00 2001 From: Michael Save Date: Thu, 19 Apr 2012 23:07:52 +1000 Subject: Bugfix: purge() while in CLI-mode --- inc/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc/functions.php') diff --git a/inc/functions.php b/inc/functions.php index 3ca5f599..d9af4e6a 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -339,7 +339,7 @@ function boardTitle($uri) { function purge($uri) { global $config, $debug; - if (preg_match($config['referer_match'], $config['root']) && isset($_SERVER['REQUEST_URI'])) { + if (preg_match($config['referer_match'], $config['root'])) { $uri = (str_replace('\\', '/', dirname($_SERVER['REQUEST_URI'])) == '/' ? '/' : str_replace('\\', '/', dirname($_SERVER['REQUEST_URI'])) . '/') . $uri; } else { $uri = $config['root'] . $uri; -- cgit v1.3 From 24cc47791cb5b3bdc50e25e79b81adab5076618a Mon Sep 17 00:00:00 2001 From: Michael Save Date: Thu, 19 Apr 2012 23:09:51 +1000 Subject: Bugfix: with previous commit --- inc/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc/functions.php') diff --git a/inc/functions.php b/inc/functions.php index d9af4e6a..3ca5f599 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -339,7 +339,7 @@ function boardTitle($uri) { function purge($uri) { global $config, $debug; - if (preg_match($config['referer_match'], $config['root'])) { + if (preg_match($config['referer_match'], $config['root']) && isset($_SERVER['REQUEST_URI'])) { $uri = (str_replace('\\', '/', dirname($_SERVER['REQUEST_URI'])) == '/' ? '/' : str_replace('\\', '/', dirname($_SERVER['REQUEST_URI'])) . '/') . $uri; } else { $uri = $config['root'] . $uri; -- cgit v1.3 From a6104587203f1b1b448e6977066d6e649de91ae8 Mon Sep 17 00:00:00 2001 From: Michael Save Date: Sun, 6 May 2012 01:33:10 +1000 Subject: a lot more improvements --- inc/config.php | 5 +- inc/functions.php | 25 +- inc/mod/pages.php | 396 +++++++++++++++++++++++++++++-- install.php | 4 +- js/show-op.js | 2 - mod.php | 39 ++- templates/generic_page.html | 71 ++++++ templates/index.html | 16 +- templates/mod/ban_form.html | 20 +- templates/mod/ban_list.html | 24 +- templates/mod/board.html | 44 ++++ templates/mod/confirm.html | 4 +- templates/mod/dashboard.html | 56 ++++- templates/mod/inbox.html | 36 +++ templates/mod/log.html | 18 +- templates/mod/login.html | 4 +- templates/mod/new_pm.html | 6 +- templates/mod/news.html | 70 ++++++ templates/mod/noticeboard.html | 8 +- templates/mod/pm.html | 14 +- templates/mod/rebuild.html | 20 +- templates/mod/rebuilt.html | 4 +- templates/mod/report.html | 12 +- templates/mod/reports.html | 3 +- templates/mod/user.html | 64 +++-- templates/mod/users.html | 57 +++-- templates/mod/view_ip.html | 72 +++--- templates/page.html | 10 +- templates/themes/basic/info.php | 4 +- templates/themes/basic/theme.php | 2 +- templates/themes/categories/info.php | 4 +- templates/themes/categories/sidebar.html | 2 +- templates/themes/categories/theme.php | 12 +- templates/themes/frameset/sidebar.html | 2 +- templates/themes/frameset/theme.php | 6 +- templates/themes/recent/info.php | 6 +- templates/themes/recent/theme.php | 28 +-- templates/themes/rrdtool/info.php | 16 +- templates/themes/rrdtool/theme.php | 54 +++-- templates/thread.html | 17 +- 40 files changed, 986 insertions(+), 271 deletions(-) create mode 100644 templates/generic_page.html create mode 100644 templates/mod/board.html create mode 100644 templates/mod/inbox.html create mode 100644 templates/mod/news.html (limited to 'inc/functions.php') diff --git a/inc/config.php b/inc/config.php index 414d5262..c202d8c9 100644 --- a/inc/config.php +++ b/inc/config.php @@ -816,8 +816,6 @@ // Do a DNS lookup on IP addresses to get their hostname on the IP summary page $config['mod']['dns_lookup'] = true; - // Show ban form on the IP summary page - $config['mod']['ip_banform'] = true; // How many recent posts, per board, to show in the IP summary page $config['mod']['ip_recentposts'] = 5; @@ -829,6 +827,9 @@ // How many bans to show per page in the ban list $config['mod']['banlist_page'] = 350; + // Number of news entries to display per page + $config['mod']['news_page'] = 40; + // Maximum number of results to display for a search, per board $config['mod']['search_results'] = 75; diff --git a/inc/functions.php b/inc/functions.php index 3ca5f599..ac0a1c96 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -32,7 +32,30 @@ function loadConfig() { if (!isset($_SERVER['REMOTE_ADDR'])) $_SERVER['REMOTE_ADDR'] = '0.0.0.0'; - $arrays = array('db', 'cache', 'cookies', 'error', 'dir', 'mod', 'spam', 'flood_filters', 'wordfilters', 'custom_capcode', 'custom_tripcode', 'dnsbl', 'dnsbl_exceptions', 'remote', 'allowed_ext', 'allowed_ext_files', 'file_icons', 'footer', 'stylesheets', 'additional_javascript', 'markup'); + $arrays = array( + 'db', + 'cache', + 'cookies', + 'error', + 'dir', + 'mod', + 'spam', + 'flood_filters', + 'wordfilters', + 'custom_capcode', + 'custom_tripcode', + 'dnsbl', + 'dnsbl_exceptions', + 'remote', + 'allowed_ext', + 'allowed_ext_files', + 'file_icons', + 'footer', + 'stylesheets', + 'additional_javascript', + 'markup', + 'custom_pages' + ); $config = array(); foreach ($arrays as $key) { diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 260ad94c..c56570a5 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -9,7 +9,7 @@ if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) { exit; } -function mod_page($title, $template, $args) { +function mod_page($title, $template, $args, $subtitle = false) { global $config, $mod; echo Element('page.html', array( @@ -17,6 +17,7 @@ function mod_page($title, $template, $args) { 'mod' => $mod, 'hide_dashboard_link' => $template == 'mod/dashboard.html', 'title' => $title, + 'subtitle' => $subtitle, 'body' => Element($template, array_merge( array('config' => $config, 'mod' => $mod), @@ -28,6 +29,8 @@ function mod_page($title, $template, $args) { } function mod_login() { + global $config; + $args = array(); if (isset($_POST['login'])) { @@ -60,8 +63,14 @@ function mod_confirm($request) { mod_page('Confirm action', 'mod/confirm.html', array('request' => $request)); } +function mod_logout() { + destroyCookies(); + + header('Location: ?/', true, $config['redirect_http']); +} + function mod_dashboard() { - global $config; + global $config, $mod; $args = array(); @@ -79,9 +88,180 @@ function mod_dashboard() { } } + $query = prepare('SELECT COUNT(*) FROM `pms` WHERE `to` = :id AND `unread` = 1'); + $query->bindValue(':id', $mod['id']); + $query->execute() or error(db_error($query)); + $args['unread_pms'] = $query->fetchColumn(0); + + if ($mod['type'] >= ADMIN && $config['check_updates']) { + if (!$config['version']) + error(_('Could not find current version! (Check .installed)')); + + if (isset($_COOKIE['update'])) { + $latest = unserialize($_COOKIE['update']); + } else { + $ctx = stream_context_create(array('http' => array('timeout' => 5))); + if ($code = @file_get_contents('http://tinyboard.org/version.txt', 0, $ctx)) { + eval($code); + if (preg_match('/v(\d+)\.(\d)\.(\d+)(-dev.+)?$/', $config['version'], $matches)) { + $current = array( + 'massive' => (int) $matches[1], + 'major' => (int) $matches[2], + 'minor' => (int) $matches[3] + ); + if (isset($m[4])) { + // Development versions are always ahead in the versioning numbers + $current['minor'] --; + } + // Check if it's newer + if (!( $latest['massive'] > $current['massive'] || + $latest['major'] > $current['major'] || + ($latest['massive'] == $current['massive'] && + $latest['major'] == $current['major'] && + $latest['minor'] > $current['minor'] + ))) + $latest = false; + } else { + $latest = false; + } + } else { + // Couldn't get latest version + $latest = false; + } + + setcookie('update', serialize($latest), time() + $config['check_updates_time'], $config['cookies']['jail'] ? $config['cookies']['path'] : '/', null, false, true); + } + + if ($latest) + $args['newer_release'] = $latest; + } + mod_page('Dashboard', 'mod/dashboard.html', $args); } +function mod_edit_board($boardName) { + global $board, $config; + + if (!openBoard($boardName)) + error($config['error']['noboard']); + + if (!hasPermission($config['mod']['manageboards'], $board['uri'])) + error($config['error']['noaccess']); + + if (isset($_POST['title'], $_POST['subtitle'])) { + if (isset($_POST['delete'])) { + if (!hasPermission($config['mod']['manageboards'], $board['uri'])) + error($config['error']['deleteboard']); + + $query = prepare('DELETE FROM `boards` WHERE `uri` = :uri'); + $query->bindValue(':uri', $board['uri']); + $query->execute() or error(db_error($query)); + + modLog('Deleted board: ' . sprintf($config['board_abbreviation'], $board['uri']), false); + + // Delete entire board directory + rrmdir($board['uri'] . '/'); + + // Delete posting table + $query = query(sprintf('DROP TABLE IF EXISTS `posts_%s`', $board['uri'])) or error(db_error()); + + // Clear reports + $query = prepare('DELETE FROM `reports` WHERE `board` = :id'); + $query->bindValue(':id', $board['uri'], PDO::PARAM_INT); + $query->execute() or error(db_error($query)); + + // Delete from table + $query = prepare('DELETE FROM `boards` WHERE `uri` = :uri'); + $query->bindValue(':uri', $board['uri'], PDO::PARAM_INT); + $query->execute() or error(db_error($query)); + + if ($config['cache']['enabled']) { + cache::delete('board_' . $board['uri']); + cache::delete('all_boards'); + } + + $query = prepare("SELECT `board`, `post` FROM `cites` WHERE `target_board` = :board"); + $query->bindValue(':board', $board['uri']); + $query->execute() or error(db_error($query)); + while ($cite = $query->fetch(PDO::FETCH_ASSOC)) { + if ($board['uri'] != $cite['board']) { + if (!isset($tmp_board)) + $tmp_board = $board; + openBoard($cite['board']); + rebuildPost($cite['post']); + } + } + + $query = prepare('DELETE FROM `cites` WHERE `board` = :board OR `target_board` = :board'); + $query->bindValue(':board', $board['uri']); + $query->execute() or error(db_error($query)); + + $query = prepare('DELETE FROM `antispam` WHERE `board` = :board'); + $query->bindValue(':board', $board['uri']); + $query->execute() or error(db_error($query)); + } else { + $query = prepare('UPDATE `boards` SET `title` = :title, `subtitle` = :subtitle WHERE `uri` = :uri'); + $query->bindValue(':uri', $board['uri']); + $query->bindValue(':title', $_POST['title']); + $query->bindValue(':subtitle', $_POST['subtitle']); + $query->execute() or error(db_error($query)); + } + + rebuildThemes('boards'); + + header('Location: ?/', true, $config['redirect_http']); + } else { + mod_page('Edit board: ' . sprintf($config['board_abbreviation'], $board['uri']), 'mod/board.html', array('board' => $board)); + } +} + +function mod_new_board() { + global $config, $board; + + if (!hasPermission($config['mod']['newboard'])) + error($config['error']['noaccess']); + + if (isset($_POST['uri'], $_POST['title'], $_POST['subtitle'])) { + if ($_POST['uri'] == '') + error(sprintf($config['error']['required'], 'URI')); + + if ($_POST['title'] == '') + error(sprintf($config['error']['required'], 'title')); + + if (!preg_match('/^\w+$/', $_POST['uri'])) + error(sprintf($config['error']['invalidfield'], 'URI')); + + if (openBoard($_POST['uri'])) { + error(sprintf($config['error']['boardexists'], $board['url'])); + } + + $query = prepare('INSERT INTO `boards` VALUES (:uri, :title, :subtitle)'); + $query->bindValue(':uri', $_POST['uri']); + $query->bindValue(':title', $_POST['title']); + $query->bindValue(':subtitle', $_POST['subtitle']); + $query->execute() or error(db_error($query)); + + modLog('Created a new board: ' . sprintf($config['board_abbreviation'], $_POST['uri'])); + + if (!openBoard($_POST['uri'])) + error(_("Couldn't open board after creation.")); + + query(Element('posts.sql', array('board' => $board['uri']))) or error(db_error()); + + if ($config['cache']['enabled']) + cache::delete('all_boards'); + + // Build the board + buildIndex(); + + rebuildThemes('boards'); + + header('Location: ?/' . $board['uri'] . '/' . $config['file_index'], true, $config['redirect_http']); + } + + mod_page('New board', 'mod/board.html', array('new' => true)); +} + function mod_noticeboard($page_no = 1) { global $config, $pdo, $mod; @@ -104,9 +284,11 @@ function mod_noticeboard($page_no = 1) { $query->bindValue(':body', $_POST['body']); $query->execute() or error(db_error($query)); - if($config['cache']['enabled']) + if ($config['cache']['enabled']) cache::delete('noticeboard_preview'); + modLog('Posted a noticeboard entry'); + header('Location: ?/noticeboard#' . $pdo->lastInsertId(), true, $config['redirect_http']); } @@ -126,6 +308,78 @@ function mod_noticeboard($page_no = 1) { mod_page('Noticeboard', 'mod/noticeboard.html', array('noticeboard' => $noticeboard, 'count' => $count)); } +function mod_noticeboard_delete($id) { + global $config; + + if (!hasPermission($config['mod']['noticeboard_delete'])) + error($config['error']['noaccess']); + + $query = prepare('DELETE FROM `noticeboard` WHERE `id` = :id'); + $query->bindValue(':id', $id); + $query->execute() or error(db_error($query)); + + modLog('Deleted a noticeboard entry'); + + header('Location: ?/noticeboard', true, $config['redirect_http']); +} + +function mod_news($page_no = 1) { + global $config, $pdo, $mod; + + if ($page_no < 1) + error($config['error']['404']); + + if (isset($_POST['subject'], $_POST['body'])) { + if (!hasPermission($config['mod']['news'])) + error($config['error']['noaccess']); + + markup($_POST['body']); + + $query = prepare('INSERT INTO `news` VALUES (NULL, :name, :time, :subject, :body)'); + $query->bindValue(':name', isset($_POST['name']) && hasPermission($config['mod']['news_custom']) ? $_POST['name'] : $mod['username']); + $query->bindvalue(':time', time()); + $query->bindValue(':subject', $_POST['subject']); + $query->bindValue(':body', $_POST['body']); + $query->execute() or error(db_error($query)); + + modLog('Posted a news entry'); + + rebuildThemes('news'); + + header('Location: ?/news#' . $pdo->lastInsertId(), true, $config['redirect_http']); + } + + $query = prepare("SELECT * FROM `news` ORDER BY `id` DESC LIMIT :offset, :limit"); + $query->bindValue(':limit', $config['mod']['news_page'], PDO::PARAM_INT); + $query->bindValue(':offset', ($page_no - 1) * $config['mod']['news_page'], PDO::PARAM_INT); + $query->execute() or error(db_error($query)); + $news = $query->fetchAll(PDO::FETCH_ASSOC); + + if (empty($news) && $page_no > 1) + error($config['error']['404']); + + $query = prepare("SELECT COUNT(*) FROM `news`"); + $query->execute() or error(db_error($query)); + $count = $query->fetchColumn(0); + + mod_page('News', 'mod/news.html', array('news' => $news, 'count' => $count)); +} + +function mod_news_delete($id) { + global $config; + + if (!hasPermission($config['mod']['news_delete'])) + error($config['error']['noaccess']); + + $query = prepare('DELETE FROM `news` WHERE `id` = :id'); + $query->bindValue(':id', $id); + $query->execute() or error(db_error($query)); + + modLog('Deleted a news entry'); + + header('Location: ?/news', true, $config['redirect_http']); +} + function mod_log($page_no = 1) { global $config; @@ -135,7 +389,7 @@ function mod_log($page_no = 1) { if (!hasPermission($config['mod']['modlog'])) error($config['error']['noaccess']); - $query = prepare("SELECT `username`, `ip`, `board`, `time`, `text` FROM `modlogs` LEFT JOIN `mods` ON `mod` = `mods`.`id` ORDER BY `time` DESC LIMIT :offset, :limit"); + $query = prepare("SELECT `username`, `mod`, `ip`, `board`, `time`, `text` FROM `modlogs` LEFT JOIN `mods` ON `mod` = `mods`.`id` ORDER BY `time` DESC LIMIT :offset, :limit"); $query->bindValue(':limit', $config['mod']['modlog_page'], PDO::PARAM_INT); $query->bindValue(':offset', ($page_no - 1) * $config['mod']['modlog_page'], PDO::PARAM_INT); $query->execute() or error(db_error($query)); @@ -196,7 +450,7 @@ function mod_ip_remove_note($ip, $id) { modLog("Removed a note for {$ip}"); - header('Location: ?/IP/' . $ip, true, $config['redirect_http']); + header('Location: ?/IP/' . $ip . '#notes', true, $config['redirect_http']); } function mod_page_ip($ip) { @@ -212,7 +466,8 @@ function mod_page_ip($ip) { require_once 'inc/mod/ban.php'; unban($_POST['ban_id']); - header('Location: ?/IP/' . $ip, true, $config['redirect_http']); + + header('Location: ?/IP/' . $ip . '#bans', true, $config['redirect_http']); return; } @@ -230,7 +485,7 @@ function mod_page_ip($ip) { modLog("Added a note for {$ip}"); - header('Location: ?/IP/' . $ip, true, $config['redirect_http']); + header('Location: ?/IP/' . $ip . '#notes', true, $config['redirect_http']); return; } @@ -238,6 +493,9 @@ function mod_page_ip($ip) { $args['ip'] = $ip; $args['posts'] = array(); + if ($config['mod']['dns_lookup']) + $args['hostname'] = rDNS($ip); + $boards = listBoards(); foreach ($boards as $board) { openBoard($board['uri']); @@ -287,7 +545,7 @@ function mod_page_ip($ip) { $args['notes'] = $query->fetchAll(PDO::FETCH_ASSOC); } - mod_page("IP: $ip", 'mod/view_ip.html', $args); + mod_page("IP: $ip", 'mod/view_ip.html', $args, $args['hostname']); } function mod_ban() { @@ -382,7 +640,7 @@ function mod_lock($board, $unlock, $post) { $query->bindValue(':id', $post); $query->bindValue(':locked', $unlock ? 0 : 1); $query->execute() or error(db_error($query)); - if($query->rowCount()) { + if ($query->rowCount()) { modLog(($unlock ? 'Unlocked' : 'Locked') . " thread #{$post}"); buildThread($post); buildIndex(); @@ -404,7 +662,7 @@ function mod_sticky($board, $unsticky, $post) { $query->bindValue(':id', $post); $query->bindValue(':sticky', $unsticky ? 0 : 1); $query->execute() or error(db_error($query)); - if($query->rowCount()) { + if ($query->rowCount()) { modLog(($unlock ? 'Unstickied' : 'Stickied') . " thread #{$post}"); buildThread($post); buildIndex(); @@ -426,7 +684,7 @@ function mod_bumplock($board, $unbumplock, $post) { $query->bindValue(':id', $post); $query->bindValue(':bumplock', $unbumplock ? 0 : 1); $query->execute() or error(db_error($query)); - if($query->rowCount()) { + if ($query->rowCount()) { modLog(($unlock ? 'Unbumplocked' : 'Bumplocked') . " thread #{$post}"); buildThread($post); buildIndex(); @@ -447,7 +705,7 @@ function mod_ban_post($board, $delete, $post) { $query = prepare(sprintf('SELECT `ip`, `thread` FROM `posts_%s` WHERE `id` = :id', $board)); $query->bindValue(':id', $post); $query->execute() or error(db_error($query)); - if(!$_post = $query->fetch(PDO::FETCH_ASSOC)) + if (!$_post = $query->fetch(PDO::FETCH_ASSOC)) error($config['error']['404']); $thread = $_post['thread']; @@ -624,25 +882,54 @@ function mod_user($uid) { } } + if (isset($_POST['delete'])) { + if (!hasPermission($config['mod']['deleteusers'])) + error($config['error']['noaccess']); + + $query = prepare('DELETE FROM `mods` WHERE `id` = :id'); + $query->bindValue(':id', $uid); + $query->execute() or error(db_error($query)); + + modLog('Deleted user ' . utf8tohtml($user['username']) . ' (#' . $user['id'] . ')'); + + header('Location: ?/users', true, $config['redirect_http']); + + return; + } + + if ($_POST['username'] == '') + error(sprintf($config['error']['required'], 'username')); + $query = prepare('UPDATE `mods` SET `username` = :username, `boards` = :boards WHERE `id` = :id'); $query->bindValue(':id', $uid); $query->bindValue(':username', $_POST['username']); $query->bindValue(':boards', implode(',', $boards)); $query->execute() or error(db_error($query)); + if ($user['username'] !== $_POST['username']) { + // account was renamed + modLog('Renamed user "' . utf8tohtml($user['username']) . '" (#' . $user['id'] . ') to "' . utf8tohtml($_POST['username']) . '"'); + } + if ($_POST['password'] != '') { $query = prepare('UPDATE `mods` SET `password` = SHA1(:password) WHERE `id` = :id'); $query->bindValue(':id', $uid); $query->bindValue(':password', $_POST['password']); $query->execute() or error(db_error($query)); + modLog('Changed password for ' . utf8tohtml($_POST['username']) . ' (#' . $user['id'] . ')'); + if ($uid == $mod['id']) { login($_POST['username'], $_POST['password']); setCookies(); } } - header('Location: ?/users', true, $config['redirect_http']); + if (hasPermission($config['mod']['manageusers'])) + header('Location: ?/users', true, $config['redirect_http']); + else + header('Location: ?/', true, $config['redirect_http']); + return; } @@ -653,11 +940,17 @@ function mod_user($uid) { $query->bindValue(':password', $_POST['password']); $query->execute() or error(db_error($query)); - login($_POST['username'], $_POST['password']); + modLog('Changed own password'); + + login($user['username'], $_POST['password']); setCookies(); } - header('Location: ?/users', true, $config['redirect_http']); + if (hasPermission($config['mod']['manageusers'])) + header('Location: ?/users', true, $config['redirect_http']); + else + header('Location: ?/', true, $config['redirect_http']); + return; } @@ -675,6 +968,47 @@ function mod_user($uid) { mod_page('Edit user', 'mod/user.html', array('user' => $user, 'logs' => $log, 'boards' => listBoards())); } +function mod_user_new() { + if (isset($_POST['username'], $_POST['password'], $_POST['type'])) { + if ($_POST['username'] == '') + error(sprintf($config['error']['required'], 'username')); + if ($_POST['password'] == '') + error(sprintf($config['error']['required'], 'password')); + + if (isset($_POST['allboards'])) { + $boards = array('*'); + } else { + $_boards = listBoards(); + foreach ($_boards as &$board) { + $board = $board['uri']; + } + + $boards = array(); + foreach ($_POST as $name => $value) { + if (preg_match('/^board_(\w+)$/', $name, $matches) && in_array($matches[1], $_boards)) + $boards[] = $matches[1]; + } + } + + $_POST['type'] = (int) $_POST['type']; + if ($_POST['type'] !== JANITOR && $_POST['type'] !== MOD && $_POST['type'] !== ADMIN) + error(sprintf($config['error']['invalidfield'], 'type')); + + $query = prepare('INSERT INTO `mods` VALUES (NULL, :username, SHA1(:password), :type, :boards)'); + $query->bindValue(':username', $_POST['username']); + $query->bindValue(':password', $_POST['password']); + $query->bindValue(':type', $_POST['type']); + $query->bindValue(':boards', implode(',', $boards)); + $query->execute() or error(db_error($query)); + + header('Location: ?/users', true, $config['redirect_http']); + return; + } + + mod_page('Edit user', 'mod/user.html', array('new' => true, 'boards' => listBoards())); +} + + function mod_users() { global $config; @@ -734,12 +1068,38 @@ function mod_pm($id, $reply = false) { if (!$pm['to_username']) error($config['error']['404']); // deleted? - mod_page("New PM for {$pm['to_username']}", 'mod/new_pm.html', array('username' => $pm['to_username'], 'id' => $pm['to'], 'message' => quote($pm['message']))); + mod_page("New PM for {$pm['to_username']}", 'mod/new_pm.html', array( + 'username' => $pm['username'], 'id' => $pm['sender'], 'message' => quote($pm['message']) + )); } else { mod_page("Private message – #$id", 'mod/pm.html', $pm); } } +function mod_inbox() { + global $config, $mod; + + $query = prepare('SELECT `unread`,`pms`.`id`, `time`, `sender`, `to`, `message`, `username` FROM `pms` LEFT JOIN `mods` ON `mods`.`id` = `sender` WHERE `to` = :mod ORDER BY `unread` DESC, `time` DESC'); + $query->bindValue(':mod', $mod['id']); + $query->execute() or error(db_error($query)); + $messages = $query->fetchAll(PDO::FETCH_ASSOC); + + $query = prepare('SELECT COUNT(*) FROM `pms` WHERE `to` = :mod AND `unread` = 1'); + $query->bindValue(':mod', $mod['id']); + $query->execute() or error(db_error($query)); + $unread = $query->fetchColumn(0); + + foreach ($messages as &$message) { + $message['snippet'] = pm_snippet($message['message']); + } + + mod_page('PM inbox (' . (count($messages) > 0 ? $unread . ' unread' : 'empty') . ')', 'mod/inbox.html', array( + 'messages' => $messages, + 'unread' => $unread + )); +} + + function mod_new_pm($username) { global $config, $mod; @@ -920,7 +1280,7 @@ function mod_reports() { $body .= $po->build(true) . '
'; - if(isset($__old_body_truncate_char)) + if (isset($__old_body_truncate_char)) $config['body_truncate_char'] = $__old_body_truncate_char; } @@ -971,7 +1331,7 @@ function mod_debug_antispam() { if (isset($_POST['board'], $_POST['thread'])) { $where = '`board` = ' . $pdo->quote($_POST['board']); - if($_POST['thread'] != '') + if ($_POST['thread'] != '') $where .= ' AND `thread` = ' . $pdo->quote($_POST['thread']); if (isset($_POST['purge'])) { diff --git a/install.php b/install.php index 2e732c4c..1e872911 100644 --- a/install.php +++ b/install.php @@ -1,7 +1,7 @@ ':?/', // redirect to dashboard '!^/$!' => 'dashboard', // dashboard '!^/confirm/(.+)$!' => 'confirm', // confirm action (if javascript didn't work) + '!^/logout$!' => 'logout', // logout '!^/users$!' => 'users', // manage users '!^/users/(\d+)$!' => 'user', // edit user '!^/users/(\d+)/(promote|demote)$!' => 'user_promote', // prmote/demote user + '!^/users/new$!' => 'user_new', // create a new user '!^/new_PM/([^/]+)$!' => 'new_pm', // create a new pm '!^/PM/(\d+)(/reply)?$!' => 'pm', // read a pm + '!^/inbox$!' => 'inbox', // pm inbox '!^/noticeboard$!' => 'noticeboard', // view noticeboard '!^/noticeboard/(\d+)$!' => 'noticeboard', // view noticeboard + '!^/noticeboard/delete/(\d+)$!' => 'noticeboard_delete',// delete from noticeboard '!^/log$!' => 'log', // modlog '!^/log/(\d+)$!' => 'log', // modlog + '!^/news$!' => 'news', // view news + '!^/news/(\d+)$!' => 'news', // view news + '!^/news/delete/(\d+)$!' => 'news_delete', // delete from news + + '!^/edit/(\w+)$!' => 'edit_board', // edit board details + '!^/new-board$!' => 'new_board', // create a new board + '!^/rebuild$!' => 'rebuild', // rebuild static files '!^/reports$!' => 'reports', // report queue '!^/reports/(\d+)/dismiss(all)?$!' => 'report_dismiss', // dismiss a report @@ -64,8 +75,14 @@ $pages = array( str_replace('%d', '(\d+)', preg_quote($config['file_page'], '!')) . '$!' => 'view_thread', ); -if (!$mod) + +if (!$mod) { $pages = array('//' => 'login'); +} elseif (isset($_GET['status'], $_GET['r'])) { + header('Location: ' . $_GET['r'], true, (int)$_GET['stats']); +} elseif (isset($config['mod']['custom_pages'])) { + $pages = array_merge($pages, $config['mod']['custom_pages']); +} foreach ($pages as $uri => $handler) { if (preg_match($uri, $query, $matches)) { @@ -79,14 +96,20 @@ foreach ($pages as $uri => $handler) { ); } - if ($handler[0] == ':') { - header('Location: ' . substr($handler, 1), true, $config['redirect_http']); - } elseif (is_callable("mod_page_$handler")) { - call_user_func_array("mod_page_$handler", $matches); - } elseif (is_callable("mod_$handler")) { - call_user_func_array("mod_$handler", $matches); + if (is_string($handler)) { + if ($handler[0] == ':') { + header('Location: ' . substr($handler, 1), true, $config['redirect_http']); + } elseif (is_callable("mod_page_$handler")) { + call_user_func_array("mod_page_$handler", $matches); + } elseif (is_callable("mod_$handler")) { + call_user_func_array("mod_$handler", $matches); + } else { + error("Mod page '$handler' not found!"); + } + } elseif (is_callable($handler)) { + call_user_func_array($handler, $matches); } else { - error("Mod page '$handler' not found!"); + error("Mod page '$handler' not a string, and not callable!"); } exit; diff --git a/templates/generic_page.html b/templates/generic_page.html new file mode 100644 index 00000000..e834aad0 --- /dev/null +++ b/templates/generic_page.html @@ -0,0 +1,71 @@ + + + + {% block head %} + + {% if config.url_favicon %}{% endif %} + {{ board.url }} - {{ board.name }} + + + {% if config.meta_keywords %}{% endif %} + {% if config.default_stylesheet.1 != '' %}{% endif %} + {% if not nojavascript %} + + {% if not config.additional_javascript_compile %} + {% for javascript in config.additional_javascript %}{% endfor %} + {% endif %} + {% endif %} + {% if config.recaptcha %}{% endif %} + {% endblock %} + + + {{ boardlist.top }} + {% if pm %}
You have an unread PM{% if pm.waiting > 0 %}, plus {{ pm.waiting }} more waiting{% endif %}.

{% endif %} + {% if config.url_banner %}{% endif %} +
+

{{ board.url }} - {{ board.name }}

+
+ {% if board.title %} + {{ board.title|e }} + {% endif %} + {% if mod %}

{% trans %}Return to dashboard{% endtrans %}

{% endif %} +
+
+ + {% include 'post_form.html' %} + + {% if config.blotter %}
{{ config.blotter }}
{% endif %} +
+
+ + {% if mod %}{% endif %} + {{ body }} + {% include 'report_delete.html' %} +
+
{{ btn.prev }} {% for page in pages %} + [{{ page.num }}]{% if loop.last %} {% endif %} + {% endfor %} {{ btn.next }}
+ {{ boardlist.bottom }} +
+

Powered by Tinyboard {{ config.version }} | Tinyboard Copyright © 2010-2012 Tinyboard Development Group

+ {% for footer in config.footer %}

{{ footer }}

{% endfor %} +
+ + + diff --git a/templates/index.html b/templates/index.html index f12e2517..a28724a1 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,13 +1,13 @@ - - {% if config.url_favicon %}{% endif %} + + + {% if config.url_favicon %}{% endif %} {{ board.url }} - {{ board.name }} - - - {% if config.meta_keywords %}{% endif %} - + + {% if config.meta_keywords %}{% endif %} + {% if config.default_stylesheet.1 != '' %}{% endif %} {% if not nojavascript %} {% if not config.additional_javascript_compile %} @@ -35,10 +35,10 @@ {% if pm %}
You have an unread PM{% if pm.waiting > 0 %}, plus {{ pm.waiting }} more waiting{% endif %}.

{% endif %} {% if config.url_banner %}{% endif %}
-

{{ board.url }} - {{ board.title }}

+

{{ board.url }} - {{ board.title|e }}

{% if board.subtitle %} - {{ board.subtitle }} + {{ board.subtitle|e }} {% endif %} {% if mod %}

{% trans %}Return to dashboard{% endtrans %}

{% endif %}
diff --git a/templates/mod/ban_form.html b/templates/mod/ban_form.html index 9d4d6728..5d5f2b81 100644 --- a/templates/mod/ban_form.html +++ b/templates/mod/ban_form.html @@ -16,19 +16,19 @@ - + {% if not hide_ip %} {% else %} - hidden + {% trans 'hidden' %} {% endif %} - + @@ -37,12 +37,12 @@ {% if post and board and not delete %} - + - (public; attached to post) + ({% trans 'public; attached to post' %}) {% endif %} diff --git a/templates/themes/basic/info.php b/templates/themes/basic/info.php index b782a6d4..0b8ba98b 100644 --- a/templates/themes/basic/info.php +++ b/templates/themes/basic/info.php @@ -44,9 +44,9 @@ $theme['build_function'] = 'basic_build'; $theme['install_callback'] = 'build_install'; - if(!function_exists('build_install')) { + if (!function_exists('build_install')) { function build_install($settings) { - if(!is_numeric($settings['no_recent']) || $settings['no_recent'] < 0) + if (!is_numeric($settings['no_recent']) || $settings['no_recent'] < 0) return Array(false, '' . utf8tohtml($settings['no_recent']) . ' is not a non-negative integer.'); } } diff --git a/templates/themes/basic/theme.php b/templates/themes/basic/theme.php index a07dc7ec..806a331a 100644 --- a/templates/themes/basic/theme.php +++ b/templates/themes/basic/theme.php @@ -15,7 +15,7 @@ public static function build($action, $settings) { global $config; - if($action == 'all' || $action == 'news') + if ($action == 'all' || $action == 'news') file_write($config['dir']['home'] . $settings['file'], Basic::homepage($settings)); } diff --git a/templates/themes/categories/info.php b/templates/themes/categories/info.php index 5ae3d296..62d8f6bb 100644 --- a/templates/themes/categories/info.php +++ b/templates/themes/categories/info.php @@ -54,11 +54,11 @@ Requires $config[\'categories\'].'; $theme['build_function'] = 'categories_build'; $theme['install_callback'] = 'categories_install'; - if(!function_exists('categories_install')) { + if (!function_exists('categories_install')) { function categories_install($settings) { global $config; - if(!isset($config['categories'])) { + if (!isset($config['categories'])) { return Array(false, '

Prerequisites not met!

' . 'This theme requires $config[\'boards\'] and $config[\'categories\'] to be set.'); } diff --git a/templates/themes/categories/sidebar.html b/templates/themes/categories/sidebar.html index a4bc28ae..856930ab 100644 --- a/templates/themes/categories/sidebar.html +++ b/templates/themes/categories/sidebar.html @@ -31,7 +31,7 @@ {% for board in boards %}
  • - {{ board.title }} + {{ board.title|e }}
  • {% endfor %} diff --git a/templates/themes/categories/theme.php b/templates/themes/categories/theme.php index 648034e7..11fcbbaf 100644 --- a/templates/themes/categories/theme.php +++ b/templates/themes/categories/theme.php @@ -15,13 +15,13 @@ public static function build($action, $settings) { global $config; - if($action == 'all') + if ($action == 'all') file_write($config['dir']['home'] . $settings['file_main'], Categories::homepage($settings)); - if($action == 'all' || $action == 'boards') + if ($action == 'all' || $action == 'boards') file_write($config['dir']['home'] . $settings['file_sidebar'], Categories::sidebar($settings)); - if($action == 'all' || $action == 'news') + if ($action == 'all' || $action == 'news') file_write($config['dir']['home'] . $settings['file_news'], Categories::news($settings)); } @@ -52,10 +52,10 @@ $categories = $config['categories']; - foreach($categories as &$boards) { - foreach($boards as &$board) { + foreach ($categories as &$boards) { + foreach ($boards as &$board) { $title = boardTitle($board); - if(!$title) + if (!$title) $title = $board; // board doesn't exist, but for some reason you want to display it anyway $board = Array('title' => $title, 'uri' => sprintf($config['board_path'], $board)); } diff --git a/templates/themes/frameset/sidebar.html b/templates/themes/frameset/sidebar.html index 457ecec8..40e2d719 100644 --- a/templates/themes/frameset/sidebar.html +++ b/templates/themes/frameset/sidebar.html @@ -30,7 +30,7 @@ {% for board in boards %}
  • - {{ board.title }} + {{ board.title|e }}
  • {% endfor %} diff --git a/templates/themes/frameset/theme.php b/templates/themes/frameset/theme.php index f3e1b139..015eebaf 100644 --- a/templates/themes/frameset/theme.php +++ b/templates/themes/frameset/theme.php @@ -15,13 +15,13 @@ public static function build($action, $settings) { global $config; - if($action == 'all') + if ($action == 'all') file_write($config['dir']['home'] . $settings['file_main'], Frameset::homepage($settings)); - if($action == 'all' || $action == 'boards') + if ($action == 'all' || $action == 'boards') file_write($config['dir']['home'] . $settings['file_sidebar'], Frameset::sidebar($settings)); - if($action == 'all' || $action == 'news') + if ($action == 'all' || $action == 'news') file_write($config['dir']['home'] . $settings['file_news'], Frameset::news($settings)); } diff --git a/templates/themes/recent/info.php b/templates/themes/recent/info.php index 83d7477a..d4cf1029 100644 --- a/templates/themes/recent/info.php +++ b/templates/themes/recent/info.php @@ -60,11 +60,11 @@ $theme['build_function'] = 'recentposts_build'; $theme['install_callback'] = 'recentposts_install'; - if(!function_exists('recentposts_install')) { + if (!function_exists('recentposts_install')) { function recentposts_install($settings) { - if(!is_numeric($settings['limit_images']) || $settings['limit_images'] < 0) + if (!is_numeric($settings['limit_images']) || $settings['limit_images'] < 0) return Array(false, '' . utf8tohtml($settings['limit_images']) . ' is not a non-negative integer.'); - if(!is_numeric($settings['limit_posts']) || $settings['limit_posts'] < 0) + if (!is_numeric($settings['limit_posts']) || $settings['limit_posts'] < 0) return Array(false, '' . utf8tohtml($settings['limit_posts']) . ' is not a non-negative integer.'); } } diff --git a/templates/themes/recent/theme.php b/templates/themes/recent/theme.php index 13a5546f..986fac6a 100644 --- a/templates/themes/recent/theme.php +++ b/templates/themes/recent/theme.php @@ -17,13 +17,13 @@ public function build($action, $settings) { global $config, $_theme; - if($action == 'all') { + if ($action == 'all') { copy('templates/themes/recent/recent.css', $config['dir']['home'] . $settings['css']); } $this->excluded = explode(' ', $settings['exclude']); - if($action == 'all' || $action == 'post') + if ($action == 'all' || $action == 'post') file_write($config['dir']['home'] . $settings['html'], $this->homepage($settings)); } @@ -38,15 +38,15 @@ $boards = listBoards(); $query = ''; - foreach($boards as &$_board) { - if(in_array($_board['uri'], $this->excluded)) + foreach ($boards as &$_board) { + if (in_array($_board['uri'], $this->excluded)) continue; $query .= sprintf("SELECT *, '%s' AS `board` FROM `posts_%s` WHERE `file` IS NOT NULL AND `file` != 'deleted' AND `thumb` != 'spoiler' UNION ALL ", $_board['uri'], $_board['uri']); } $query = preg_replace('/UNION ALL $/', 'ORDER BY `time` DESC LIMIT ' . (int)$settings['limit_images'], $query); $query = query($query) or error(db_error()); - while($post = $query->fetch()) { + while ($post = $query->fetch()) { openBoard($post['board']); // board settings won't be available in the template file, so generate links now @@ -58,15 +58,15 @@ $query = ''; - foreach($boards as &$_board) { - if(in_array($_board['uri'], $this->excluded)) + foreach ($boards as &$_board) { + if (in_array($_board['uri'], $this->excluded)) continue; $query .= sprintf("SELECT *, '%s' AS `board` FROM `posts_%s` UNION ALL ", $_board['uri'], $_board['uri']); } $query = preg_replace('/UNION ALL $/', 'ORDER BY `time` DESC LIMIT ' . (int)$settings['limit_posts'], $query); $query = query($query) or error(db_error()); - while($post = $query->fetch()) { + while ($post = $query->fetch()) { openBoard($post['board']); $post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], ($post['thread'] ? $post['thread'] : $post['id'])) . '#' . $post['id']; @@ -78,8 +78,8 @@ // Total posts $query = 'SELECT SUM(`top`) AS `count` FROM ('; - foreach($boards as &$_board) { - if(in_array($_board['uri'], $this->excluded)) + foreach ($boards as &$_board) { + if (in_array($_board['uri'], $this->excluded)) continue; $query .= sprintf("SELECT MAX(`id`) AS `top` FROM `posts_%s` UNION ALL ", $_board['uri']); } @@ -90,8 +90,8 @@ // Unique IPs $query = 'SELECT COUNT(DISTINCT(`ip`)) AS `count` FROM ('; - foreach($boards as &$_board) { - if(in_array($_board['uri'], $this->excluded)) + foreach ($boards as &$_board) { + if (in_array($_board['uri'], $this->excluded)) continue; $query .= sprintf("SELECT `ip` FROM `posts_%s` UNION ALL ", $_board['uri']); } @@ -102,8 +102,8 @@ // Active content $query = 'SELECT SUM(`filesize`) AS `count` FROM ('; - foreach($boards as &$_board) { - if(in_array($_board['uri'], $this->excluded)) + foreach ($boards as &$_board) { + if (in_array($_board['uri'], $this->excluded)) continue; $query .= sprintf("SELECT `filesize` FROM `posts_%s` UNION ALL ", $_board['uri']); } diff --git a/templates/themes/rrdtool/info.php b/templates/themes/rrdtool/info.php index 73658a22..46a20587 100644 --- a/templates/themes/rrdtool/info.php +++ b/templates/themes/rrdtool/info.php @@ -28,7 +28,7 @@ $__boards = listBoards(); $__default_boards = Array(); - foreach($__boards as $__board) + foreach ($__boards as $__board) $__default_boards[] = $__board['uri']; $theme['config'][] = Array( @@ -83,31 +83,31 @@ ); $theme['install_callback'] = 'rrdtool_install'; - if(!function_exists('rrdtool_install')) { + if (!function_exists('rrdtool_install')) { function rrdtool_install($settings) { global $config; - if(!is_numeric($settings['interval']) || $settings['interval'] < 1 || $settings['interval'] > 86400) + if (!is_numeric($settings['interval']) || $settings['interval'] < 1 || $settings['interval'] > 86400) return Array(false, 'Invalid interval: ' . $settings['interval'] . '. Must be an integer greater than 1 and less than 86400.'); - if(!is_numeric($settings['width']) || $settings['width'] < 1) + if (!is_numeric($settings['width']) || $settings['width'] < 1) return Array(false, 'Invalid width: ' . $settings['width'] . '!'); - if(!is_numeric($settings['height']) || $settings['height'] < 1) + if (!is_numeric($settings['height']) || $settings['height'] < 1) return Array(false, 'Invalid height: ' . $settings['height'] . '!'); - if(!in_array($settings['rate'], Array('second', 'minute', 'day', 'hour', 'week', 'month', 'year'))) + if (!in_array($settings['rate'], Array('second', 'minute', 'day', 'hour', 'week', 'month', 'year'))) return Array(false, 'Invalid rate: ' . $settings['rate'] . '!'); $job = '*/' . $settings['interval'] . ' * * * * php -q ' . str_replace('\\', '/', dirname(__FILE__)) . '/cron.php' . PHP_EOL; - if(function_exists('system')) { + if (function_exists('system')) { $crontab = tempnam($config['tmp'], 'tinyboard-rrdtool'); file_write($crontab, $job); @system('crontab ' . escapeshellarg($crontab), $ret); unlink($crontab); - if($ret === 0) + if ($ret === 0) return ''; // it seems to install okay? } diff --git a/templates/themes/rrdtool/theme.php b/templates/themes/rrdtool/theme.php index 20a00e76..eed2ac9a 100644 --- a/templates/themes/rrdtool/theme.php +++ b/templates/themes/rrdtool/theme.php @@ -17,7 +17,7 @@ public function build($action, $settings) { global $config, $_theme, $argv; - if(!$settings) { + if (!$settings) { error('This theme is not currently installed.'); } @@ -26,18 +26,18 @@ // exclude boards from the "combined" graph $this->combined_exclude = Array(); - if($action == 'cron') { - if(!file_exists($settings['path'])) + if ($action == 'cron') { + if (!file_exists($settings['path'])) mkdir($settings['path']); - if(!file_exists($settings['images'])) + if (!file_exists($settings['images'])) mkdir($settings['images']); - foreach($this->boards as &$board) { + foreach ($this->boards as &$board) { $file = $settings['path'] . '/' . $board . '.rrd'; - if(!file_exists($file)) { + if (!file_exists($file)) { // Create graph - if(!rrd_create($file, Array( + if (!rrd_create($file, Array( '-s 60', 'DS:posts:COUNTER:86400:0:10000', @@ -59,22 +59,22 @@ } // debug just the graphing (not updating) with the --debug switch - if(!isset($argv[1]) || $argv[1] != '--debug') { + if (!isset($argv[1]) || $argv[1] != '--debug') { // Update graph $query = query(sprintf("SELECT MAX(`id`) AS `count` FROM `posts_%s`", $board)); $count = $query->fetch(); $count = $count['count']; - if(!rrd_update($file, Array( + if (!rrd_update($file, Array( '-t', 'posts', 'N:' . $count))) error('RRDtool failed: ' . htmlentities(rrd_error())); } - foreach($this->spans as &$span) { + foreach ($this->spans as &$span) { // Graph graph - if(!rrd_graph($settings['images'] . '/' . $board . '-' . $span . '.png', Array( + if (!rrd_graph($settings['images'] . '/' . $board . '-' . $span . '.png', Array( '-s -1' . $span, '-t Posts on ' . sprintf($config['board_abbreviation'], $board) .' this ' . $span, '--lazy', @@ -105,7 +105,7 @@ } // combined graph - foreach($this->spans as &$span) { + foreach ($this->spans as &$span) { $options = Array( '-s -1' . $span, '-t Posts this ' . $span, @@ -129,8 +129,8 @@ $c = 1; $cc = 0; $red = 2; - foreach($this->boards as &$board) { - if(in_array($board, $this->combined_exclude)) + foreach ($this->boards as &$board) { + if (in_array($board, $this->combined_exclude)) continue; $color = str_pad(dechex($red*85), 2, '0', STR_PAD_LEFT) . str_pad(dechex($green*85), 2, '0', STR_PAD_LEFT) . @@ -147,31 +147,35 @@ sprintf($config['board_abbreviation'], $board); // Randomize colors using this horrible undocumented algorithm I threw together while debugging - if($c == 0) + if ($c == 0) $red++; - elseif($c == 1) + elseif ($c == 1) $green++; - elseif($c == 2) + elseif ($c == 2) $blue++; - elseif($c == 3) + elseif ($c == 3) $green--; - elseif($c == 4) + elseif ($c == 4) $red--; $cc++; - if($cc > 2) { + if ($cc > 2) { $c++; $cc = 0; } - if($c>4) $c = 0; + if ($c > 4) + $c = 0; - if($red>3) $red = 0; - if($green>3) $green = 0; - if($blue>3) $blue = 0; + if ($red > 3) + $red = 0; + if ($green > 3) + $green = 0; + if ($blue > 3) + $blue = 0; } $options[] = 'HRULE:0#000000'; - if(!rrd_graph($settings['images'] . '/combined-' . $span . '.png', $options)) + if (!rrd_graph($settings['images'] . '/combined-' . $span . '.png', $options)) error('RRDtool failed: ' . htmlentities(rrd_error())); } } diff --git a/templates/thread.html b/templates/thread.html index 9a56a50f..e7c65f9b 100644 --- a/templates/thread.html +++ b/templates/thread.html @@ -1,13 +1,13 @@ - - {% if config.url_favicon %}{% endif %} + + + {% if config.url_favicon %}{% endif %} {{ board.url }} - {{ board.name }} - - - {% if config.meta_keywords %}{% endif %} - + + {% if config.meta_keywords %}{% endif %} + {% if config.default_stylesheet.1 != '' %}{% endif %} {% if not nojavascript %} {% if not config.additional_javascript_compile %} @@ -29,17 +29,16 @@ display: block; } {% endraw %}{% endif %} - {{ boardlist.top }} {% if pm %}
    You have an unread PM{% if pm.waiting > 0 %}, plus {{ pm.waiting }} more waiting{% endif %}.

    {% endif %} {% if config.url_banner %}{% endif %}
    -

    {{ board.url }} - {{ board.title }}

    +

    {{ board.url }} - {{ board.title|e }}

    {% if board.subtitle %} - {{ board.subtitle }} + {{ board.subtitle|e }} {% endif %} {% if mod %}

    {% trans %}Return to dashboard{% endtrans %}

    {% endif %}
    -- cgit v1.3 From ae91636d1d2190c314cd95b3448b7002be0712d8 Mon Sep 17 00:00:00 2001 From: Michael Save Date: Tue, 8 May 2012 23:59:54 +1000 Subject: Bugfix: with disabling config[markup_urls] --- inc/functions.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'inc/functions.php') diff --git a/inc/functions.php b/inc/functions.php index ac0a1c96..f21df417 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1396,8 +1396,10 @@ function markup(&$body, $track_cites = false) { if ($config['auto_unicode']) { $body = unicodify($body); - foreach ($markup_urls as &$url) { - $body = str_replace(unicodify($url), $url, $body); + if ($config['markup_urls']) { + foreach ($markup_urls as &$url) { + $body = str_replace(unicodify($url), $url, $body); + } } } -- cgit v1.3 From 970c6cd95bfbb39454531f3990863d19cfbfe0ba Mon Sep 17 00:00:00 2001 From: Michael Save Date: Sat, 19 May 2012 18:27:45 +1000 Subject: [move] --- inc/functions.php | 4 +- inc/mod/pages.php | 183 ++++++++++++++++++++++++++++++++++++++++++++++++ mod.php | 1 + templates/mod/move.html | 41 +++++++++++ 4 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 templates/mod/move.html (limited to 'inc/functions.php') diff --git a/inc/functions.php b/inc/functions.php index f21df417..ff255614 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -716,13 +716,13 @@ function post(array $post) { $query->bindValue(':password', $post['password']); $query->bindValue(':ip', isset($post['ip']) ? $post['ip'] : $_SERVER['REMOTE_ADDR']); - if ($post['mod'] && $post['sticky']) { + if ($post['op'] && $post['mod'] && $post['sticky']) { $query->bindValue(':sticky', 1, PDO::PARAM_INT); } else { $query->bindValue(':sticky', 0, PDO::PARAM_INT); } - if ($post['mod'] && $post['locked']) { + if ($post['op'] && $post['mod'] && $post['locked']) { $query->bindValue(':locked', 1, PDO::PARAM_INT); } else { $query->bindValue(':locked', 0, PDO::PARAM_INT); diff --git a/inc/mod/pages.php b/inc/mod/pages.php index d532d9ba..7f78cd0b 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -693,6 +693,189 @@ function mod_bumplock($board, $unbumplock, $post) { header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); } +function mod_move($originBoard, $postID) { + global $board, $config, $mod; + + if (!openBoard($originBoard)) + error($config['error']['noboard']); + + if (!hasPermission($config['mod']['move'], $originBoard)) + error($config['error']['noaccess']); + + $query = prepare(sprintf('SELECT * FROM `posts_%s` WHERE `id` = :id AND `thread` IS NULL', $originBoard)); + $query->bindValue(':id', $postID); + $query->execute() or error(db_error($query)); + if (!$post = $query->fetch(PDO::FETCH_ASSOC)) + error($config['error']['404']); + + if (isset($_POST['board'])) { + $targetBoard = $_POST['board']; + $shadow = isset($_POST['shadow']); + + if ($targetBoard === $originBoard) + error(_('Target and source board are the same.')); + + // copy() if leaving a shadow thread behind; else, rename(). + $clone = $shadow ? 'copy' : 'rename'; + + // indicate that the post is a thread + $post['op'] = true; + + if ($post['file']) { + $post['has_file'] = true; + $post['width'] = &$post['filewidth']; + $post['height'] = &$post['fileheight']; + + $file_src = sprintf($config['board_path'], $board['uri']) . $config['dir']['img'] . $post['file']; + $file_thumb = sprintf($config['board_path'], $board['uri']) . $config['dir']['thumb'] . $post['thumb']; + } else { + $post['has_file'] = false; + } + + // allow thread to keep its same traits (stickied, locked, etc.) + $post['mod'] = true; + + if (!openBoard($targetBoard)) + error($config['error']['noboard']); + + // create the new thread + $newID = post($post); + + if($post['has_file']) { + // copy image + $clone($file_src, sprintf($config['board_path'], $board['uri']) . $config['dir']['img'] . $post['file']); + $clone($file_thumb, sprintf($config['board_path'], $board['uri']) . $config['dir']['thumb'] . $post['thumb']); + } + + // go back to the original board to fetch replies + openBoard($originBoard); + + $query = prepare(sprintf('SELECT * FROM `posts_%s` WHERE `thread` = :id ORDER BY `id`', $originBoard)); + $query->bindValue(':id', $postID, PDO::PARAM_INT); + $query->execute() or error(db_error($query)); + + $replies = array(); + + while($post = $query->fetch()) { + $post['mod'] = true; + $post['thread'] = $newID; + + if($post['file']) { + $post['has_file'] = true; + $post['width'] = &$post['filewidth']; + $post['height'] = &$post['fileheight']; + + $post['file_src'] = sprintf($config['board_path'], $board['uri']) . $config['dir']['img'] . $post['file']; + $post['file_thumb'] = sprintf($config['board_path'], $board['uri']) . $config['dir']['thumb'] . $post['thumb']; + } else { + $post['has_file'] = false; + } + + $replies[] = $post; + } + + $newIDs = array($postID => $newID); + + openBoard($targetBoard); + + foreach($replies as &$post) { + $query = prepare('SELECT `target` FROM `cites` WHERE `target_board` = :board AND `board` = :board AND `post` = :post'); + $query->bindValue(':board', $originBoard); + $query->bindValue(':post', $post['id'], PDO::PARAM_INT); + $query->execute() or error(db_error($qurey)); + + // correct >>X links + while($cite = $query->fetch(PDO::FETCH_ASSOC)) { + if(isset($newIDs[$cite['target']])) { + $post['body_nomarkup'] = preg_replace( + '/(>>(>\/' . preg_quote($originBoard, '/') . '\/)?)' . preg_quote($cite['target'], '/') . '/', + '>>' . $newIDs[$cite['target']], + $post['body_nomarkup']); + + $post['body'] = $post['body_nomarkup']; + } + } + + $post['body'] = $post['body_nomarkup']; + + $post['op'] = false; + $post['tracked_cites'] = markup($post['body'], true); + + // insert reply + $newIDs[$post['id']] = $newPostID = post($post); + + if($post['has_file']) { + // copy image + $clone($post['file_src'], sprintf($config['board_path'], $board['uri']) . $config['dir']['img'] . $post['file']); + $clone($post['file_thumb'], sprintf($config['board_path'], $board['uri']) . $config['dir']['thumb'] . $post['thumb']); + } + + foreach($post['tracked_cites'] as $cite) { + $query = prepare('INSERT INTO `cites` VALUES (:board, :post, :target_board, :target)'); + $query->bindValue(':board', $board['uri']); + $query->bindValue(':post', $newPostID, PDO::PARAM_INT); + $query->bindValue(':target_board',$cite[0]); + $query->bindValue(':target', $cite[1], PDO::PARAM_INT); + $query->execute() or error(db_error($query)); + } + } + + // build new hread + buildThread($newID); + buildIndex(); + + // trigger themes + rebuildThemes('post'); + + // return to original board + openBoard($originBoard); + + if($shadow) { + // lock old thread + $query = prepare(sprintf('UPDATE `posts_%s` SET `locked` = 1 WHERE `id` = :id', $originBoard)); + $query->bindValue(':id', $postID, PDO::PARAM_INT); + $query->execute() or error(db_error($query)); + + // leave a reply, linking to the new thread + $post = array( + 'mod' => true, + 'subject' => '', + 'email' => '', + 'name' => $config['mod']['shadow_name'], + 'capcode' => $config['mod']['shadow_capcode'], + 'trip' => '', + 'password' => '', + 'has_file' => false, + // attach to original thread + 'thread' => $postID, + 'op' => false + ); + + $post['body'] = $post['body_nomarkup'] = sprintf($config['mod']['shadow_mesage'], '>>>/' . $targetBoard . '/' . $newID); + + markup($post['body']); + + $botID = post($post); + buildThread($postID); + + header('Location: ?/' . sprintf($config['board_path'], $originBoard) . $config['dir']['res'] .sprintf($config['file_page'], $postID) . + '#' . $botID, true, $config['redirect_http']); + } else { + deletePost($postID); + buildIndex(); + + openBoard($targetBoard); + header('Location: ?/' . sprintf($config['board_path'], $board['uri']) . $config['dir']['res'] . sprintf($config['file_page'], $newID), true, $config['redirect_http']); + } + } + + $boards = listBoards(); + if (count($boards) <= 1) + error(_('Impossible to move thread; there is only one board.')); + + mod_page("Move thread", 'mod/move.html', array('post' => $postID, 'board' => $originBoard, 'boards' => $boards)); +} + function mod_ban_post($board, $delete, $post) { global $config, $mod; diff --git a/mod.php b/mod.php index b1422b6a..23cacc11 100644 --- a/mod.php +++ b/mod.php @@ -63,6 +63,7 @@ $pages = array( '/(\w+)/(un)?lock/(\d+)' => 'lock', // lock thread '/(\w+)/(un)?sticky/(\d+)' => 'sticky', // sticky thread '/(\w+)/bump(un)?lock/(\d+)' => 'bumplock', // "bumplock" thread + '/(\w+)/move/(\d+)' => 'move', // move thread // these pages aren't listed in the dashboard without $config['debug'] '/debug/antispam' => 'debug_antispam', diff --git a/templates/mod/move.html b/templates/mod/move.html new file mode 100644 index 00000000..802903b2 --- /dev/null +++ b/templates/mod/move.html @@ -0,0 +1,41 @@ +
    + + + + + + + + + + + + + +
    + {% trans 'Thread ID' %} + + >>>{{ config.board_abbreviation|sprintf(board) }}{{ post }} +
    + {% trans 'Leave shadow thread' %} + + + ({% trans 'locks thread; replies to it with a link.' %}) +
    {% trans 'Target board' %} +
      + {% for targetboard in boards if targetboard.uri != board %} +
    • + + +
    • + {% endfor %} +
    +
    + +
      +
    • +
    +
    + -- cgit v1.3 From 97dd6ab391d617698196abd7ad3c360b9edebb6b Mon Sep 17 00:00:00 2001 From: Michael Save Date: Mon, 28 May 2012 17:08:09 +1000 Subject: Bugfix: deleting OP image didn't rebuild --- inc/functions.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'inc/functions.php') diff --git a/inc/functions.php b/inc/functions.php index ff255614..f175ba05 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -803,12 +803,8 @@ function deleteFile($id, $remove_entirely_if_already=true) { $query = prepare(sprintf("SELECT `thread`,`thumb`,`file` FROM `posts_%s` WHERE `id` = :id LIMIT 1", $board['uri'])); $query->bindValue(':id', $id, PDO::PARAM_INT); $query->execute() or error(db_error($query)); - - if ($query->rowCount() < 1) { + if (!$post = $query->fetch()) error($config['error']['invalidpost']); - } - - $post = $query->fetch(); if ($post['file'] == 'deleted' && !$post['thread']) return; // Can't delete OP's image completely. @@ -827,13 +823,14 @@ function deleteFile($id, $remove_entirely_if_already=true) { // Set file to 'deleted' $query->bindValue(':file', 'deleted', PDO::PARAM_INT); } - // Update database $query->bindValue(':id', $id, PDO::PARAM_INT); $query->execute() or error(db_error($query)); if ($post['thread']) buildThread($post['thread']); + else + buildThread($id); } // rebuild post (markup) -- cgit v1.3 From 8b4e097b3c9bd974a59a4b3acdad2f957b510a2f Mon Sep 17 00:00:00 2001 From: Sebastian Stal Date: Wed, 4 Jul 2012 10:17:51 -0700 Subject: Share antibot hash across index pages fixes an issue with slow boards and multi-page indexes --- inc/functions.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'inc/functions.php') diff --git a/inc/functions.php b/inc/functions.php index f175ba05..eedbf9b9 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1202,6 +1202,7 @@ function buildIndex() { global $board, $config; $pages = getPages(); + $antibot = create_antibot($board['uri']); $page = 1; while ($page <= $config['max_pages'] && $content = index($page)) { @@ -1211,7 +1212,7 @@ function buildIndex() { $content['pages'] = $pages; $content['pages'][$page-1]['selected'] = true; $content['btn'] = getPageButtons($content['pages']); - $content['antibot'] = create_antibot($board['uri']); + $content['antibot'] = $antibot; file_write($filename, Element('index.html', $content)); if (isset($md5) && $md5 == md5_file($filename)) { -- cgit v1.3