Browse Source

a lot more improvements

pull/40/head
Michael Save 11 years ago
parent
commit
a610458720
  1. 5
      inc/config.php
  2. 25
      inc/functions.php
  3. 396
      inc/mod/pages.php
  4. 4
      install.php
  5. 2
      js/show-op.js
  6. 39
      mod.php
  7. 71
      templates/generic_page.html
  8. 16
      templates/index.html
  9. 20
      templates/mod/ban_form.html
  10. 24
      templates/mod/ban_list.html
  11. 44
      templates/mod/board.html
  12. 4
      templates/mod/confirm.html
  13. 56
      templates/mod/dashboard.html
  14. 36
      templates/mod/inbox.html
  15. 18
      templates/mod/log.html
  16. 4
      templates/mod/login.html
  17. 6
      templates/mod/new_pm.html
  18. 70
      templates/mod/news.html
  19. 8
      templates/mod/noticeboard.html
  20. 14
      templates/mod/pm.html
  21. 20
      templates/mod/rebuild.html
  22. 4
      templates/mod/rebuilt.html
  23. 12
      templates/mod/report.html
  24. 3
      templates/mod/reports.html
  25. 64
      templates/mod/user.html
  26. 57
      templates/mod/users.html
  27. 72
      templates/mod/view_ip.html
  28. 10
      templates/page.html
  29. 4
      templates/themes/basic/info.php
  30. 2
      templates/themes/basic/theme.php
  31. 4
      templates/themes/categories/info.php
  32. 2
      templates/themes/categories/sidebar.html
  33. 12
      templates/themes/categories/theme.php
  34. 2
      templates/themes/frameset/sidebar.html
  35. 6
      templates/themes/frameset/theme.php
  36. 6
      templates/themes/recent/info.php
  37. 28
      templates/themes/recent/theme.php
  38. 16
      templates/themes/rrdtool/info.php
  39. 54
      templates/themes/rrdtool/theme.php
  40. 17
      templates/thread.html

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

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

396
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 <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'])) {

4
install.php

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

2
js/show-op.js

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

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

71
templates/generic_page.html

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

16
templates/index.html

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

20
templates/mod/ban_form.html

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

24
templates/mod/ban_list.html

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

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

4
templates/mod/confirm.html

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

56
templates/mod/dashboard.html

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

@ -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 %}

18
templates/mod/log.html

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

4
templates/mod/login.html

@ -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="">

6
templates/mod/new_pm.html

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

@ -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 %}

8
templates/mod/noticeboard.html

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

14
templates/mod/pm.html

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

20
templates/mod/rebuild.html

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

4
templates/mod/rebuilt.html

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

12
templates/mod/report.html

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