1
0
mirror of https://github.com/vichan-devel/vichan.git synced 2024-11-27 17:00:52 +01:00

a lot more improvements

This commit is contained in:
Michael Save 2012-05-06 01:33:10 +10:00
parent ac2837c620
commit a610458720
40 changed files with 986 additions and 271 deletions

View File

@ -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;

View File

@ -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) {

View File

@ -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 <a href=\"?/IP/{$ip}\">{$ip}</a>");
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 <a href=\"?/IP/{$ip}\">{$ip}</a>");
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']) . ' <small>(#' . $user['id'] . ')</small>');
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']) . '" <small>(#' . $user['id'] . ')</small> 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']) . ' <small>(#' . $user['id'] . ')</small>');
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 &ndash; #$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) . '<hr>';
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'])) {

View File

@ -1,7 +1,7 @@
<?php
// Installation/upgrade file
define('VERSION', 'v0.9.6-dev-4');
define('VERSION', 'v0.9.6-dev-5');
require 'inc/functions.php';
@ -210,6 +210,8 @@ if (file_exists($config['has_installed'])) {
}
case 'v0.9.6-dev-3':
query("ALTER TABLE `antispam` CHANGE `hash` `hash` CHAR( 40 ) NOT NULL") or error(db_error());
case 'v0.9.6-dev-4':
query("ALTER TABLE `news` DROP INDEX `id`, ADD PRIMARY KEY ( `id` )") or error(db_error());
case false:
// Update version number
file_write($config['has_installed'], VERSION);

View File

@ -23,8 +23,6 @@ $(document).ready(function(){
OP = $('div.post.op a.post_no:eq(1)').text();
}
console.log(OP);
$(this).find('p.body a:not([rel="nofollow"])').each(function() {
var postID;

39
mod.php
View File

@ -24,17 +24,28 @@ $pages = array(
'!^$!' => ':?/', // 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;

View File

@ -0,0 +1,71 @@
<!doctype html>
<html>
<head>
{% block head %}
<link rel="stylesheet" media="screen" href="{{ config.url_stylesheet }}">
{% if config.url_favicon %}<link rel="shortcut icon" href="{{ config.url_favicon }}">{% endif %}
<title>{{ board.url }} - {{ board.name }}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=yes">
{% if config.meta_keywords %}<meta name="keywords" content="{{ config.meta_keywords }}">{% endif %}
{% if config.default_stylesheet.1 != '' %}<link rel="stylesheet" type="text/css" id="stylesheet" href="{{ config.uri_stylesheets }}{{ config.default_stylesheet.1 }}">{% endif %}
{% if not nojavascript %}
<script type="text/javascript" src="{{ config.url_javascript }}"></script>
{% if not config.additional_javascript_compile %}
{% for javascript in config.additional_javascript %}<script type="text/javascript" src="{{ config.additional_javascript_url }}{{ javascript }}"></script>{% endfor %}
{% endif %}
{% endif %}
{% if config.recaptcha %}<style type="text/css">{% raw %}
.recaptcha_image_cell {
background: none !important;
}
table.recaptchatable {
border: none !important;
}
#recaptcha_logo, #recaptcha_tagline {
display: none;
float: right;
}
.recaptchatable a {
display: block;
}
{% endraw %}</style>{% endif %}
{% endblock %}
</head>
<body>
{{ boardlist.top }}
{% if pm %}<div class="top_notice">You have <a href="?/PM/{{ pm.id }}">an unread PM</a>{% if pm.waiting > 0 %}, plus {{ pm.waiting }} more waiting{% endif %}.</div><hr />{% endif %}
{% if config.url_banner %}<img class="banner" src="{{ config.url_banner }}" {% if config.banner_width or config.banner_height %}style="{% if config.banner_width %}width:{{ config.banner_width }}px{% endif %};{% if config.banner_width %}height:{{ config.banner_height }}px{% endif %}" {% endif %}alt="" />{% endif %}
<header>
<h1>{{ board.url }} - {{ board.name }}</h1>
<div class="subtitle">
{% if board.title %}
{{ board.title|e }}
{% endif %}
{% if mod %}<p><a href="?/">{% trans %}Return to dashboard{% endtrans %}</a></p>{% endif %}
</div>
</header>
{% include 'post_form.html' %}
{% if config.blotter %}<hr /><div class="blotter">{{ config.blotter }}</div>{% endif %}
<hr />
<form name="postcontrols" action="{{ config.post_url }}" method="post">
<input type="hidden" name="board" value="{{ board.uri }}" />
{% if mod %}<input type="hidden" name="mod" value="1" />{% endif %}
{{ body }}
{% include 'report_delete.html' %}
</form>
<div class="pages">{{ btn.prev }} {% for page in pages %}
[<a {% if page.selected %}class="selected"{% endif %}{% if not page.selected %}href="{{ page.link }}"{% endif %}>{{ page.num }}</a>]{% if loop.last %} {% endif %}
{% endfor %} {{ btn.next }}</div>
{{ boardlist.bottom }}
<footer>
<p class="unimportant" style="margin-top:20px;text-align:center;">Powered by <a href="http://tinyboard.org/">Tinyboard</a> {{ config.version }} | <a href="http://tinyboard.org/">Tinyboard</a> Copyright &copy; 2010-2012 Tinyboard Development Group</p>
{% for footer in config.footer %}<p class="unimportant" style="text-align:center;">{{ footer }}</p>{% endfor %}
</footer>
<script type="text/javascript">{% raw %}
ready();
{% endraw %}</script>
</body>
</html>

View File

@ -1,13 +1,13 @@
<!doctype html>
<html>
<head>
<link rel="stylesheet" media="screen" href="{{ config.url_stylesheet }}" />
{% if config.url_favicon %}<link rel="shortcut icon" href="{{ config.url_favicon }}" />{% endif %}
<meta charset="utf-8">
<link rel="stylesheet" media="screen" href="{{ config.url_stylesheet }}">
{% if config.url_favicon %}<link rel="shortcut icon" href="{{ config.url_favicon }}">{% endif %}
<title>{{ board.url }} - {{ board.name }}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
{% if config.meta_keywords %}<meta name="keywords" content="{{ config.meta_keywords }}" />{% endif %}
<link rel="stylesheet" type="text/css" id="stylesheet" href="{{ config.uri_stylesheets }}{{ config.default_stylesheet.1 }}" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes">
{% if config.meta_keywords %}<meta name="keywords" content="{{ config.meta_keywords }}">{% endif %}
{% if config.default_stylesheet.1 != '' %}<link rel="stylesheet" type="text/css" id="stylesheet" href="{{ config.uri_stylesheets }}{{ config.default_stylesheet.1 }}">{% endif %}
{% if not nojavascript %}
<script type="text/javascript" src="{{ config.url_javascript }}"></script>
{% if not config.additional_javascript_compile %}
@ -35,10 +35,10 @@
{% if pm %}<div class="top_notice">You have <a href="?/PM/{{ pm.id }}">an unread PM</a>{% if pm.waiting > 0 %}, plus {{ pm.waiting }} more waiting{% endif %}.</div><hr />{% endif %}
{% if config.url_banner %}<img class="banner" src="{{ config.url_banner }}" {% if config.banner_width or config.banner_height %}style="{% if config.banner_width %}width:{{ config.banner_width }}px{% endif %};{% if config.banner_width %}height:{{ config.banner_height }}px{% endif %}" {% endif %}alt="" />{% endif %}
<header>
<h1>{{ board.url }} - {{ board.title }}</h1>
<h1>{{ board.url }} - {{ board.title|e }}</h1>
<div class="subtitle">
{% if board.subtitle %}
{{ board.subtitle }}
{{ board.subtitle|e }}
{% endif %}
{% if mod %}<p><a href="?/">{% trans %}Return to dashboard{% endtrans %}</a></p>{% endif %}
</div>

View File

@ -16,19 +16,19 @@
<tr>
<th>
<label for="ip">IP <span class="unimportant">(or subnet)</span></label>
<label for="ip">{% trans 'IP' %} <span class="unimportant">{% trans '(or subnet)' %}</span></label>
</th>
<td>
{% if not hide_ip %}
<input type="text" name="ip" id="ip" size="30" maxlength="40" value="{{ ip }}">
{% else %}
<em>hidden</em>
<em>{% trans 'hidden' %}</em>
{% endif %}
</td>
</tr>
<tr>
<th>
<label for="reason">Reason</label>
<label for="reason">{% trans 'Reason' %}</label>
</th>
<td>
<textarea name="reason" id="reason" rows="5" cols="30">{{ reason|e }}</textarea>
@ -37,12 +37,12 @@
{% if post and board and not delete %}
<tr>
<th>
<label for="reason">Message</label>
<label for="reason">{% trans 'Message' %}</label>
</th>
<td>
<input type="checkbox" id="public_message" name="public_message">
<input type="text" name="message" id="message" size="35" maxlength="200" value="{{ config.mod.default_ban_message|e }}">
<span class="unimportant">(public; attached to post)</span>
<span class="unimportant">({% trans 'public; attached to post' %})</span>
<script type="text/javascript">
document.getElementById('message').disabled = true;
document.getElementById('public_message').onchange = function() {
@ -54,20 +54,20 @@
{% endif %}
<tr>
<th>
<label for="length">Length</label>
<label for="length">{% trans 'Length' %}</label>
</th>
<td>
<input type="text" name="length" id="length" size="20" maxlength="40">
<span class="unimportant">(eg. "2d1h30m" or "2 days")</span></td>
</tr>
<tr>
<th>Board</th>
<th>{% trans 'Board' %}</th>
<td>
<ul style="list-style:none;padding:2px 5px">
<li>
<input type="radio" name="board" value="*" id="ban-allboards" checked>
<label style="display:inline" for="ban-allboards">
<em>all boards</em>
<em>{% trans 'all boards' %}</em>
</label>
</li>
@ -75,7 +75,7 @@
<li>
<input type="radio" name="board" value="{{ board.uri }}" id="ban-board-{{ board.uri }}">
<label style="display:inline" for="ban-board-{{ board.uri }}">
{{ config.board_abbreviation|sprintf(board.uri) }} - {{ board.title }}
{{ config.board_abbreviation|sprintf(board.uri) }} - {{ board.title|e }}
</label>
</li>
{% endfor %}
@ -84,7 +84,7 @@
</tr>
<tr>
<td></td>
<td><input name="new_ban" type="submit" value="New Ban"></td>
<td><input name="new_ban" type="submit" value="{% trans 'New Ban' %}"></td>
</tr>
</table>
</form>

View File

@ -1,15 +1,15 @@
{% if bans|count == 0 %}
<p style="text-align:center" class="unimportant">(There are no active bans.)</p>
<p style="text-align:center" class="unimportant">({% trans 'There are no active bans.' %})</p>
{% else %}
<form action="" method="post">
<table class="mod">
<tr>
<th>{% trans %}IP address{% endtrans %}</th>
<th>{% trans %}Reason{% endtrans %}</th>
<th>{% trans %}Board{% endtrans %}</th>
<th>{% trans %}Set{% endtrans %}</th>
<th>{% trans %}Expires{% endtrans %}</th>
<th>{% trans %}Staff{% endtrans %}</th>
<th>{% trans 'IP address' %}</th>
<th>{% trans 'Reason' %}</th>
<th>{% trans 'Board' %}</th>
<th>{% trans 'Set' %}</th>
<th>{% trans 'Expires' %}</th>
<th>{% trans 'Staff' %}</th>
</tr>
{% for ban in bans %}
<tr{% if ban.expires != 0 and ban.expires < time() %} style="text-decoration:line-through"{% endif %}>
@ -32,7 +32,7 @@
{% if ban.board %}
{{ config.board_abbreviation|sprintf(ban.board) }}
{% else %}
<em>{% trans %}all boards{% endtrans %}
<em>{% trans 'all boards' %}</em>
{% endif %}
</td>
<td style="white-space: nowrap">
@ -40,7 +40,7 @@
</td>
<td style="white-space: nowrap">
{% if ban.expires == 0 %}
<em>never</em>
<em>{% trans 'never' %}</em>
{% else %}
{{ ban.expires|date(config.post_date) }}
{% if ban.expires > time() %}
@ -59,8 +59,10 @@
{% endif %}
{% endif %}
{% elseif ban.mod == -1 %}
<em>system</em>
{% else %}
<em>deleted?</em>
<em>{% trans 'deleted?' %}</em>
{% endif %}
</td>
</tr>
@ -68,7 +70,7 @@
</table>
<p style="text-align:center">
<input type="submit" name="unban" value="Unban selected">
<input type="submit" name="unban" value="{% trans 'Unban selected' %}">
</p>
</form>
{% endif %}

44
templates/mod/board.html Normal file
View File

@ -0,0 +1,44 @@
{% if new %}
{% set action = '?/new-board' %}
{% else %}
{% set action = '?/edit/' ~ board.uri %}
{% endif %}
<form action="{{ action }}" method="post">
<table>
<tr>
<th>{% trans 'URI' %}</th>
<td>
{% if not new %}
{{ config.board_abbreviation|sprintf(board.uri) }}
{% else %}
/<input size="10" maxlength="255" type="text" name="uri" autocomplete="off">/
{% endif %}
</td>
</tr>
<tr>
<th>{% trans 'Title' %}</th>
<td>
<input size="25" type="text" name="title" value="{{ board.title|e }}" autocomplete="off">
</td>
</tr>
<tr>
<th>{% trans 'Subtitle' %}</th>
<td>
<input size="25" type="text" name="subtitle" value="{{ board.subtitle|e }}" autocomplete="off">
</td>
</tr>
</table>
<ul style="padding:0;text-align:center;list-style:none">
{% if new %}
<li><input type="submit" value="{% trans 'Create board' %}"></li>
{% else %}
<li><input type="submit" value="{% trans 'Save changes' %}"></li>
{% if mod|hasPermission(config.mod.deleteboard) %}
<li><input name="delete" onclick="return confirm('Are you sure you want to permanently delete this board?');" type="submit" value="{% trans 'Delete board' %}"></li>
{% endif %}
{% endif %}
</ul>
</form>

View File

@ -1,7 +1,7 @@
<p style="text-align:center;font-size:1.1em">
Are you sure you want to do that? <a href="?/{{ request }}">Click to proceed to ?/{{ request }}</a>.
{% trans 'Are you sure you want to do that?' %} <a href="?/{{ request }}">{% trans 'Click to proceed to' %} ?/{{ request }}</a>.
</p>
<p class="unimportant" style="text-align:center">
You are seeing this message because we were unable to serve a confirmation dialog, probably due to Javascript being disabled.
{% trans 'You are seeing this message because we were unable to serve a confirmation dialog, probably due to Javascript being disabled.' %}
</p>

View File

@ -6,30 +6,30 @@
<li>
<a href="?/{{ config.board_path|sprintf(board.uri) }}{{ config.file_index }}">{{ config.board_abbreviation|sprintf(board.uri) }}</a>
-
{{ board.title }}
{{ board.title|e }}
{% if board.subtitle %}
<small>&mdash; {{ board.subtitle }}</small>
<small>&mdash; {{ board.subtitle|e }}</small>
{% endif %}
{% if mod|hasPermission(config.mod.manageboards) %}
<a href="?/manage/{{ board.uri }}"><small>[{% trans 'manage' %}]</small></a>
<a href="?/edit/{{ board.uri }}"><small>[{% trans 'edit' %}]</small></a>
{% endif %}
</li>
{% endfor %}
{% if mod|hasPermission(config.mod.newboard) %}
<li style="margin-top:15px"><a href="?/new_board"><strong>{% trans 'Create new board' %}</strong></a></li>
<li style="margin-top:15px"><a href="?/new-board"><strong>{% trans 'Create new board' %}</strong></a></li>
{% endif %}
</ul>
</fieldset>
{% if mod|hasPermission(config.mod.noticeboard) %}
<fieldset>
<legend>{% trans 'Noticeboard' %}</legend>
<ul>
<fieldset>
<legend>{% trans 'Messages' %}</legend>
<ul>
{% if mod|hasPermission(config.mod.noticeboard) %}
{% if noticeboard|count > 0 %}
<li>
{% trans 'Latest posts:' %}
{% trans 'Noticeboard' %}:
<ul>
{% for post in noticeboard %}
<li>
@ -43,7 +43,7 @@
<small class="unimportant">
&mdash; by
{% if post.username %}
{{ post.username }}
{{ post.username|e }}
{% else %}
<em>deleted?</em>
{% endif %}
@ -56,9 +56,18 @@
</li>
{% endif %}
<li><a href="?/noticeboard">{% trans 'View all entries' %}</a></li>
</ul>
</fieldset>
{% endif %}
{% endif %}
<li><a href="?/news">{% trans 'News' %}</a></li>
<li>
<a href="?/inbox">
{% trans 'PM inbox' %}
{% if unread_pms > 0 %}
<strong>({{ unread_pms }} unread)</strong>
{% endif %}
</a>
</li>
</ul>
</fieldset>
<fieldset>
<legend>{% trans 'Administration' %}</legend>
@ -115,3 +124,24 @@
</fieldset>
{% endif %}
{% if newer_release %}
<fieldset>
<legend>Update</legend>
<ul>
<li>
A newer version of Tinyboard
(<strong>v{{ newer_release.massive }}.{{ newer_release.major }}.{{ newer_release.minor }}</strong>) is available!
See <a href="http://tinyboard.org">http://tinyboard.org/</a> for upgrade instructions.
</li>
</ul>
</fieldset>
{% endif %}
<fieldset>
<legend>{% trans 'User account' %}</legend>
<ul>
<li><a href="?/logout">{% trans 'Logout' %}</a></li>
</ul>
</fieldset>

36
templates/mod/inbox.html Normal file
View File

@ -0,0 +1,36 @@
{% if messages|count == 0 %}
<p style="text-align:center" class="unimportant">({% trans 'No private messages for you.' %})</p>
{% else %}
<table class="modlog">
<tr>
<th>{% trans 'ID' %}</th>
<th>{% trans 'From' %}</th>
<th>{% trans 'Date' %}</th>
<th>{% trans 'Message snippet' %}</th>
</tr>
{% for message in messages %}
<tr{% if message.unread %} style="font-weight:bold"{% endif %}>
<td class="minimal">
<a href="?/PM/{{ message.id }}">
{{ message.id }}
</a>
</td>
<td class="minimal">
{% if message.username %}
<a href="?/new_PM/{{ message.username|e }}">{{ message.username|e }}</a>
{% else %}
<em>{% trans 'deleted?' %}</em>
{% endif %}
</td>
<td class="minimal">
{{ message.time|date(config.post_date) }}
</td>
<td>
<a href="?/PM/{{ message.id }}">
{{ message.snippet }}
</a>
</td>
</tr>
{% endfor %}
</table>
{% endif %}

View File

@ -1,15 +1,21 @@
<table class="modlog">
<tr>
<th>Staff</th>
<th>IP address</th>
<th>Time</th>
<th>Board</th>
<th>Action</th>
<th>{% trans 'Staff' %}</th>
<th>{% trans 'IP address' %}</th>
<th>{% trans 'Time' %}</th>
<th>{% trans 'Board' %}</th>
<th>{% trans 'Action' %}</th>
</tr>
{% for log in logs %}
<tr>
<td class="minimal">
<a href="?/new_PM/{{ log.username }}">{{ log.username }}</a>
{% if log.username %}
<a href="?/new_PM/{{ log.username|e }}">{{ log.username|e }}</a>
{% elseif log.mod == -1 %}
<em>system</em>
{% else %}
<em>{% trans 'deleted?' %}</em>
{% endif %}
</td>
<td class="minimal">
<a href="?/IP/{{ log.ip }}">{{ log.ip }}</a>

View File

@ -3,7 +3,7 @@
<table style="margin-top:25px;">
<tr>
<th>
{% trans %}Username{% endtrans %}
{% trans 'Username' %}
</th>
<td>
<input type="text" name="username" size="20" maxlength="30" value="{{ username|e }}">
@ -11,7 +11,7 @@
</tr>
<tr>
<th>
{% trans %}Password{% endtrans %}
{% trans 'Password' %}
</th>
<td>
<input type="password" name="password" size="20" maxlength="30" value="">

View File

@ -1,7 +1,3 @@
{#{% if id == mod.id %}
{% set username = 'me' %}
{% endif %}#}
<form action="?/new_PM/{{ username|e }}" method="post">
<table>
<tr>
@ -18,5 +14,5 @@
</tr>
</table>
<p style="text-align:center"><input type="submit" value="Send message"></p>
<p style="text-align:center"><input type="submit" value="{% trans 'Send message' %}"></p>
</form>

70
templates/mod/news.html Normal file
View File

@ -0,0 +1,70 @@
{% if mod|hasPermission(config.mod.news) %}
<fieldset>
<legend>{% trans 'New post' %}</legend>
<form style="margin:0" action="" method="post">
<table>
<tr>
<th>
{% if mod|hasPermission(config.mod.news_custom) %}
<label for="name">{% trans 'Name' %}</label>
{% else %}
{% trans 'Name' %}
{% endif %}
</th>
<td>
{% if mod|hasPermission(config.mod.news_custom) %}
<input type="text" size="55" name="name" id="name" value="{{ mod.username|e }}">
{% else %}
{{ mod.username|e }}
{% endif %}
</td>
</tr>
<tr>
<th><label for="subject">{% trans 'Subject' %}</label></th>
<td><input type="text" size="55" name="subject" id="subject"></td>
</tr>
<tr>
<th><label for="body">{% trans 'Body' %}</label></th>
<td><textarea name="body" id="body" style="width:100%;height:100px"></textarea></td>
</tr>
</table>
<p style="text-align:center">
<input type="submit" value="{% trans 'Post news entry' %}">
</p>
</form>
</fieldset>
{% endif %}
{% for post in news %}
<div class="ban">
{% if mod|hasPermission(config.mod.news_delete) %}
<span style="float:right;padding:2px">
<a class="unimportant" href="?/news/delete/{{ post.id }}">[{% trans 'delete' %}]</a>
</span>
{% endif %}
<h2 id="{{ post.id }}">
<small class="unimportant">
<a href="#{{ post.id }}">#</a>
</small>
{% if post.subject %}
{{ post.subject|e }}
{% else %}
<em>{% trans 'no subject' %}</em>
{% endif %}
<small class="unimportant">
&mdash; {% trans 'by' %} {{ post.name }} {% trans 'at' %} {{ notice.time|date(config.post_date) }}
</small>
</h2>
<p>
{{ post.body }}
</p>
</div>
{% endfor %}
{% if count > news|count %}
<p class="unimportant" style="text-align:center;word-wrap:break-word">
{% for i in range(0, (count - 1) / config.mod.news_page) %}
<a href="?/news/{{ i + 1 }}">[{{ i + 1 }}]</a>
{% endfor %}
</p>
{% endif %}

View File

@ -40,13 +40,13 @@
<em>{% trans 'no subject' %}</em>
{% endif %}
<small class="unimportant">
&mdash; by
&mdash; {% trans 'by' %}
{% if post.username %}
{{ post.username }}
{{ post.username|e }}
{% else %}
<em>deleted?</em>
<em>{% trans 'deleted?' %}</em>
{% endif %}
at
{% trans 'at' %}
{{ notice.time|date(config.post_date) }}
</small>
</h2>

View File

@ -1,11 +1,11 @@
<form action="" method="post">
<table>
<tr>
<th>From</th>
<th>{% trans 'From' %}</th>
{% if username %}
<td><a href="?/new_PM/{{ username|e }}">{{ username|e }}</a></td>
{% else %}
<td><em>deleted?</em></td>
<td><em>{% trans 'deleted?' %}</em></td>
{% endif %}
</tr>
{% if to != mod.id %}
@ -14,27 +14,27 @@
{% if to_username %}
<td><a href="?/new_PM/{{ to_username|e }}">{{ to_username|e }}</a></td>
{% else %}
<td><em>deleted?</em></td>
<td><em>{% trans 'deleted?' %}</em></td>
{% endif %}
</tr>
{% endif %}
<tr>
<th>Date</th>
<th>{% trans 'Date' %}</th>
<td>{{ time|date(config.post_date) }}</td>
</tr>
<tr>
<th>Message</th>
<th>{% trans 'Message' %}</th>
<td>{{ message }}</td>
</tr>
</table>
<ul style="list-style:none;text-align:center;padding:0">
<li style="padding:5px 0">
<input type="submit" name="delete" value="Delete forever">
<input type="submit" name="delete" value="{% trans 'Delete forever' %}">
</li>
<li style="padding:5px 0">
<a href="?/PM/{{ id }}/reply">
Reply with quote
{% trans 'Reply with quote' %}
</a>
</li>
</ul>

View File

@ -2,7 +2,7 @@
<ul id="rebuild">
<li style="margin-bottom:8px">
<input type="checkbox" name="rebuild_all" id="rebuild_all" onchange="toggleall(this.checked)">
<label for="rebuild_all"><strong>Toggle all</strong></label>
<label for="rebuild_all"><strong>{% trans 'Toggle all' %}</strong></label>
<script>
function toggleall(val) {
/* TODO: something more suitable for all browsers? */
@ -15,27 +15,27 @@
</li>
<li>
<input type="checkbox" name="rebuild_cache" id="rebuild_cache" checked>
<label for="rebuild_cache">Flush cache</label>
<label for="rebuild_cache">{% trans 'Flush cache' %}</label>
</li>
<li>
<input type="checkbox" name="rebuild_javascript" id="rebuild_javascript" checked>
<label for="rebuild_javascript">Rebuild Javascript</label>
<label for="rebuild_javascript">{% trans 'Rebuild Javascript' %}</label>
</li>
<li>
<input type="checkbox" name="rebuild_index" id="rebuild_index" checked>
<label for="rebuild_index">Rebuild index pages</label>
<label for="rebuild_index">{% trans 'Rebuild index pages' %}</label>
</li>
<li>
<input type="checkbox" name="rebuild_thread" id="rebuild_thread" checked>
<label for="rebuild_thread">Rebuild thread pages</label>
<label for="rebuild_thread">{% trans 'Rebuild thread pages' %}</label>
</li>
<li>
<input type="checkbox" name="rebuild_themes" id="rebuild_themes" checked>
<label for="rebuild_themes">Rebuild themes</label>
<label for="rebuild_themes">{% trans 'Rebuild themes' %}</label>
</li>
<li>
<input type="checkbox" name="rebuild_posts" id="rebuild_posts">
<label for="rebuild_posts">Rebuild replies</label>
<label for="rebuild_posts">{% trans 'Rebuild replies' %}</label>
</li>
</ul>
@ -44,7 +44,7 @@
<ul id="boards">
<li style="margin-bottom:8px">
<input type="checkbox" name="boards_all" id="boards_all" onchange="toggleallboards(this.checked)" checked>
<label for="boards_all"><strong>All boards</strong></label>
<label for="boards_all"><strong>{% trans 'All boards' %}</strong></label>
<script>
function toggleallboards(val) {
/* TODO: something more suitable for all browsers? */
@ -59,13 +59,13 @@
<li>
<input type="checkbox" name="board_{{ board.uri }}" id="board-{{ board.uri }}" checked>
<label for="board-{{ board.uri }}">
{{ config.board_abbreviation|sprintf(board.uri) }} - {{ board.title }}
{{ config.board_abbreviation|sprintf(board.uri) }} - {{ board.title|e }}
</label>
</li>
{% endfor %}
</ul>
<p style="text-align:center">
<input type="submit" value="Rebuild" name="rebuild">
<input type="submit" value="{% trans 'Rebuild' %}" name="rebuild">
</p>
</form>

View File

@ -1,12 +1,12 @@
<div class="ban">
<h2>Rebuilt</h2>
<h2>{% trans 'Rebuilt' %}</h2>
<ul>
{% for log in logs %}
<li>{{ log }}</li>
{% endfor %}
</ul>
<p>
<a href="?/rebuild">Go back and rebuild again</a>.
<a href="?/rebuild">{% trans 'Go back and rebuild again' %}</a>.
</p>
</div>

View File

@ -1,25 +1,25 @@
<div class="report">
<hr>
Board: <a href="?/{{ report.board }}/{{ config.file_index }}">{{ config.board_abbreviation|sprintf(report.board) }}</a>
{% trans 'Board' %}: <a href="?/{{ report.board }}/{{ config.file_index }}">{{ config.board_abbreviation|sprintf(report.board) }}</a>
<br>
Reason: {{ report.reason }}
{% trans 'Reason' %}: {{ report.reason }}
<br>
Report date: {{ report.time|date(config.post_date) }}
{% trans 'Report date' %}: {{ report.time|date(config.post_date) }}
<br>
{% if mod|hasPermission(config.mod.show_ip, report.board) %}
Reported by: <a href="?/IP/{{ report.ip }}">{{ report.ip }}</a>
{% trans 'Reported by' %}: <a href="?/IP/{{ report.ip }}">{{ report.ip }}</a>
<br>
{% endif %}
{% if mod|hasPermission(config.mod.report_dismiss, report.board) or mod|hasPermission(config.mod.report_dismiss_ip, report.board) %}
<hr>
{% if mod|hasPermission(config.mod.report_dismiss, report.board) %}
<a title="Discard abuse report" href="?/reports/{{ report.id }}/dismiss">Dismiss</a>
<a title="{% trans 'Discard abuse report' %}" href="?/reports/{{ report.id }}/dismiss">Dismiss</a>
{% endif %}
{% if mod|hasPermission(config.mod.report_dismiss_ip, report.board) %}
{% if mod|hasPermission(config.mod.report_dismiss, report.board) %}
|
{% endif %}
<a title="Discard all abuse reports by this IP address" href="?/reports/{{ report.id }}/dismissall">Dismiss+</a>
<a title="{% trans 'Discard all abuse reports by this IP address' %}" href="?/reports/{{ report.id }}/dismissall">Dismiss+</a>
{% endif %}
{% endif %}
</div>

View File

@ -1,5 +1,6 @@
{% if reports %}
{{ reports }}
{% else %}
<p style="text-align:center" class="unimportant">(There are no reports.)</p>
<p style="text-align:center" class="unimportant">({% trans 'There are no reports.' %})</p>
{% endif %}

View File

@ -1,9 +1,15 @@
<form action="?/users/{{ mod.id }}" method="post">
{% if new %}
{% set action = '?/users/new' %}
{% else %}
{% set action = '?/users/' ~ user.id %}
{% endif %}
<form action="{{ action }}" method="post">
<table>
<tr>
<th>Username</th>
<th>{% trans 'Username' %}</th>
<td>
{% if mod|hasPermission(config.mod.editusers) %}
{% if new or mod|hasPermission(config.mod.editusers) %}
<input size="20" maxlength="30" type="text" name="username" value="{{ user.username|e }}" autocomplete="off">
{% else %}
{{ user.username|e }}
@ -11,17 +17,38 @@
</td>
</tr>
<tr>
<th>Password <small style="font-weight:normal">(new; optional)</small></th>
<th>{% trans 'Password' %}{% if not new %} <small style="font-weight:normal">({% trans 'new; optional' %})</small>{% endif %}</th>
<td>
{% if mod|hasPermission(config.mod.editusers) or (mod|hasPermission(config.mod.change_password) and user.id == mod.id) %}
{% if new or (mod|hasPermission(config.mod.editusers) or (mod|hasPermission(config.mod.change_password) and user.id == mod.id)) %}
<input size="20" maxlength="30" type="password" name="password" value="" autocomplete="off">
{% else %}
-
{% endif %}
</td>
</tr>
{% if new %}
<tr>
<th>{% trans 'Class' %}</th>
<td>
<ul style="padding:5px 8px;list-style:none">
<li>
<input type="radio" name="type" id="janitor" value="{{ constant('JANITOR') }}">
<label for="janitor">{% trans 'Janitor' %}</label>
</li>
<li>
<input type="radio" name="type" id="mod" value="{{ constant('MOD') }}" checked>
<label for="mod">{% trans 'Mod' %}</label>
</li>
<li>
<input type="radio" name="type" id="admin" value="{{ constant('Admin') }}">
<label for="admin">{% trans 'Admin' %}</label>
</li>
</ul>
</td>
</tr>
{% endif %}
<tr>
<th>Boards</th>
<th>{% trans 'Boards' %}</th>
<td>
<ul style="padding:0 5px;list-style:none">
<li>
@ -31,7 +58,7 @@
disabled
{% endif %}
>
<label for="allboards">"*" - All boards</label>
<label for="allboards">"*" - {% trans 'All boards' %}</label>
</li>
{% for board in boards %}
<li>
@ -44,7 +71,7 @@
<label for="board_{{ board.uri }}">
{{ config.board_abbreviation|sprintf(board.uri) }}
-
{{ board.title }}
{{ board.title|e }}
</label>
</li>
{% endfor %}
@ -53,10 +80,14 @@
</tr>
</table>
<ul style="padding:0;text-align:center">
<li><input type="submit" value="Save changes"></li>
{% if mod|hasPermission(config.mod.deleteusers) %}
<li><input type="submit" value="Delete user"></li>
<ul style="padding:0;text-align:center;list-style:none">
{% if new %}
<li><input type="submit" value="{% trans 'Create user' %}"></li>
{% else %}
<li><input type="submit" value="{% trans 'Save changes' %}"></li>
{% if mod|hasPermission(config.mod.deleteusers) %}
<li><input name="delete" onclick="return confirm('Are you sure you want to permanently delete this user?');" type="submit" value="{% trans 'Delete user' %}"></li>
{% endif %}
{% endif %}
</ul>
</form>
@ -64,10 +95,10 @@
{% if logs|count > 0 %}
<table class="modlog" style="width:600px">
<tr>
<th>IP address</th>
<th>Time</th>
<th>Board</th>
<th>Action</th>
<th>{% trans 'IP address' %}</th>
<th>{% trans 'Time' %}</th>
<th>{% trans 'Board' %}</th>
<th>{% trans 'Action' %}</th>
</tr>
{% for log in logs %}
<tr>
@ -91,3 +122,4 @@
{% endfor %}
</table>
{% endif %}

View File

@ -1,39 +1,45 @@
<table class="modlog" style="width:auto">
<tr>
<th>ID</th>
<th>Username</th>
<th>Type</th>
<th>Boards</th>
<th>Last action</th>
<th>{% trans 'ID' %}</th>
<th>{% trans 'Username' %}</th>
<th>{% trans 'Type' %}</th>
<th>{% trans 'Boards' %}</th>
<th>{% trans 'Last action' %}</th>
<th>&hellip;</th>
</tr>
{% for user in users %}
<tr>
<td><small>{{ user.id }}</small></td>
<td>{{ user.username }}</td>
<td>{{ user.username|e }}</td>
<td>
{% if user.type == constant('JANITOR') %}Janitor
{% elseif user.type == constant('MOD') %}Mod
{% elseif user.type == constant('ADMIN') %}Admin
{% if user.type == constant('JANITOR') %}{% trans 'Janitor' %}
{% elseif user.type == constant('MOD') %}{% trans 'Mod' %}
{% elseif user.type == constant('ADMIN') %}{% trans 'Admin' %}
{% endif %}
</td>
<td>
{# This is really messy, but IMO it beats doing it in PHP. #}
{% set boards = user.boards|split(',') %}
{% set _boards = [] %}
{% for board in boards %}
{% set _boards = _boards|push(board == '*' ? '*' : config.board_abbreviation|sprintf(board)) %}
{% endfor %}
{% set _boards = _boards|sort %}
{{ _boards|join(', ') }}
{% if user.boards == '' %}
<em>{% trans 'none' %}</em>
{% elseif user.boards == '*' %}
<em>{% trans 'all boards' %}</em>
{% else %}
{# This is really messy, but IMO it beats doing it in PHP. #}
{% set boards = user.boards|split(',') %}
{% set _boards = [] %}
{% for board in boards %}
{% set _boards = _boards|push(board == '*' ? '*' : config.board_abbreviation|sprintf(board)) %}
{% endfor %}
{% set _boards = _boards|sort %}
{{ _boards|join(', ') }}
{% endif %}
</td>
<td>
{% if mod|hasPermission(config.mod.modlog) %}
{% if user.last %}
<span title="{{ user.action|e }}">{{ user.last|ago }}</span>
{% else %}
<em>never</em>
<em>{% trans 'never' %}</em>
{% endif %}
{% else %}
&ndash;
@ -41,18 +47,25 @@
</td>
<td>
{% if mod|hasPermission(config.mod.promoteusers) and user.type < constant('ADMIN') %}
<a style="float:left;text-decoration:none" href="?/users/{{ user.id }}/promote" title="Promote">&#9650;</a>
<a style="float:left;text-decoration:none" href="?/users/{{ user.id }}/promote" title="{% trans 'Promote' %}">&#9650;</a>
{% endif %}
{% if mod|hasPermission(config.mod.promoteusers) and user.type > constant('JANITOR') %}
<a style="float:left;text-decoration:none" href="?/users/{{ user.id }}/demote" title="Demote">&#9660;</a>
<a style="float:left;text-decoration:none" href="?/users/{{ user.id }}/demote" title="{% trans 'Demote' %}">&#9660;</a>
{% endif %}
{% if mod|hasPermission(config.editusers) or (mod|hasPermission(config.change_password) and mod.id == user.id) %}
<a class="unimportant" style="margin-left:5px;float:right" href="?/users/{{ user.id }}">[edit]</a>
<a class="unimportant" style="margin-left:5px;float:right" href="?/users/{{ user.id }}">[{% trans 'edit' %}]</a>
{% endif %}
{% if mod|hasPermission(config.mod.create_pm) %}
<a class="unimportant" style="margin-left:5px;float:right" href="?/new_PM/{{ user.username }}">[PM]</a>
<a class="unimportant" style="margin-left:5px;float:right" href="?/new_PM/{{ user.username|e }}">[{% trans 'PM' %}]</a>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
{% if mod|hasPermission(config.mod.createusers) %}
<p style="text-align:center">
<a href="?/users/new">Create a new user</a>
</p>
{% endif %}

View File

@ -1,37 +1,38 @@
{% for board_posts in posts %}
<fieldset>
<legend>
<a href="?/{{ config.board_path|sprintf(board.uri) }}{{ config.file_index }}">{{ config.board_abbreviation|sprintf(board_posts.board.uri) }}</a>
<a href="?/{{ config.board_path|sprintf(board_posts.board.uri) }}{{ config.file_index }}">{{ config.board_abbreviation|sprintf(board_posts.board.uri) }}</a>
-
{{ board_posts.board.title }}
{{ board_posts.board.title|e }}
</legend>
{{ board_posts.posts|join('<hr>') }}
</fieldset>
{% endfor %}
{% if mod|hasPermission(config.mod.view_notes) %}
<fieldset>
<fieldset id="notes">
<legend>
{{ notes|count }} note{% if notes|count != 1 %}s{% endif %} on record
{% set notes_on_record = 'note' ~ (notes|count != 1 ? 's' : '') ~ ' on record' %}
<legend>{{ notes|count }} {% trans notes_on_record %}</legend>
</legend>
{% if notes|count > 0 %}
<table class="modlog">
<tr>
<th>Staff</th>
<th>Note</th>
<th>Date</th>
<th>{% trans 'Staff' %}</th>
<th>{% trans 'Note' %}</th>
<th>{% trans 'Date' %}</th>
{% if mod|hasPermission(config.mod.remove_notes) %}
<th>Actions</th>
<th>{% trans 'Actions' %}</th>
{% endif %}
</tr>
{% for note in notes %}
<tr>
<td class="minimal">
{% if note.username %}
<a href="?/new_PM/{{ note.username }}">{{ note.username }}</a>
<a href="?/new_PM/{{ note.username|e }}">{{ note.username|e }}</a>
{% else %}
<em>deleted?</em>
<em>{% trans 'deleted?' %}</em>
{% endif %}
</td>
<td>
@ -42,7 +43,9 @@
</td>
{% if mod|hasPermission(config.mod.remove_notes) %}
<td class="minimal">
<a href="?/IP/{{ ip }}/remove_note/{{ note.id }}"><small>[remove]</small></a>
<a href="?/IP/{{ ip }}/remove_note/{{ note.id }}">
<small>[{% trans 'remove' %}]</small>
</a>
</td>
{% endif %}
</tr>
@ -54,12 +57,12 @@
<form action="" method="post" style="margin:0">
<table>
<tr>
<th>Staff</th>
<td>{{ mod.username }}</td>
<th>{% trans 'Staff' %}</th>
<td>{{ mod.username|e }}</td>
</tr>
<tr>
<th>
<label for="note">Note</label>
<label for="note">{% trans 'Note' %}</label>
</th>
<td>
<textarea id="note" name="note" rows="5" cols="30"></textarea>
@ -67,7 +70,7 @@
</tr>
<tr>
<td></td>
<td><input type="submit" value="New note"></td>
<td><input type="submit" value="{% trans 'New note' %}"></td>
</tr>
</table>
</form>
@ -76,73 +79,74 @@
{% endif %}
{% if bans|count > 0 and mod|hasPermission(config.mod.view_ban) %}
<fieldset>
<legend>Ban{% if bans|count != 1 %}s{% endif %} on record</legend>
<fieldset id="bans">
{% set bans_on_record = 'ban' ~ (bans|count != 1 ? 's' : '') ~ ' on record' %}
<legend>{{ bans|count }} {% trans bans_on_record %}</legend>
{% for ban in bans %}
<form action="" method="post" style="text-align:center">
<table style="width:400px;margin-bottom:10px;border-bottom:1px solid #ddd;padding:5px">
<tr>
<th>Status</th>
<th>{% trans 'Status' %}</th>
<td>
{% if config.mod.view_banexpired and ban.expires != 0 and ban.expires < time() %}
Expired
{% trans 'Expired' %}
{% else %}
Active
{% trans 'Active' %}
{% endif %}
</td>
</tr>
<tr>
<th>IP</th>
<th>{% trans 'IP' %}</th>
<td>{{ ban.ip }}</td>
</tr>
<tr>
<th>Reason</th>
<th>{% trans 'Reason' %}</th>
<td>
{% if ban.reason %}
{{ ban.reason }}
{% else %}
<em>no reason</em>
<em>{% trans 'no reason' %}</em>
{% endif %}
</td>
</tr>
<tr>
<th>Board</th>
<th>{% trans 'Board' %}</th>
<td>
{% if ban.board %}
{{ config.board_abbreviation|sprintf(ban.board) }}
{% else %}
<em>all boards</em>
<em>{% trans 'all boards' %}</em>
{% endif %}
</td>
</tr>
<tr>
<th>Set</th>
<th>{% trans 'Set' %}</th>
<td>{{ ban.set|date(config.post_date) }}</td>
</tr>
<tr>
<th>Expires</th>
<th>{% trans 'Expires' %}</th>
<td>
{% if ban.expires %}
{{ ban.expires|date(config.post_date) }}
{% else %}
<em>never</em>
<em>{% trans 'never' %}</em>
{% endif %}
</td>
</tr>
<tr>
<th>Staff</th>
<th>{% trans 'Staff' %}</th>
<td>
{% if ban.username %}
{{ ban.username }}
{{ ban.username|e }}
{% else %}
<em>deleted?</em>
<em>{% trans 'deleted?' %}</em>
{% endif %}
</td>
</tr>
</table>
<input type="hidden" name="ban_id" value="{{ ban.id }}">
<input type="submit" name="unban" value="Remove ban">
<input type="submit" name="unban" value="{% trans 'Remove ban' %}">
</form>
{% endfor %}
</fieldset>
@ -150,8 +154,8 @@
{% if mod|hasPermission(config.mod.ban) %}
<fieldset>
<legend>New ban</legend>
{% set redirect = '?/IP/' ~ ip %}
<legend>{% trans 'New ban' %}</legend>
{% set redirect = '?/IP/' ~ ip ~ '#bans' %}
{% include 'mod/ban_form.html' %}
</fieldset>
{% endif %}

View File

@ -1,12 +1,12 @@
<!doctype html>
<html>
<head>
<link rel="stylesheet" media="screen" href="{{ config.url_stylesheet }}" />
{% if config.url_favicon %}<link rel="shortcut icon" href="{{ config.url_favicon }}" />{% endif %}
<meta charset="utf-8">
<link rel="stylesheet" media="screen" href="{{ config.url_stylesheet }}">
{% if config.url_favicon %}<link rel="shortcut icon" href="{{ config.url_favicon }}">{% endif %}
<title>{{ title }}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<link rel="stylesheet" type="text/css" id="stylesheet" href="{{ config.uri_stylesheets }}{{ config.default_stylesheet.1 }}" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes">
{% if config.default_stylesheet.1 != '' %}<link rel="stylesheet" type="text/css" id="stylesheet" href="{{ config.uri_stylesheets }}{{ config.default_stylesheet.1 }}">{% endif %}
{% if not nojavascript %}<script type="text/javascript" src="{{ config.url_javascript }}"></script>{% endif %}
</head>
<body>

View File

@ -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, '<strong>' . utf8tohtml($settings['no_recent']) . '</strong> is not a non-negative integer.');
}
}

View File

@ -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));
}

View File

@ -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, '<h2>Prerequisites not met!</h2>' .
'This theme requires $config[\'boards\'] and $config[\'categories\'] to be set.');
}

View File

@ -31,7 +31,7 @@
</legend>
{% for board in boards %}
<li>
<a href="{{ board.uri }}">{{ board.title }}</a>
<a href="{{ board.uri }}">{{ board.title|e }}</a>
</li>
{% endfor %}
</fieldset>

View File

@ -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));
}

View File

@ -30,7 +30,7 @@
{% for board in boards %}
<li>
<a href="{{ config.board_path|sprintf(board.uri) }}">
{{ board.title }}
{{ board.title|e }}
</a>
</li>
{% endfor %}

View File

@ -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));
}

View File

@ -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, '<strong>' . utf8tohtml($settings['limit_images']) . '</strong> 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, '<strong>' . utf8tohtml($settings['limit_posts']) . '</strong> is not a non-negative integer.');
}
}

View File

@ -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']);
}

View File

@ -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: <strong>' . $settings['interval'] . '</strong>. 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: <strong>' . $settings['width'] . '</strong>!');
if(!is_numeric($settings['height']) || $settings['height'] < 1)
if (!is_numeric($settings['height']) || $settings['height'] < 1)
return Array(false, 'Invalid height: <strong>' . $settings['height'] . '</strong>!');
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: <strong>' . $settings['rate'] . '</strong>!');
$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?
}

View File

@ -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()));
}
}

View File

@ -1,13 +1,13 @@
<!doctype html>
<html>
<head>
<link rel="stylesheet" media="screen" href="{{ config.url_stylesheet }}" />
{% if config.url_favicon %}<link rel="shortcut icon" href="{{ config.url_favicon }}" />{% endif %}
<meta charset="utf-8">
<link rel="stylesheet" media="screen" href="{{ config.url_stylesheet }}">
{% if config.url_favicon %}<link rel="shortcut icon" href="{{ config.url_favicon }}">{% endif %}
<title>{{ board.url }} - {{ board.name }}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
{% if config.meta_keywords %}<meta name="keywords" content="{{ config.meta_keywords }}" />{% endif %}
<link rel="stylesheet" type="text/css" id="stylesheet" href="{{ config.uri_stylesheets }}{{ config.default_stylesheet.1 }}" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes">
{% if config.meta_keywords %}<meta name="keywords" content="{{ config.meta_keywords }}">{% endif %}
{% if config.default_stylesheet.1 != '' %}<link rel="stylesheet" type="text/css" id="stylesheet" href="{{ config.uri_stylesheets }}{{ config.default_stylesheet.1 }}">{% endif %}
{% if not nojavascript %}
<script type="text/javascript" src="{{ config.url_javascript }}"></script>
{% if not config.additional_javascript_compile %}
@ -29,17 +29,16 @@
display: block;
}
{% endraw %}</style>{% endif %}
</head>
<body>
{{ boardlist.top }}
{% if pm %}<div class="top_notice">You have <a href="?/PM/{{ pm.id }}">an unread PM</a>{% if pm.waiting > 0 %}, plus {{ pm.waiting }} more waiting{% endif %}.</div><hr />{% endif %}
{% if config.url_banner %}<img class="banner" src="{{ config.url_banner }}" {% if config.banner_width or config.banner_height %}style="{% if config.banner_width %}width:{{ config.banner_width }}px{% endif %};{% if config.banner_width %}height:{{ config.banner_height }}px{% endif %}" {% endif %}alt="" />{% endif %}
<header>
<h1>{{ board.url }} - {{ board.title }}</h1>
<h1>{{ board.url }} - {{ board.title|e }}</h1>
<div class="subtitle">
{% if board.subtitle %}
{{ board.subtitle }}
{{ board.subtitle|e }}
{% endif %}
{% if mod %}<p><a href="?/">{% trans %}Return to dashboard{% endtrans %}</a></p>{% endif %}
</div>