mirror of
https://github.com/vichan-devel/vichan.git
synced 2024-11-12 01:50:48 +01:00
Merge branch 'mod-rewrite'
Conflicts: inc/lib/Twig/Extensions/Extension/Tinyboard.php install.php mod.php stylesheets/style.css templates/index.html templates/page.html templates/thread.html
This commit is contained in:
commit
6a705fd8c2
@ -19,7 +19,7 @@ class AntiBot {
|
|||||||
if ($uppercase)
|
if ($uppercase)
|
||||||
$chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
$chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||||
if ($special_chars)
|
if ($special_chars)
|
||||||
$chars .= ' ~!@#$%^&*()_+,./;\'[]\\{}|:"<>?=-` ';
|
$chars .= ' ~!@#$%^&*()_+,./;\'[]\\{}|:<>?=-` ';
|
||||||
|
|
||||||
$chars = str_split($chars);
|
$chars = str_split($chars);
|
||||||
|
|
||||||
@ -48,7 +48,8 @@ class AntiBot {
|
|||||||
|
|
||||||
foreach ($chars as &$c) {
|
foreach ($chars as &$c) {
|
||||||
if (rand(0, 2) != 0)
|
if (rand(0, 2) != 0)
|
||||||
continue;
|
$c = utf8tohtml($c);
|
||||||
|
else
|
||||||
$c = mb_encode_numericentity($c, array(0, 0xffff, 0, 0xffff), 'UTF-8');
|
$c = mb_encode_numericentity($c, array(0, 0xffff, 0, 0xffff), 'UTF-8');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ class Cache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// debug
|
// debug
|
||||||
if ($data && $config['debug']) {
|
if ($data !== false && $config['debug']) {
|
||||||
$debug['cached'][] = $key;
|
$debug['cached'][] = $key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,6 @@
|
|||||||
$config['check_updates_time'] = 43200; // 12 hours
|
$config['check_updates_time'] = 43200; // 12 hours
|
||||||
|
|
||||||
// Shows some extra information at the bottom of pages. Good for debugging development.
|
// Shows some extra information at the bottom of pages. Good for debugging development.
|
||||||
// Also experimental.
|
|
||||||
$config['debug'] = false;
|
$config['debug'] = false;
|
||||||
// For development purposes. Turns 'display_errors' on. Not recommended for production.
|
// For development purposes. Turns 'display_errors' on. Not recommended for production.
|
||||||
$config['verbose_errors'] = true;
|
$config['verbose_errors'] = true;
|
||||||
@ -362,7 +361,7 @@
|
|||||||
$config['markup'][] = array("/'''(.+?)'''/", "<strong>\$1</strong>");
|
$config['markup'][] = array("/'''(.+?)'''/", "<strong>\$1</strong>");
|
||||||
$config['markup'][] = array("/''(.+?)''/", "<em>\$1</em>");
|
$config['markup'][] = array("/''(.+?)''/", "<em>\$1</em>");
|
||||||
$config['markup'][] = array("/\*\*(.+?)\*\*/", "<span class=\"spoiler\">\$1</span>");
|
$config['markup'][] = array("/\*\*(.+?)\*\*/", "<span class=\"spoiler\">\$1</span>");
|
||||||
$config['markup'][] = array("/^\s*==(.+?)==\s*$/m", "<span class=\"heading\">\$1</span>");
|
$config['markup'][] = array("/^[ |\t]*==(.+?)==[ |\t]*$/m", "<span class=\"heading\">\$1</span>");
|
||||||
|
|
||||||
// Highlight PHP code wrapped in <code> tags (PHP 5.3.0+)
|
// Highlight PHP code wrapped in <code> tags (PHP 5.3.0+)
|
||||||
// $config['markup'][] = array(
|
// $config['markup'][] = array(
|
||||||
@ -816,8 +815,6 @@
|
|||||||
|
|
||||||
// Do a DNS lookup on IP addresses to get their hostname on the IP summary page
|
// Do a DNS lookup on IP addresses to get their hostname on the IP summary page
|
||||||
$config['mod']['dns_lookup'] = true;
|
$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
|
// How many recent posts, per board, to show in the IP summary page
|
||||||
$config['mod']['ip_recentposts'] = 5;
|
$config['mod']['ip_recentposts'] = 5;
|
||||||
|
|
||||||
@ -826,12 +823,17 @@
|
|||||||
|
|
||||||
// How many actions to show per page in the moderation log
|
// How many actions to show per page in the moderation log
|
||||||
$config['mod']['modlog_page'] = 350;
|
$config['mod']['modlog_page'] = 350;
|
||||||
|
// 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
|
// Maximum number of results to display for a search, per board
|
||||||
$config['mod']['search_results'] = 75;
|
$config['mod']['search_results'] = 75;
|
||||||
|
|
||||||
// Maximum number of notices to display on the moderator noticeboard
|
// How many entries to show per page in the moderator noticeboard
|
||||||
$config['mod']['noticeboard_display'] = 50;
|
$config['mod']['noticeboard_page'] = 50;
|
||||||
// Number of entries to summarize and display on the dashboard
|
// Number of entries to summarize and display on the dashboard
|
||||||
$config['mod']['noticeboard_dashboard'] = 5;
|
$config['mod']['noticeboard_dashboard'] = 5;
|
||||||
|
|
||||||
@ -868,6 +870,19 @@
|
|||||||
* ====================
|
* ====================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Capcode permissions
|
||||||
|
$config['mod']['capcode'] = array(
|
||||||
|
// JANITOR => array('Janitor'),
|
||||||
|
MOD => array('Mod'),
|
||||||
|
ADMIN => true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Example: Allow mods to post with "## Moderator" as well
|
||||||
|
// $config['mod']['capcode'][MOD][] = 'Moderator';
|
||||||
|
|
||||||
|
// Example: Allow janitors to post with any capcode
|
||||||
|
// $config['mod']['capcode'][JANITOR] = true;
|
||||||
|
|
||||||
// Set any of the below to "DISABLED" to make them unavailable for everyone.
|
// Set any of the below to "DISABLED" to make them unavailable for everyone.
|
||||||
|
|
||||||
// Don't worry about per-board moderators. Let all mods moderate any board.
|
// Don't worry about per-board moderators. Let all mods moderate any board.
|
||||||
@ -1043,6 +1058,4 @@
|
|||||||
|
|
||||||
// Complex regular expression to catch URLs
|
// Complex regular expression to catch URLs
|
||||||
$config['url_regex'] = '/' . '(https?|ftp):\/\/' . '(([\w\-]+\.)+[a-zA-Z]{2,6}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' . '(:\d+)?' . '(\/([\w\-~.#\/?=&;:+%!*\[\]@$\'()+,|\^]+)?)?' . '/';
|
$config['url_regex'] = '/' . '(https?|ftp):\/\/' . '(([\w\-]+\.)+[a-zA-Z]{2,6}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' . '(:\d+)?' . '(\/([\w\-~.#\/?=&;:+%!*\[\]@$\'()+,|\^]+)?)?' . '/';
|
||||||
// INSANE regular expression for IPv6 addresses
|
|
||||||
$config['ipv6_regex'] = '((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?';
|
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ class Filter {
|
|||||||
case 'name':
|
case 'name':
|
||||||
return preg_match($match, $post['name']);
|
return preg_match($match, $post['name']);
|
||||||
case 'trip':
|
case 'trip':
|
||||||
return preg_match($match, $post['trip']);
|
return $match === $post['trip'];
|
||||||
case 'email':
|
case 'email':
|
||||||
return preg_match($match, $post['email']);
|
return preg_match($match, $post['email']);
|
||||||
case 'subject':
|
case 'subject':
|
||||||
|
@ -32,7 +32,30 @@ function loadConfig() {
|
|||||||
if (!isset($_SERVER['REMOTE_ADDR']))
|
if (!isset($_SERVER['REMOTE_ADDR']))
|
||||||
$_SERVER['REMOTE_ADDR'] = '0.0.0.0';
|
$_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();
|
$config = array();
|
||||||
foreach ($arrays as $key) {
|
foreach ($arrays as $key) {
|
||||||
@ -277,10 +300,13 @@ function setupBoard($array) {
|
|||||||
|
|
||||||
$board = array(
|
$board = array(
|
||||||
'uri' => $array['uri'],
|
'uri' => $array['uri'],
|
||||||
'name' => $array['title'],
|
'title' => $array['title'],
|
||||||
'title' => $array['subtitle']
|
'subtitle' => $array['subtitle']
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// older versions
|
||||||
|
$board['name'] = &$board['title'];
|
||||||
|
|
||||||
$board['dir'] = sprintf($config['board_path'], $board['uri']);
|
$board['dir'] = sprintf($config['board_path'], $board['uri']);
|
||||||
$board['url'] = sprintf($config['board_abbreviation'], $board['uri']);
|
$board['url'] = sprintf($config['board_abbreviation'], $board['uri']);
|
||||||
|
|
||||||
@ -690,13 +716,13 @@ function post(array $post) {
|
|||||||
$query->bindValue(':password', $post['password']);
|
$query->bindValue(':password', $post['password']);
|
||||||
$query->bindValue(':ip', isset($post['ip']) ? $post['ip'] : $_SERVER['REMOTE_ADDR']);
|
$query->bindValue(':ip', isset($post['ip']) ? $post['ip'] : $_SERVER['REMOTE_ADDR']);
|
||||||
|
|
||||||
if ($post['mod'] && $post['sticky']) {
|
if ($post['op'] && $post['mod'] && $post['sticky']) {
|
||||||
$query->bindValue(':sticky', 1, PDO::PARAM_INT);
|
$query->bindValue(':sticky', 1, PDO::PARAM_INT);
|
||||||
} else {
|
} else {
|
||||||
$query->bindValue(':sticky', 0, PDO::PARAM_INT);
|
$query->bindValue(':sticky', 0, PDO::PARAM_INT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($post['mod'] && $post['locked']) {
|
if ($post['op'] && $post['mod'] && $post['locked']) {
|
||||||
$query->bindValue(':locked', 1, PDO::PARAM_INT);
|
$query->bindValue(':locked', 1, PDO::PARAM_INT);
|
||||||
} else {
|
} else {
|
||||||
$query->bindValue(':locked', 0, PDO::PARAM_INT);
|
$query->bindValue(':locked', 0, PDO::PARAM_INT);
|
||||||
@ -777,12 +803,8 @@ function deleteFile($id, $remove_entirely_if_already=true) {
|
|||||||
$query = prepare(sprintf("SELECT `thread`,`thumb`,`file` FROM `posts_%s` WHERE `id` = :id LIMIT 1", $board['uri']));
|
$query = prepare(sprintf("SELECT `thread`,`thumb`,`file` FROM `posts_%s` WHERE `id` = :id LIMIT 1", $board['uri']));
|
||||||
$query->bindValue(':id', $id, PDO::PARAM_INT);
|
$query->bindValue(':id', $id, PDO::PARAM_INT);
|
||||||
$query->execute() or error(db_error($query));
|
$query->execute() or error(db_error($query));
|
||||||
|
if (!$post = $query->fetch())
|
||||||
if ($query->rowCount() < 1) {
|
|
||||||
error($config['error']['invalidpost']);
|
error($config['error']['invalidpost']);
|
||||||
}
|
|
||||||
|
|
||||||
$post = $query->fetch();
|
|
||||||
|
|
||||||
if ($post['file'] == 'deleted' && !$post['thread'])
|
if ($post['file'] == 'deleted' && !$post['thread'])
|
||||||
return; // Can't delete OP's image completely.
|
return; // Can't delete OP's image completely.
|
||||||
@ -801,13 +823,14 @@ function deleteFile($id, $remove_entirely_if_already=true) {
|
|||||||
// Set file to 'deleted'
|
// Set file to 'deleted'
|
||||||
$query->bindValue(':file', 'deleted', PDO::PARAM_INT);
|
$query->bindValue(':file', 'deleted', PDO::PARAM_INT);
|
||||||
}
|
}
|
||||||
// Update database
|
|
||||||
|
|
||||||
$query->bindValue(':id', $id, PDO::PARAM_INT);
|
$query->bindValue(':id', $id, PDO::PARAM_INT);
|
||||||
$query->execute() or error(db_error($query));
|
$query->execute() or error(db_error($query));
|
||||||
|
|
||||||
if ($post['thread'])
|
if ($post['thread'])
|
||||||
buildThread($post['thread']);
|
buildThread($post['thread']);
|
||||||
|
else
|
||||||
|
buildThread($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// rebuild post (markup)
|
// rebuild post (markup)
|
||||||
@ -1179,6 +1202,7 @@ function buildIndex() {
|
|||||||
global $board, $config;
|
global $board, $config;
|
||||||
|
|
||||||
$pages = getPages();
|
$pages = getPages();
|
||||||
|
$antibot = create_antibot($board['uri']);
|
||||||
|
|
||||||
$page = 1;
|
$page = 1;
|
||||||
while ($page <= $config['max_pages'] && $content = index($page)) {
|
while ($page <= $config['max_pages'] && $content = index($page)) {
|
||||||
@ -1188,7 +1212,7 @@ function buildIndex() {
|
|||||||
$content['pages'] = $pages;
|
$content['pages'] = $pages;
|
||||||
$content['pages'][$page-1]['selected'] = true;
|
$content['pages'][$page-1]['selected'] = true;
|
||||||
$content['btn'] = getPageButtons($content['pages']);
|
$content['btn'] = getPageButtons($content['pages']);
|
||||||
$content['antibot'] = create_antibot($board['uri']);
|
$content['antibot'] = $antibot;
|
||||||
file_write($filename, Element('index.html', $content));
|
file_write($filename, Element('index.html', $content));
|
||||||
|
|
||||||
if (isset($md5) && $md5 == md5_file($filename)) {
|
if (isset($md5) && $md5 == md5_file($filename)) {
|
||||||
@ -1370,10 +1394,12 @@ function markup(&$body, $track_cites = false) {
|
|||||||
if ($config['auto_unicode']) {
|
if ($config['auto_unicode']) {
|
||||||
$body = unicodify($body);
|
$body = unicodify($body);
|
||||||
|
|
||||||
|
if ($config['markup_urls']) {
|
||||||
foreach ($markup_urls as &$url) {
|
foreach ($markup_urls as &$url) {
|
||||||
$body = str_replace(unicodify($url), $url, $body);
|
$body = str_replace(unicodify($url), $url, $body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// replace tabs with 8 spaces
|
// replace tabs with 8 spaces
|
||||||
$body = str_replace("\t", ' ', $body);
|
$body = str_replace("\t", ' ', $body);
|
||||||
|
@ -10,19 +10,22 @@ class Twig_Extensions_Extension_Tinyboard extends Twig_Extension
|
|||||||
public function getFilters()
|
public function getFilters()
|
||||||
{
|
{
|
||||||
return Array(
|
return Array(
|
||||||
'filesize' => new Twig_Filter_Function('format_bytes', Array('needs_environment' => false)),
|
'filesize' => new Twig_Filter_Function('format_bytes'),
|
||||||
'truncate' => new Twig_Filter_Function('twig_truncate_filter', array('needs_environment' => false)),
|
'truncate' => new Twig_Filter_Function('twig_truncate_filter'),
|
||||||
'truncate_body' => new Twig_Filter_Function('truncate', array('needs_environment' => false)),
|
'truncate_body' => new Twig_Filter_Function('truncate'),
|
||||||
'extension' => new Twig_Filter_Function('twig_extension_filter', array('needs_environment' => false)),
|
'extension' => new Twig_Filter_Function('twig_extension_filter'),
|
||||||
'sprintf' => new Twig_Filter_Function('sprintf', array('needs_environment' => false)),
|
'sprintf' => new Twig_Filter_Function('sprintf'),
|
||||||
'capcode' => new Twig_Filter_Function('capcode', array('needs_environment' => false)),
|
'capcode' => new Twig_Filter_Function('capcode'),
|
||||||
'hasPermission' => new Twig_Filter_Function('twig_hasPermission_filter', array('needs_environment' => false)),
|
'hasPermission' => new Twig_Filter_Function('twig_hasPermission_filter'),
|
||||||
'date' => new Twig_Filter_Function('twig_date_filter', array('needs_environment' => false)),
|
'date' => new Twig_Filter_Function('twig_date_filter'),
|
||||||
'poster_id' => new Twig_Filter_Function('poster_id', array('needs_environment' => false)),
|
'poster_id' => new Twig_Filter_Function('poster_id'),
|
||||||
'remove_whitespace' => new Twig_Filter_Function('twig_remove_whitespace_filter', array('needs_environment' => false)),
|
'remove_whitespace' => new Twig_Filter_Function('twig_remove_whitespace_filter'),
|
||||||
'count' => new Twig_Filter_Function('count', array('needs_environment' => false)),
|
'count' => new Twig_Filter_Function('count'),
|
||||||
'until' => new Twig_Filter_Function('until', array('needs_environment' => false)),
|
'ago' => new Twig_Filter_Function('ago'),
|
||||||
'addslashes' => new Twig_Filter_Function('addslashes', array('needs_environment' => false)),
|
'until' => new Twig_Filter_Function('until'),
|
||||||
|
'split' => new Twig_Filter_Function('twig_split_filter'),
|
||||||
|
'push' => new Twig_Filter_Function('twig_push_filter'),
|
||||||
|
'addslashes' => new Twig_Filter_Function('addslashes')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,10 +37,11 @@ class Twig_Extensions_Extension_Tinyboard extends Twig_Extension
|
|||||||
public function getFunctions()
|
public function getFunctions()
|
||||||
{
|
{
|
||||||
return Array(
|
return Array(
|
||||||
'time' => new Twig_Filter_Function('time', array('needs_environment' => false)),
|
'time' => new Twig_Filter_Function('time'),
|
||||||
'timezone' => new Twig_Filter_Function('twig_timezone_function', array('needs_environment' => false)),
|
'floor' => new Twig_Filter_Function('floor'),
|
||||||
'hiddenInputs' => new Twig_Filter_Function('hiddenInputs', array('needs_environment' => false)),
|
'timezone' => new Twig_Filter_Function('twig_timezone_function'),
|
||||||
'hiddenInputsHash' => new Twig_Filter_Function('hiddenInputsHash', array('needs_environment' => false))
|
'hiddenInputs' => new Twig_Filter_Function('hiddenInputs'),
|
||||||
|
'hiddenInputsHash' => new Twig_Filter_Function('hiddenInputsHash'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +61,15 @@ function twig_timezone_function() {
|
|||||||
return sprintf("%s%02d", ($hr = (int)floor(($tz = date('Z')) / 3600)) > 0 ? '+' : '-', abs($hr)) . ':' . sprintf("%02d", (($tz / 3600) - $hr) * 60);
|
return sprintf("%s%02d", ($hr = (int)floor(($tz = date('Z')) / 3600)) > 0 ? '+' : '-', abs($hr)) . ':' . sprintf("%02d", (($tz / 3600) - $hr) * 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function twig_split_filter($str, $delim) {
|
||||||
|
return explode($delim, $str);
|
||||||
|
}
|
||||||
|
|
||||||
|
function twig_push_filter($array, $value) {
|
||||||
|
array_push($array, $value);
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
function twig_remove_whitespace_filter($data) {
|
function twig_remove_whitespace_filter($data) {
|
||||||
return preg_replace('/[\t\r\n]/', '', $data);
|
return preg_replace('/[\t\r\n]/', '', $data);
|
||||||
}
|
}
|
||||||
@ -65,7 +78,7 @@ function twig_date_filter($date, $format) {
|
|||||||
return strftime($format, $date);
|
return strftime($format, $date);
|
||||||
}
|
}
|
||||||
|
|
||||||
function twig_hasPermission_filter($mod, $permission, $board) {
|
function twig_hasPermission_filter($mod, $permission, $board = null) {
|
||||||
return hasPermission($permission, $board, $mod);
|
return hasPermission($permission, $board, $mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
287
inc/mod-old.php
Normal file
287
inc/mod-old.php
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2012 Tinyboard Development Group
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
|
||||||
|
// You cannot request this file directly.
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a hash/salt pair for validate logins
|
||||||
|
function mkhash($username, $password, $salt = false) {
|
||||||
|
global $config;
|
||||||
|
|
||||||
|
if (!$salt) {
|
||||||
|
// create some sort of salt for the hash
|
||||||
|
$salt = substr(base64_encode(sha1(rand() . time(), true) . $config['cookies']['salt']), 0, 15);
|
||||||
|
|
||||||
|
$generated_salt = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate hash (method is not important as long as it's strong)
|
||||||
|
$hash = substr(base64_encode(md5($username . sha1($username . $password . $salt . ($config['mod']['lock_ip'] ? $_SERVER['REMOTE_ADDR'] : ''), true), true)), 0, 20);
|
||||||
|
|
||||||
|
if (isset($generated_salt))
|
||||||
|
return Array($hash, $salt);
|
||||||
|
else
|
||||||
|
return $hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
function login($username, $password, $makehash=true) {
|
||||||
|
global $mod;
|
||||||
|
|
||||||
|
// SHA1 password
|
||||||
|
if ($makehash) {
|
||||||
|
$password = sha1($password);
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = prepare("SELECT `id`,`type`,`boards` FROM `mods` WHERE `username` = :username AND `password` = :password LIMIT 1");
|
||||||
|
$query->bindValue(':username', $username);
|
||||||
|
$query->bindValue(':password', $password);
|
||||||
|
$query->execute() or error(db_error($query));
|
||||||
|
|
||||||
|
if ($user = $query->fetch()) {
|
||||||
|
return $mod = Array(
|
||||||
|
'id' => $user['id'],
|
||||||
|
'type' => $user['type'],
|
||||||
|
'username' => $username,
|
||||||
|
'hash' => mkhash($username, $password),
|
||||||
|
'boards' => explode(',', $user['boards'])
|
||||||
|
);
|
||||||
|
} else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCookies() {
|
||||||
|
global $mod, $config;
|
||||||
|
if (!$mod)
|
||||||
|
error('setCookies() was called for a non-moderator!');
|
||||||
|
|
||||||
|
setcookie($config['cookies']['mod'],
|
||||||
|
$mod['username'] . // username
|
||||||
|
':' .
|
||||||
|
$mod['hash'][0] . // password
|
||||||
|
':' .
|
||||||
|
$mod['hash'][1], // salt
|
||||||
|
time() + $config['cookies']['expire'], $config['cookies']['jail'] ? $config['cookies']['path'] : '/', null, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyCookies() {
|
||||||
|
global $config;
|
||||||
|
// Delete the cookies
|
||||||
|
setcookie($config['cookies']['mod'], 'deleted', time() - $config['cookies']['expire'], $config['cookies']['jail']?$config['cookies']['path'] : '/', null, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_pm_header() {
|
||||||
|
global $mod;
|
||||||
|
$query = prepare("SELECT `id` FROM `pms` WHERE `to` = :id AND `unread` = 1");
|
||||||
|
$query->bindValue(':id', $mod['id'], PDO::PARAM_INT);
|
||||||
|
$query->execute() or error(db_error($query));
|
||||||
|
|
||||||
|
if ($pm = $query->fetch()) {
|
||||||
|
return Array('id' => $pm['id'], 'waiting' => $query->rowCount() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function modLog($action, $_board=null) {
|
||||||
|
global $mod, $board, $config;
|
||||||
|
$query = prepare("INSERT INTO `modlogs` VALUES (:id, :ip, :board, :time, :text)");
|
||||||
|
$query->bindValue(':id', $mod['id'], PDO::PARAM_INT);
|
||||||
|
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
|
||||||
|
$query->bindValue(':time', time(), PDO::PARAM_INT);
|
||||||
|
$query->bindValue(':text', $action);
|
||||||
|
if (isset($_board))
|
||||||
|
$query->bindValue(':board', $_board);
|
||||||
|
elseif (isset($board))
|
||||||
|
$query->bindValue(':board', $board['uri']);
|
||||||
|
else
|
||||||
|
$query->bindValue(':board', null, PDO::PARAM_NULL);
|
||||||
|
$query->execute() or error(db_error($query));
|
||||||
|
|
||||||
|
if ($config['syslog'])
|
||||||
|
_syslog(LOG_INFO, '[mod/' . $mod['username'] . ']: ' . $action);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates a <ul> element with a list of linked
|
||||||
|
// boards and their subtitles. (without the <ul> opening and ending tags)
|
||||||
|
function ulBoards() {
|
||||||
|
global $mod, $config;
|
||||||
|
|
||||||
|
$body = '';
|
||||||
|
|
||||||
|
// List of boards
|
||||||
|
$boards = listBoards();
|
||||||
|
|
||||||
|
foreach ($boards as &$b) {
|
||||||
|
$body .= '<li>' .
|
||||||
|
'<a href="?/' .
|
||||||
|
sprintf($config['board_path'], $b['uri']) . $config['file_index'] .
|
||||||
|
'">' .
|
||||||
|
sprintf($config['board_abbreviation'], $b['uri']) .
|
||||||
|
'</a> - ' .
|
||||||
|
$b['title'] .
|
||||||
|
(isset($b['subtitle']) ? '<span class="unimportant"> — ' . $b['subtitle'] . '</span>' : '') .
|
||||||
|
($mod['type'] >= $config['mod']['manageboards'] ?
|
||||||
|
' <a href="?/' . $b['uri'] . '/edit" class="unimportant">[manage]</a>' : '') .
|
||||||
|
'</li>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mod['type'] >= $config['mod']['newboard']) {
|
||||||
|
$body .= '<li style="margin-top:15px;"><a href="?/new"><strong>' . _('Create new board') . '</strong></a></li>';
|
||||||
|
}
|
||||||
|
return $body;
|
||||||
|
}
|
||||||
|
|
||||||
|
function form_newBan($ip=null, $reason='', $continue=false, $delete=false, $board=false, $allow_public = false) {
|
||||||
|
global $config, $mod;
|
||||||
|
|
||||||
|
$boards = listBoards();
|
||||||
|
$__boards = '<li><input type="radio" checked="checked" name="board" id="board_*" value=""/> <label style="display:inline" for="board_*"><em>' . _('all boards') . '</em></label></li>';
|
||||||
|
foreach ($boards as &$_board) {
|
||||||
|
$__boards .= '<li>' .
|
||||||
|
'<input type="radio" name="board" id="board_' . $_board['uri'] . '" value="' . $_board['uri'] . '">' .
|
||||||
|
'<label style="display:inline" for="board_' . $_board['uri'] . '"> ' .
|
||||||
|
($_board['uri'] == '*' ?
|
||||||
|
'<em>"*"</em>'
|
||||||
|
:
|
||||||
|
sprintf($config['board_abbreviation'], $_board['uri'])
|
||||||
|
) .
|
||||||
|
' - ' . $_board['title'] .
|
||||||
|
'</label>' .
|
||||||
|
'</li>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return '<fieldset><legend>New ban</legend>' .
|
||||||
|
'<form action="?/ban" method="post">' .
|
||||||
|
($continue ? '<input type="hidden" name="continue" value="' . htmlentities($continue) . '" />' : '') .
|
||||||
|
($delete || $allow_public ? '<input type="hidden" name="' . (!$allow_public ? 'delete' : 'post') . '" value="' . htmlentities($delete) . '" />' : '') .
|
||||||
|
($board ? '<input type="hidden" name="board" value="' . htmlentities($board) . '" />' : '') .
|
||||||
|
'<table>' .
|
||||||
|
'<tr>' .
|
||||||
|
'<th><label for="ip">IP ' .
|
||||||
|
($config['ban_cidr'] ? '<span class="unimportant">(or subnet)' : '') .
|
||||||
|
'</span></label></th>' .
|
||||||
|
'<td><input type="text" name="ip" id="ip" size="30" maxlength="30" ' .
|
||||||
|
(isset($ip) ?
|
||||||
|
'value="' . htmlentities($ip) . '" ' : ''
|
||||||
|
) .
|
||||||
|
'/></td>' .
|
||||||
|
'</tr>' .
|
||||||
|
'<tr>' .
|
||||||
|
'<th><label for="reason">Reason</label></th>' .
|
||||||
|
'<td><textarea name="reason" id="reason" rows="5" cols="30">' .
|
||||||
|
htmlentities($reason) .
|
||||||
|
'</textarea></td>' .
|
||||||
|
'</tr>' .
|
||||||
|
($mod['type'] >= $config['mod']['public_ban'] && $allow_public ?
|
||||||
|
'<tr>' .
|
||||||
|
'<th><label for="message">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="' . htmlentities($config['mod']['default_ban_message']) . '" />' .
|
||||||
|
' <span class="unimportant">(public; attached to post)</span></td>' .
|
||||||
|
'<script type="text/javascript">' .
|
||||||
|
'document.getElementById(\'message\').disabled = true;' .
|
||||||
|
'document.getElementById(\'public_message\').onchange = function() {' .
|
||||||
|
'document.getElementById(\'message\').disabled = !this.checked;' .
|
||||||
|
'}' .
|
||||||
|
|
||||||
|
'</script>' .
|
||||||
|
'</tr>'
|
||||||
|
: '') .
|
||||||
|
'<tr>' .
|
||||||
|
'<th><label for="length">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>' .
|
||||||
|
'<td><ul style="list-style:none;padding:2px 5px">' . $__boards . '</tl></td>' .
|
||||||
|
'</tr>' .
|
||||||
|
|
||||||
|
'<tr>' .
|
||||||
|
'<td></td>' .
|
||||||
|
'<td><input name="new_ban" type="submit" value="New Ban" /></td>' .
|
||||||
|
'</tr>' .
|
||||||
|
'</table>' .
|
||||||
|
'</form>' .
|
||||||
|
'</fieldset>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function form_newBoard() {
|
||||||
|
return '<fieldset><legend>New board</legend>' .
|
||||||
|
'<form action="?/new" method="post">' .
|
||||||
|
'<table>' .
|
||||||
|
'<tr>' .
|
||||||
|
'<th><label for="board">URI</label></th>' .
|
||||||
|
'<td><input type="text" name="uri" id="board" size="10" />' .
|
||||||
|
' <span class="unimportant">(eg. "b"; "mu")</span></td>' .
|
||||||
|
'</tr>' .
|
||||||
|
'<tr>' .
|
||||||
|
'<th><label for="title">Title</label></th>' .
|
||||||
|
'<td><input type="text" name="title" id="title" size="25" />' .
|
||||||
|
' <span class="unimportant">(eg. "Random")</span></td>' .
|
||||||
|
'</tr>' .
|
||||||
|
'<tr>' .
|
||||||
|
'<th><label for="subtitle">Subtitle</label></th>' .
|
||||||
|
'<td><input type="text" name="subtitle" id="subtitle" size="25" />' .
|
||||||
|
' <span class="unimportant">(optional)</span></td>' .
|
||||||
|
'</tr>' .
|
||||||
|
'<tr>' .
|
||||||
|
'<td></td>' .
|
||||||
|
'<td><input name="new_board" type="submit" value="New Board" /></td>' .
|
||||||
|
'</tr>' .
|
||||||
|
'</table>' .
|
||||||
|
'</form>' .
|
||||||
|
'</fieldset>';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function removeBan($id) {
|
||||||
|
global $config, $memcached;
|
||||||
|
|
||||||
|
$query = prepare("DELETE FROM `bans` WHERE `id` = :id");
|
||||||
|
$query->bindValue(':id', $id, PDO::PARAM_INT);
|
||||||
|
$query->execute() or error(db_error($query));
|
||||||
|
|
||||||
|
//if ($config['memcached']['enabled']) {
|
||||||
|
// Remove cached ban
|
||||||
|
// TODO
|
||||||
|
// $memcached->delete("ban_{$id}");
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Validate session
|
||||||
|
|
||||||
|
if (isset($_COOKIE[$config['cookies']['mod']])) {
|
||||||
|
// Should be username:hash:salt
|
||||||
|
$cookie = explode(':', $_COOKIE[$config['cookies']['mod']]);
|
||||||
|
if (count($cookie) != 3) {
|
||||||
|
destroyCookies();
|
||||||
|
error($config['error']['malformed']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = prepare("SELECT `id`, `type`, `boards`, `password` FROM `mods` WHERE `username` = :username LIMIT 1");
|
||||||
|
$query->bindValue(':username', $cookie[0]);
|
||||||
|
$query->execute() or error(db_error($query));
|
||||||
|
$user = $query->fetch();
|
||||||
|
|
||||||
|
// validate password hash
|
||||||
|
if ($cookie[1] != mkhash($cookie[0], $user['password'], $cookie[2])) {
|
||||||
|
// Malformed cookies
|
||||||
|
destroyCookies();
|
||||||
|
error($config['error']['malformed']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$mod = Array(
|
||||||
|
'id' => $user['id'],
|
||||||
|
'type' => $user['type'],
|
||||||
|
'username' => $cookie[0],
|
||||||
|
'boards' => explode(',', $user['boards'])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
278
inc/mod.php
278
inc/mod.php
@ -4,284 +4,12 @@
|
|||||||
* Copyright (c) 2010-2012 Tinyboard Development Group
|
* Copyright (c) 2010-2012 Tinyboard Development Group
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// WARNING: Including this file is DEPRECIATED. It's only here to support older versions and won't exist forever.
|
||||||
|
|
||||||
if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
|
if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
|
||||||
// You cannot request this file directly.
|
// You cannot request this file directly.
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a hash/salt pair for validate logins
|
require 'inc/mod/auth.php';
|
||||||
function mkhash($username, $password, $salt = false) {
|
|
||||||
global $config;
|
|
||||||
|
|
||||||
if (!$salt) {
|
|
||||||
// create some sort of salt for the hash
|
|
||||||
$salt = substr(base64_encode(sha1(rand() . time(), true) . $config['cookies']['salt']), 0, 15);
|
|
||||||
|
|
||||||
$generated_salt = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate hash (method is not important as long as it's strong)
|
|
||||||
$hash = substr(base64_encode(md5($username . sha1($username . $password . $salt . ($config['mod']['lock_ip'] ? $_SERVER['REMOTE_ADDR'] : ''), true), true)), 0, 20);
|
|
||||||
|
|
||||||
if (isset($generated_salt))
|
|
||||||
return Array($hash, $salt);
|
|
||||||
else
|
|
||||||
return $hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
function login($username, $password, $makehash=true) {
|
|
||||||
global $mod;
|
|
||||||
|
|
||||||
// SHA1 password
|
|
||||||
if ($makehash) {
|
|
||||||
$password = sha1($password);
|
|
||||||
}
|
|
||||||
|
|
||||||
$query = prepare("SELECT `id`,`type`,`boards` FROM `mods` WHERE `username` = :username AND `password` = :password LIMIT 1");
|
|
||||||
$query->bindValue(':username', $username);
|
|
||||||
$query->bindValue(':password', $password);
|
|
||||||
$query->execute() or error(db_error($query));
|
|
||||||
|
|
||||||
if ($user = $query->fetch()) {
|
|
||||||
return $mod = Array(
|
|
||||||
'id' => $user['id'],
|
|
||||||
'type' => $user['type'],
|
|
||||||
'username' => $username,
|
|
||||||
'hash' => mkhash($username, $password),
|
|
||||||
'boards' => explode(',', $user['boards'])
|
|
||||||
);
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCookies() {
|
|
||||||
global $mod, $config;
|
|
||||||
if (!$mod)
|
|
||||||
error('setCookies() was called for a non-moderator!');
|
|
||||||
|
|
||||||
setcookie($config['cookies']['mod'],
|
|
||||||
$mod['username'] . // username
|
|
||||||
':' .
|
|
||||||
$mod['hash'][0] . // password
|
|
||||||
':' .
|
|
||||||
$mod['hash'][1], // salt
|
|
||||||
time() + $config['cookies']['expire'], $config['cookies']['jail'] ? $config['cookies']['path'] : '/', null, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function destroyCookies() {
|
|
||||||
global $config;
|
|
||||||
// Delete the cookies
|
|
||||||
setcookie($config['cookies']['mod'], 'deleted', time() - $config['cookies']['expire'], $config['cookies']['jail']?$config['cookies']['path'] : '/', null, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function create_pm_header() {
|
|
||||||
global $mod;
|
|
||||||
$query = prepare("SELECT `id` FROM `pms` WHERE `to` = :id AND `unread` = 1");
|
|
||||||
$query->bindValue(':id', $mod['id'], PDO::PARAM_INT);
|
|
||||||
$query->execute() or error(db_error($query));
|
|
||||||
|
|
||||||
if ($pm = $query->fetch()) {
|
|
||||||
return Array('id' => $pm['id'], 'waiting' => $query->rowCount() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function modLog($action, $_board=null) {
|
|
||||||
global $mod, $board, $config;
|
|
||||||
$query = prepare("INSERT INTO `modlogs` VALUES (:id, :ip, :board, :time, :text)");
|
|
||||||
$query->bindValue(':id', $mod['id'], PDO::PARAM_INT);
|
|
||||||
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
|
|
||||||
$query->bindValue(':time', time(), PDO::PARAM_INT);
|
|
||||||
$query->bindValue(':text', $action);
|
|
||||||
if (isset($_board))
|
|
||||||
$query->bindValue(':board', $_board);
|
|
||||||
elseif (isset($board))
|
|
||||||
$query->bindValue(':board', $board['uri']);
|
|
||||||
else
|
|
||||||
$query->bindValue(':board', null, PDO::PARAM_NULL);
|
|
||||||
$query->execute() or error(db_error($query));
|
|
||||||
|
|
||||||
if ($config['syslog'])
|
|
||||||
_syslog(LOG_INFO, '[mod/' . $mod['username'] . ']: ' . $action);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates a <ul> element with a list of linked
|
|
||||||
// boards and their subtitles. (without the <ul> opening and ending tags)
|
|
||||||
function ulBoards() {
|
|
||||||
global $mod, $config;
|
|
||||||
|
|
||||||
$body = '';
|
|
||||||
|
|
||||||
// List of boards
|
|
||||||
$boards = listBoards();
|
|
||||||
|
|
||||||
foreach ($boards as &$b) {
|
|
||||||
$body .= '<li>' .
|
|
||||||
'<a href="?/' .
|
|
||||||
sprintf($config['board_path'], $b['uri']) . $config['file_index'] .
|
|
||||||
'">' .
|
|
||||||
sprintf($config['board_abbreviation'], $b['uri']) .
|
|
||||||
'</a> - ' .
|
|
||||||
$b['title'] .
|
|
||||||
(isset($b['subtitle']) ? '<span class="unimportant"> — ' . $b['subtitle'] . '</span>' : '') .
|
|
||||||
($mod['type'] >= $config['mod']['manageboards'] ?
|
|
||||||
' <a href="?/' . $b['uri'] . '/edit" class="unimportant">[manage]</a>' : '') .
|
|
||||||
'</li>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($mod['type'] >= $config['mod']['newboard']) {
|
|
||||||
$body .= '<li style="margin-top:15px;"><a href="?/new"><strong>' . _('Create new board') . '</strong></a></li>';
|
|
||||||
}
|
|
||||||
return $body;
|
|
||||||
}
|
|
||||||
|
|
||||||
function form_newBan($ip=null, $reason='', $continue=false, $delete=false, $board=false, $allow_public = false) {
|
|
||||||
global $config, $mod;
|
|
||||||
|
|
||||||
$boards = listBoards();
|
|
||||||
$__boards = '<li><input type="radio" checked="checked" name="board" id="board_*" value=""/> <label style="display:inline" for="board_*"><em>' . _('all boards') . '</em></label></li>';
|
|
||||||
foreach ($boards as &$_board) {
|
|
||||||
$__boards .= '<li>' .
|
|
||||||
'<input type="radio" name="board" id="board_' . $_board['uri'] . '" value="' . $_board['uri'] . '">' .
|
|
||||||
'<label style="display:inline" for="board_' . $_board['uri'] . '"> ' .
|
|
||||||
($_board['uri'] == '*' ?
|
|
||||||
'<em>"*"</em>'
|
|
||||||
:
|
|
||||||
sprintf($config['board_abbreviation'], $_board['uri'])
|
|
||||||
) .
|
|
||||||
' - ' . $_board['title'] .
|
|
||||||
'</label>' .
|
|
||||||
'</li>';
|
|
||||||
}
|
|
||||||
|
|
||||||
return '<fieldset><legend>New ban</legend>' .
|
|
||||||
'<form action="?/ban" method="post">' .
|
|
||||||
($continue ? '<input type="hidden" name="continue" value="' . htmlentities($continue) . '" />' : '') .
|
|
||||||
($delete || $allow_public ? '<input type="hidden" name="' . (!$allow_public ? 'delete' : 'post') . '" value="' . htmlentities($delete) . '" />' : '') .
|
|
||||||
($board ? '<input type="hidden" name="board" value="' . htmlentities($board) . '" />' : '') .
|
|
||||||
'<table>' .
|
|
||||||
'<tr>' .
|
|
||||||
'<th><label for="ip">IP ' .
|
|
||||||
($config['ban_cidr'] ? '<span class="unimportant">(or subnet)' : '') .
|
|
||||||
'</span></label></th>' .
|
|
||||||
'<td><input type="text" name="ip" id="ip" size="30" maxlength="30" ' .
|
|
||||||
(isset($ip) ?
|
|
||||||
'value="' . htmlentities($ip) . '" ' : ''
|
|
||||||
) .
|
|
||||||
'/></td>' .
|
|
||||||
'</tr>' .
|
|
||||||
'<tr>' .
|
|
||||||
'<th><label for="reason">Reason</label></th>' .
|
|
||||||
'<td><textarea name="reason" id="reason" rows="5" cols="30">' .
|
|
||||||
htmlentities($reason) .
|
|
||||||
'</textarea></td>' .
|
|
||||||
'</tr>' .
|
|
||||||
($mod['type'] >= $config['mod']['public_ban'] && $allow_public ?
|
|
||||||
'<tr>' .
|
|
||||||
'<th><label for="message">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="' . htmlentities($config['mod']['default_ban_message']) . '" />' .
|
|
||||||
' <span class="unimportant">(public; attached to post)</span></td>' .
|
|
||||||
'<script type="text/javascript">' .
|
|
||||||
'document.getElementById(\'message\').disabled = true;' .
|
|
||||||
'document.getElementById(\'public_message\').onchange = function() {' .
|
|
||||||
'document.getElementById(\'message\').disabled = !this.checked;' .
|
|
||||||
'}' .
|
|
||||||
|
|
||||||
'</script>' .
|
|
||||||
'</tr>'
|
|
||||||
: '') .
|
|
||||||
'<tr>' .
|
|
||||||
'<th><label for="length">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>' .
|
|
||||||
'<td><ul style="list-style:none;padding:2px 5px">' . $__boards . '</tl></td>' .
|
|
||||||
'</tr>' .
|
|
||||||
|
|
||||||
'<tr>' .
|
|
||||||
'<td></td>' .
|
|
||||||
'<td><input name="new_ban" type="submit" value="New Ban" /></td>' .
|
|
||||||
'</tr>' .
|
|
||||||
'</table>' .
|
|
||||||
'</form>' .
|
|
||||||
'</fieldset>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function form_newBoard() {
|
|
||||||
return '<fieldset><legend>New board</legend>' .
|
|
||||||
'<form action="?/new" method="post">' .
|
|
||||||
'<table>' .
|
|
||||||
'<tr>' .
|
|
||||||
'<th><label for="board">URI</label></th>' .
|
|
||||||
'<td><input type="text" name="uri" id="board" size="10" />' .
|
|
||||||
' <span class="unimportant">(eg. "b"; "mu")</span></td>' .
|
|
||||||
'</tr>' .
|
|
||||||
'<tr>' .
|
|
||||||
'<th><label for="title">Title</label></th>' .
|
|
||||||
'<td><input type="text" name="title" id="title" size="25" />' .
|
|
||||||
' <span class="unimportant">(eg. "Random")</span></td>' .
|
|
||||||
'</tr>' .
|
|
||||||
'<tr>' .
|
|
||||||
'<th><label for="subtitle">Subtitle</label></th>' .
|
|
||||||
'<td><input type="text" name="subtitle" id="subtitle" size="25" />' .
|
|
||||||
' <span class="unimportant">(optional)</span></td>' .
|
|
||||||
'</tr>' .
|
|
||||||
'<tr>' .
|
|
||||||
'<td></td>' .
|
|
||||||
'<td><input name="new_board" type="submit" value="New Board" /></td>' .
|
|
||||||
'</tr>' .
|
|
||||||
'</table>' .
|
|
||||||
'</form>' .
|
|
||||||
'</fieldset>';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function removeBan($id) {
|
|
||||||
global $config, $memcached;
|
|
||||||
|
|
||||||
$query = prepare("DELETE FROM `bans` WHERE `id` = :id");
|
|
||||||
$query->bindValue(':id', $id, PDO::PARAM_INT);
|
|
||||||
$query->execute() or error(db_error($query));
|
|
||||||
|
|
||||||
//if ($config['memcached']['enabled']) {
|
|
||||||
// Remove cached ban
|
|
||||||
// TODO
|
|
||||||
// $memcached->delete("ban_{$id}");
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Validate session
|
|
||||||
|
|
||||||
if (isset($_COOKIE[$config['cookies']['mod']])) {
|
|
||||||
// Should be username:hash:salt
|
|
||||||
$cookie = explode(':', $_COOKIE[$config['cookies']['mod']]);
|
|
||||||
if (count($cookie) != 3) {
|
|
||||||
destroyCookies();
|
|
||||||
error($config['error']['malformed']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$query = prepare("SELECT `id`, `type`, `boards`, `password` FROM `mods` WHERE `username` = :username LIMIT 1");
|
|
||||||
$query->bindValue(':username', $cookie[0]);
|
|
||||||
$query->execute() or error(db_error($query));
|
|
||||||
$user = $query->fetch();
|
|
||||||
|
|
||||||
// validate password hash
|
|
||||||
if ($cookie[1] != mkhash($cookie[0], $user['password'], $cookie[2])) {
|
|
||||||
// Malformed cookies
|
|
||||||
destroyCookies();
|
|
||||||
error($config['error']['malformed']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$mod = Array(
|
|
||||||
'id' => $user['id'],
|
|
||||||
'type' => $user['type'],
|
|
||||||
'username' => $cookie[0],
|
|
||||||
'boards' => explode(',', $user['boards'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
152
inc/mod/auth.php
Normal file
152
inc/mod/auth.php
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2012 Tinyboard Development Group
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
|
||||||
|
// You cannot request this file directly.
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a hash/salt pair for validate logins
|
||||||
|
function mkhash($username, $password, $salt = false) {
|
||||||
|
global $config;
|
||||||
|
|
||||||
|
if (!$salt) {
|
||||||
|
// create some sort of salt for the hash
|
||||||
|
$salt = substr(base64_encode(sha1(rand() . time(), true) . $config['cookies']['salt']), 0, 15);
|
||||||
|
|
||||||
|
$generated_salt = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate hash (method is not important as long as it's strong)
|
||||||
|
$hash = substr(base64_encode(md5($username . sha1($username . $password . $salt . ($config['mod']['lock_ip'] ? $_SERVER['REMOTE_ADDR'] : ''), true), true)), 0, 20);
|
||||||
|
|
||||||
|
if (isset($generated_salt))
|
||||||
|
return Array($hash, $salt);
|
||||||
|
else
|
||||||
|
return $hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
function login($username, $password, $makehash=true) {
|
||||||
|
global $mod;
|
||||||
|
|
||||||
|
// SHA1 password
|
||||||
|
if ($makehash) {
|
||||||
|
$password = sha1($password);
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = prepare("SELECT `id`,`type`,`boards` FROM `mods` WHERE `username` = :username AND `password` = :password LIMIT 1");
|
||||||
|
$query->bindValue(':username', $username);
|
||||||
|
$query->bindValue(':password', $password);
|
||||||
|
$query->execute() or error(db_error($query));
|
||||||
|
|
||||||
|
if ($user = $query->fetch()) {
|
||||||
|
return $mod = Array(
|
||||||
|
'id' => $user['id'],
|
||||||
|
'type' => $user['type'],
|
||||||
|
'username' => $username,
|
||||||
|
'hash' => mkhash($username, $password),
|
||||||
|
'boards' => explode(',', $user['boards'])
|
||||||
|
);
|
||||||
|
} else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCookies() {
|
||||||
|
global $mod, $config;
|
||||||
|
if (!$mod)
|
||||||
|
error('setCookies() was called for a non-moderator!');
|
||||||
|
|
||||||
|
setcookie($config['cookies']['mod'],
|
||||||
|
$mod['username'] . // username
|
||||||
|
':' .
|
||||||
|
$mod['hash'][0] . // password
|
||||||
|
':' .
|
||||||
|
$mod['hash'][1], // salt
|
||||||
|
time() + $config['cookies']['expire'], $config['cookies']['jail'] ? $config['cookies']['path'] : '/', null, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyCookies() {
|
||||||
|
global $config;
|
||||||
|
// Delete the cookies
|
||||||
|
setcookie($config['cookies']['mod'], 'deleted', time() - $config['cookies']['expire'], $config['cookies']['jail']?$config['cookies']['path'] : '/', null, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function modLog($action, $_board=null) {
|
||||||
|
global $mod, $board, $config;
|
||||||
|
$query = prepare("INSERT INTO `modlogs` VALUES (:id, :ip, :board, :time, :text)");
|
||||||
|
$query->bindValue(':id', $mod['id'], PDO::PARAM_INT);
|
||||||
|
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
|
||||||
|
$query->bindValue(':time', time(), PDO::PARAM_INT);
|
||||||
|
$query->bindValue(':text', $action);
|
||||||
|
if (isset($_board))
|
||||||
|
$query->bindValue(':board', $_board);
|
||||||
|
elseif (isset($board))
|
||||||
|
$query->bindValue(':board', $board['uri']);
|
||||||
|
else
|
||||||
|
$query->bindValue(':board', null, PDO::PARAM_NULL);
|
||||||
|
$query->execute() or error(db_error($query));
|
||||||
|
|
||||||
|
if ($config['syslog'])
|
||||||
|
_syslog(LOG_INFO, '[mod/' . $mod['username'] . ']: ' . $action);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate session
|
||||||
|
|
||||||
|
if (isset($_COOKIE[$config['cookies']['mod']])) {
|
||||||
|
// Should be username:hash:salt
|
||||||
|
$cookie = explode(':', $_COOKIE[$config['cookies']['mod']]);
|
||||||
|
if (count($cookie) != 3) {
|
||||||
|
destroyCookies();
|
||||||
|
error($config['error']['malformed']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = prepare("SELECT `id`, `type`, `boards`, `password` FROM `mods` WHERE `username` = :username LIMIT 1");
|
||||||
|
$query->bindValue(':username', $cookie[0]);
|
||||||
|
$query->execute() or error(db_error($query));
|
||||||
|
$user = $query->fetch();
|
||||||
|
|
||||||
|
// validate password hash
|
||||||
|
if ($cookie[1] != mkhash($cookie[0], $user['password'], $cookie[2])) {
|
||||||
|
// Malformed cookies
|
||||||
|
destroyCookies();
|
||||||
|
error($config['error']['malformed']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$mod = Array(
|
||||||
|
'id' => $user['id'],
|
||||||
|
'type' => $user['type'],
|
||||||
|
'username' => $cookie[0],
|
||||||
|
'boards' => explode(',', $user['boards'])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_pm_header() {
|
||||||
|
global $mod, $config;
|
||||||
|
|
||||||
|
if ($config['cache']['enabled'] && ($header = cache::get('pm_unread_' . $mod['id'])) !== false) {
|
||||||
|
if ($header === true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return $header;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = prepare("SELECT `id` FROM `pms` WHERE `to` = :id AND `unread` = 1");
|
||||||
|
$query->bindValue(':id', $mod['id'], PDO::PARAM_INT);
|
||||||
|
$query->execute() or error(db_error($query));
|
||||||
|
|
||||||
|
if ($pm = $query->fetch())
|
||||||
|
$header = Array('id' => $pm['id'], 'waiting' => $query->rowCount() - 1);
|
||||||
|
else
|
||||||
|
$header = true;
|
||||||
|
|
||||||
|
if ($config['cache']['enabled'])
|
||||||
|
cache::set('pm_unread_' . $mod['id'], $header);
|
||||||
|
|
||||||
|
if ($header === true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return $header;
|
||||||
|
}
|
||||||
|
|
95
inc/mod/ban.php
Normal file
95
inc/mod/ban.php
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2012 Tinyboard Development Group
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
|
||||||
|
// You cannot request this file directly.
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse_time($str) {
|
||||||
|
if (empty($str))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (($time = @strtotime($str)) !== false)
|
||||||
|
return $time;
|
||||||
|
|
||||||
|
if (!preg_match('/^((\d+)\s?ye?a?r?s?)?\s?+((\d+)\s?mon?t?h?s?)?\s?+((\d+)\s?we?e?k?s?)?\s?+((\d+)\s?da?y?s?)?((\d+)\s?ho?u?r?s?)?\s?+((\d+)\s?mi?n?u?t?e?s?)?\s?+((\d+)\s?se?c?o?n?d?s?)?$/', $str, $matches))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$expire = 0;
|
||||||
|
|
||||||
|
if (isset($matches[2])) {
|
||||||
|
// Years
|
||||||
|
$expire += $matches[2]*60*60*24*365;
|
||||||
|
}
|
||||||
|
if (isset($matches[4])) {
|
||||||
|
// Months
|
||||||
|
$expire += $matches[4]*60*60*24*30;
|
||||||
|
}
|
||||||
|
if (isset($matches[6])) {
|
||||||
|
// Weeks
|
||||||
|
$expire += $matches[6]*60*60*24*7;
|
||||||
|
}
|
||||||
|
if (isset($matches[8])) {
|
||||||
|
// Days
|
||||||
|
$expire += $matches[8]*60*60*24;
|
||||||
|
}
|
||||||
|
if (isset($matches[10])) {
|
||||||
|
// Hours
|
||||||
|
$expire += $matches[10]*60*60;
|
||||||
|
}
|
||||||
|
if (isset($matches[12])) {
|
||||||
|
// Minutes
|
||||||
|
$expire += $matches[12]*60;
|
||||||
|
}
|
||||||
|
if (isset($matches[14])) {
|
||||||
|
// Seconds
|
||||||
|
$expire += $matches[14];
|
||||||
|
}
|
||||||
|
|
||||||
|
return time() + $expire;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ban($mask, $reason, $length, $board) {
|
||||||
|
global $mod, $pdo;
|
||||||
|
|
||||||
|
$query = prepare("INSERT INTO `bans` VALUES (NULL, :ip, :mod, :time, :expires, :reason, :board)");
|
||||||
|
$query->bindValue(':ip', $mask);
|
||||||
|
$query->bindValue(':mod', $mod['id']);
|
||||||
|
$query->bindValue(':time', time());
|
||||||
|
if ($reason !== '') {
|
||||||
|
markup($reason);
|
||||||
|
$query->bindValue(':reason', $reason);
|
||||||
|
} else
|
||||||
|
$query->bindValue(':reason', null, PDO::PARAM_NULL);
|
||||||
|
|
||||||
|
if ($length > 0)
|
||||||
|
$query->bindValue(':expires', $length);
|
||||||
|
else
|
||||||
|
$query->bindValue(':expires', null, PDO::PARAM_NULL);
|
||||||
|
|
||||||
|
if ($board)
|
||||||
|
$query->bindValue(':board', $board);
|
||||||
|
else
|
||||||
|
$query->bindValue(':board', null, PDO::PARAM_NULL);
|
||||||
|
|
||||||
|
$query->execute() or error(db_error($query));
|
||||||
|
|
||||||
|
modLog('Created a new ' .
|
||||||
|
($length > 0 ? preg_replace('/^(\d+) (\w+?)s?$/', '$1-$2', until($length)) : 'permanent') .
|
||||||
|
' ban (<small>#' . $pdo->lastInsertId() . '</small>) for ' .
|
||||||
|
(filter_var($mask, FILTER_VALIDATE_IP) !== false ? "<a href=\"?/IP/$mask\">$mask</a>" : utf8tohtml($mask)) .
|
||||||
|
' with ' . ($reason ? 'reason: ' . utf8tohtml($reason) . '' : 'no reason'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function unban($id) {
|
||||||
|
$query = prepare("DELETE FROM `bans` WHERE `id` = :id");
|
||||||
|
$query->bindValue(':id', $id);
|
||||||
|
$query->execute() or error(db_error($query));
|
||||||
|
|
||||||
|
modLog("Removed ban #{$id}");
|
||||||
|
}
|
||||||
|
|
75
inc/mod/config-editor.php
Normal file
75
inc/mod/config-editor.php
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
function config_vars() {
|
||||||
|
global $config;
|
||||||
|
|
||||||
|
$config_file = file('inc/config.php', FILE_IGNORE_NEW_LINES);
|
||||||
|
$conf = array();
|
||||||
|
|
||||||
|
$var = array(
|
||||||
|
'name' => false,
|
||||||
|
'comment' => array(),
|
||||||
|
'default' => false,
|
||||||
|
'default_temp' => false
|
||||||
|
);
|
||||||
|
$temp_comment = false;
|
||||||
|
foreach ($config_file as $line) {
|
||||||
|
if ($temp_comment) {
|
||||||
|
$var['comment'][] = $temp_comment;
|
||||||
|
$temp_comment = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('!^\s*// (.*)$!', $line, $matches)) {
|
||||||
|
if ($var['default'] !== false) {
|
||||||
|
$line = '';
|
||||||
|
$temp_comment = $matches[1];
|
||||||
|
} else {
|
||||||
|
$var['comment'][] = $matches[1];
|
||||||
|
}
|
||||||
|
} else if ($var['default_temp'] !== false) {
|
||||||
|
$var['default_temp'] .= "\n" . $line;
|
||||||
|
} elseif (preg_match('!^\s*\$config\[(.+?)\] = (.+?)(;( //.+)?)?$!', $line, $matches)) {
|
||||||
|
$var['name'] = explode('][', $matches[1]);
|
||||||
|
if (count($var['name']) == 1) {
|
||||||
|
$var['name'] = preg_replace('/^\'(.*)\'$/', '$1', end($var['name']));
|
||||||
|
} else {
|
||||||
|
foreach ($var['name'] as &$i)
|
||||||
|
$i = preg_replace('/^\'(.*)\'$/', '$1', $i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($matches[3]))
|
||||||
|
$var['default'] = $matches[2];
|
||||||
|
else
|
||||||
|
$var['default_temp'] = $matches[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trim($line) === '') {
|
||||||
|
if ($var['name'] !== false) {
|
||||||
|
if ($var['default_temp'])
|
||||||
|
$var['default'] = $var['default_temp'];
|
||||||
|
|
||||||
|
$temp = eval('return ' . $var['default'] . ';');
|
||||||
|
if (!isset($temp))
|
||||||
|
$var['type'] = 'unknown';
|
||||||
|
else
|
||||||
|
$var['type'] = gettype($temp);
|
||||||
|
|
||||||
|
unset($var['default_temp']);
|
||||||
|
|
||||||
|
if (!is_array($var['name']) || (end($var['name']) != '' && !in_array(reset($var['name']), array('stylesheets')))) {
|
||||||
|
$conf[] = $var;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$var = array(
|
||||||
|
'name' => false,
|
||||||
|
'comment' => array(),
|
||||||
|
'default' => false,
|
||||||
|
'default_temp' => false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $conf;
|
||||||
|
}
|
||||||
|
|
1796
inc/mod/pages.php
Normal file
1796
inc/mod/pages.php
Normal file
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,7 @@ function load_twig() {
|
|||||||
$twig = new Twig_Environment($loader, array(
|
$twig = new Twig_Environment($loader, array(
|
||||||
'autoescape' => false,
|
'autoescape' => false,
|
||||||
'cache' => "{$config['dir']['template']}/cache",
|
'cache' => "{$config['dir']['template']}/cache",
|
||||||
'debug' => ($config['debug'] ? true : false),
|
'debug' => $config['debug']
|
||||||
));
|
));
|
||||||
$twig->addExtension(new Twig_Extensions_Extension_Tinyboard());
|
$twig->addExtension(new Twig_Extensions_Extension_Tinyboard());
|
||||||
$twig->addExtension(new Twig_Extensions_Extension_I18n());
|
$twig->addExtension(new Twig_Extensions_Extension_I18n());
|
||||||
@ -39,7 +39,7 @@ function Element($templateFile, array $options) {
|
|||||||
if (!$twig)
|
if (!$twig)
|
||||||
load_twig();
|
load_twig();
|
||||||
|
|
||||||
if (function_exists('create_pm_header') && ((isset($options['mod']) && $options['mod']) || isset($options['__mod']))) {
|
if (function_exists('create_pm_header') && ((isset($options['mod']) && $options['mod']) || isset($options['__mod'])) && !preg_match('!^mod/!', $templateFile)) {
|
||||||
$options['pm'] = create_pm_header();
|
$options['pm'] = create_pm_header();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Installation/upgrade file
|
// Installation/upgrade file
|
||||||
define('VERSION', 'v0.9.6-dev-4');
|
define('VERSION', 'v0.9.6-dev-5');
|
||||||
|
|
||||||
require 'inc/functions.php';
|
require 'inc/functions.php';
|
||||||
|
|
||||||
@ -210,6 +210,8 @@ if (file_exists($config['has_installed'])) {
|
|||||||
}
|
}
|
||||||
case 'v0.9.6-dev-3':
|
case 'v0.9.6-dev-3':
|
||||||
query("ALTER TABLE `antispam` CHANGE `hash` `hash` CHAR( 40 ) NOT NULL") or error(db_error());
|
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:
|
case false:
|
||||||
// Update version number
|
// Update version number
|
||||||
file_write($config['has_installed'], VERSION);
|
file_write($config['has_installed'], VERSION);
|
||||||
|
3128
mod-old.php
Normal file
3128
mod-old.php
Normal file
File diff suppressed because it is too large
Load Diff
30
post.php
30
post.php
@ -281,7 +281,7 @@ if (isset($_POST['delete'])) {
|
|||||||
|
|
||||||
$post['name'] = $_POST['name'] != '' ? $_POST['name'] : $config['anonymous'];
|
$post['name'] = $_POST['name'] != '' ? $_POST['name'] : $config['anonymous'];
|
||||||
$post['subject'] = $_POST['subject'];
|
$post['subject'] = $_POST['subject'];
|
||||||
$post['email'] = utf8tohtml($_POST['email']);
|
$post['email'] = str_replace(' ', '%20', htmlspecialchars($_POST['email']));
|
||||||
$post['body'] = $_POST['body'];
|
$post['body'] = $_POST['body'];
|
||||||
$post['password'] = $_POST['password'];
|
$post['password'] = $_POST['password'];
|
||||||
$post['has_file'] = !isset($post['embed']) && (($post['op'] && !isset($post['no_longer_require_an_image_for_op']) && $config['force_image_op']) || (isset($_FILES['file']) && $_FILES['file']['tmp_name'] != ''));
|
$post['has_file'] = !isset($post['embed']) && (($post['op'] && !isset($post['no_longer_require_an_image_for_op']) && $config['force_image_op']) || (isset($_FILES['file']) && $_FILES['file']['tmp_name'] != ''));
|
||||||
@ -313,13 +313,23 @@ if (isset($_POST['delete'])) {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($mod && $mod['type'] >= MOD && preg_match('/^((.+) )?## (.+)$/', $post['name'], $match)) {
|
|
||||||
if (($mod['type'] == MOD && $match[3] == 'Mod') || $mod['type'] >= ADMIN) {
|
|
||||||
$post['capcode'] = utf8tohtml($match[3]);
|
|
||||||
$post['name'] = $match[2] != '' ? $match[2] : $config['anonymous'];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$post['capcode'] = false;
|
$post['capcode'] = false;
|
||||||
|
|
||||||
|
if ($mod && preg_match('/^((.+) )?## (.+)$/', $post['name'], $matches)) {
|
||||||
|
$name = $matches[2] != '' ? $matches[2] : $config['anonymous'];
|
||||||
|
$cap = $matches[3];
|
||||||
|
|
||||||
|
if (isset($config['mod']['capcode'][$mod['type']])) {
|
||||||
|
if ( $config['mod']['capcode'][$mod['type']] === true ||
|
||||||
|
(is_array($config['mod']['capcode'][$mod['type']]) &&
|
||||||
|
in_array($cap, $config['mod']['capcode'][$mod['type']])
|
||||||
|
)) {
|
||||||
|
|
||||||
|
$post['capcode'] = utf8tohtml($cap);
|
||||||
|
$post['name'] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$trip = generate_tripcode($post['name']);
|
$trip = generate_tripcode($post['name']);
|
||||||
@ -527,7 +537,11 @@ if (isset($_POST['delete'])) {
|
|||||||
}
|
}
|
||||||
$post = (array)$post;
|
$post = (array)$post;
|
||||||
|
|
||||||
$id = post($post);
|
$post['id'] = $id = post($post);
|
||||||
|
|
||||||
|
if (isset($post['antispam_hash'])) {
|
||||||
|
incrementSpamHash($post['antispam_hash']);
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($post['antispam_hash'])) {
|
if (isset($post['antispam_hash'])) {
|
||||||
incrementSpamHash($post['antispam_hash']);
|
incrementSpamHash($post['antispam_hash']);
|
||||||
|
@ -70,15 +70,18 @@ form table input {
|
|||||||
}
|
}
|
||||||
input[type="text"], input[type="password"], textarea {
|
input[type="text"], input[type="password"], textarea {
|
||||||
border: 1px solid #a9a9a9;
|
border: 1px solid #a9a9a9;
|
||||||
text-indent: 0px;
|
text-indent: 0;
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
word-spacing: normal;
|
word-spacing: normal;
|
||||||
}
|
}
|
||||||
form table tr td {
|
form table tr td {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
margin: 0px;
|
margin: 0;
|
||||||
padding: 0px;
|
padding: 0;
|
||||||
|
}
|
||||||
|
form table.mod tr td {
|
||||||
|
padding: 2px;
|
||||||
}
|
}
|
||||||
form table tr th {
|
form table tr th {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@ -104,7 +107,7 @@ form table tr td div label {
|
|||||||
}
|
}
|
||||||
p.fileinfo {
|
p.fileinfo {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0px;
|
margin: 0;
|
||||||
padding-right: 7em;
|
padding-right: 7em;
|
||||||
}
|
}
|
||||||
div.banner {
|
div.banner {
|
||||||
@ -263,11 +266,11 @@ span.heading {
|
|||||||
color: #AF0A0F;
|
color: #AF0A0F;
|
||||||
font-size: 11pt;
|
font-size: 11pt;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
display: block;
|
|
||||||
}
|
}
|
||||||
span.spoiler {
|
span.spoiler {
|
||||||
background: black;
|
background: black;
|
||||||
color: black;
|
color: black;
|
||||||
|
padding: 0px 1px;
|
||||||
}
|
}
|
||||||
div.post.reply p.body span.spoiler a {
|
div.post.reply p.body span.spoiler a {
|
||||||
color: black;
|
color: black;
|
||||||
@ -328,7 +331,7 @@ div.pages form input {
|
|||||||
hr {
|
hr {
|
||||||
border: none;
|
border: none;
|
||||||
border-top: 1px solid #B7C5D9;
|
border-top: 1px solid #B7C5D9;
|
||||||
height: 0px;
|
height: 0;
|
||||||
clear: left;
|
clear: left;
|
||||||
}
|
}
|
||||||
div.boardlist {
|
div.boardlist {
|
||||||
@ -351,7 +354,7 @@ table.modlog {
|
|||||||
}
|
}
|
||||||
table.modlog tr td {
|
table.modlog tr td {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
margin: 0px;
|
margin: 0;
|
||||||
padding: 4px 15px 0 0;
|
padding: 4px 15px 0 0;
|
||||||
}
|
}
|
||||||
table.modlog tr th {
|
table.modlog tr th {
|
||||||
@ -385,19 +388,15 @@ div.blotter {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
table.mod.config-editor {
|
||||||
/* Uboachan stuff */
|
font-size: 9pt;
|
||||||
div.styles-sidebar {
|
width: 100%;
|
||||||
text-align: center;
|
|
||||||
padding-bottom: 0px;
|
|
||||||
}
|
}
|
||||||
div.styles-sidebar a {
|
table.mod.config-editor td {
|
||||||
margin: 0 5px;
|
text-align: left;
|
||||||
|
padding: 5px;
|
||||||
|
border-bottom: 1px solid #98e;
|
||||||
}
|
}
|
||||||
div.styles-sidebar a.selected {
|
table.mod.config-editor input[type="text"] {
|
||||||
text-decoration: none;
|
width: 98%;
|
||||||
}
|
|
||||||
.category {
|
|
||||||
background: #98E;
|
|
||||||
color: black;
|
|
||||||
}
|
}
|
||||||
|
71
templates/generic_page.html
Normal file
71
templates/generic_page.html
Normal 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 © 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>
|
@ -1,11 +1,11 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
<link rel="stylesheet" media="screen" href="{{ config.url_stylesheet }}">
|
<link rel="stylesheet" media="screen" href="{{ config.url_stylesheet }}">
|
||||||
{% if config.url_favicon %}<link rel="shortcut icon" href="{{ config.url_favicon }}">{% endif %}
|
{% if config.url_favicon %}<link rel="shortcut icon" href="{{ config.url_favicon }}">{% endif %}
|
||||||
<title>{{ board.url }} - {{ board.name }}</title>
|
<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, user-scalable=yes">
|
||||||
<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.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 config.default_stylesheet.1 != '' %}<link rel="stylesheet" type="text/css" id="stylesheet" href="{{ config.uri_stylesheets }}{{ config.default_stylesheet.1 }}">{% endif %}
|
||||||
{% if not nojavascript %}
|
{% if not nojavascript %}
|
||||||
@ -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 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 %}
|
{% 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>
|
<header>
|
||||||
<h1>{{ board.url }} - {{ board.name }}</h1>
|
<h1>{{ board.url }} - {{ board.title|e }}</h1>
|
||||||
<div class="subtitle">
|
<div class="subtitle">
|
||||||
{% if board.title %}
|
{% if board.subtitle %}
|
||||||
{{ board.title }}
|
{{ board.subtitle|e }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if mod %}<p><a href="?/">{% trans %}Return to dashboard{% endtrans %}</a></p>{% endif %}
|
{% if mod %}<p><a href="?/">{% trans %}Return to dashboard{% endtrans %}</a></p>{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
91
templates/mod/ban_form.html
Normal file
91
templates/mod/ban_form.html
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
{% if post and board %}
|
||||||
|
{% set action = '?/' ~ board ~ '/ban/' ~ post %}
|
||||||
|
{% else %}
|
||||||
|
{% set action = '?/ban' %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form action="{{ action }}" method="post">
|
||||||
|
{% if redirect %}
|
||||||
|
<input type="hidden" name="redirect" value="{{ redirect|e }}">
|
||||||
|
{% endif %}
|
||||||
|
{% if post and board %}
|
||||||
|
<input type="hidden" name="delete" value="{% if delete %}1{% else %}0{% endif %}">
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<table>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<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>{% trans 'hidden' %}</em>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<label for="reason">{% trans 'Reason' %}</label>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<textarea name="reason" id="reason" rows="5" cols="30">{{ reason|e }}</textarea>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% if post and board and not delete %}
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<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">({% trans 'public; attached to post' %})</span>
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.getElementById('message').disabled = true;
|
||||||
|
document.getElementById('public_message').onchange = function() {
|
||||||
|
document.getElementById('message').disabled = !this.checked;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<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>{% 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>{% trans 'all boards' %}</em>
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{% for board in boards %}
|
||||||
|
<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|e }}
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td><input name="new_ban" type="submit" value="{% trans 'New Ban' %}"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
|
95
templates/mod/ban_list.html
Normal file
95
templates/mod/ban_list.html
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
{% if bans|count == 0 %}
|
||||||
|
<p style="text-align:center" class="unimportant">({% trans 'There are no active bans.' %})</p>
|
||||||
|
{% else %}
|
||||||
|
<form action="" method="post">
|
||||||
|
<table class="mod" style="width:100%">
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'IP address/mask' %}</th>
|
||||||
|
<th>{% trans 'Reason' %}</th>
|
||||||
|
<th>{% trans 'Board' %}</th>
|
||||||
|
<th>{% trans 'Set' %}</th>
|
||||||
|
<th>{% trans 'Duration' %}</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 %}>
|
||||||
|
<td style="white-space: nowrap">
|
||||||
|
<input type="checkbox" name="ban_{{ ban.id }}">
|
||||||
|
{% if ban.real_ip %}
|
||||||
|
<a href="?/IP/{{ ban.ip }}">{{ ban.ip }}</a>
|
||||||
|
{% else %}
|
||||||
|
{{ ban.ip|e }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if ban.reason %}
|
||||||
|
{{ ban.reason }}
|
||||||
|
{% else %}
|
||||||
|
-
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td style="white-space: nowrap">
|
||||||
|
{% if ban.board %}
|
||||||
|
{{ config.board_abbreviation|sprintf(ban.board) }}
|
||||||
|
{% else %}
|
||||||
|
<em>{% trans 'all boards' %}</em>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td style="white-space: nowrap">
|
||||||
|
<span title="{{ ban.set|date(config.post_date) }}">
|
||||||
|
{{ ban.set|ago }} ago
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td style="white-space: nowrap">
|
||||||
|
{% if ban.expires == 0 %}
|
||||||
|
-
|
||||||
|
{% else %}
|
||||||
|
{{ (ban.expires - ban.set + time()) | until }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td style="white-space: nowrap">
|
||||||
|
{% if ban.expires == 0 %}
|
||||||
|
<em>{% trans 'never' %}</em>
|
||||||
|
{% else %}
|
||||||
|
{{ ban.expires|date(config.post_date) }}
|
||||||
|
{% if ban.expires > time() %}
|
||||||
|
<small>(in {{ ban.expires|until }})</small>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if ban.username %}
|
||||||
|
{% if mod|hasPermission(config.mod.view_banstaff) %}
|
||||||
|
<a href="?/new_PM/{{ ban.username|e }}">{{ ban.username|e }}</a>
|
||||||
|
{% else %}
|
||||||
|
{% if mod|hasPermission(config.mod.view_banquestionmark) %}
|
||||||
|
<em>?</em>
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% elseif ban.mod == -1 %}
|
||||||
|
<em>system</em>
|
||||||
|
{% else %}
|
||||||
|
<em>{% trans 'deleted?' %}</em>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p style="text-align:center">
|
||||||
|
<input type="submit" name="unban" value="{% trans 'Unban selected' %}">
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if count > bans|count %}
|
||||||
|
<p class="unimportant" style="text-align:center;word-wrap:break-word">
|
||||||
|
{% for i in range(0, (count - 1) / config.mod.modlog_page) %}
|
||||||
|
<a href="?/bans/{{ i + 1 }}">[{{ i + 1 }}]</a>
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
|
44
templates/mod/board.html
Normal file
44
templates/mod/board.html
Normal 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>
|
||||||
|
|
56
templates/mod/config-editor.html
Normal file
56
templates/mod/config-editor.html
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<form method="post" action="">
|
||||||
|
<table class="mod config-editor">
|
||||||
|
<tr>
|
||||||
|
<th class="minimal">Name</th>
|
||||||
|
<th>Value</th>
|
||||||
|
<th class="minimal">Type</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
{% for var in conf if var.type != 'array' %}
|
||||||
|
{% if var.name|count == 1 %}
|
||||||
|
{% set name = 'cf_' ~ var.name %}
|
||||||
|
{% else %}
|
||||||
|
{% set name = 'cf_' ~ var.name|join('/') %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="minimal">
|
||||||
|
{% if var.name|count == 1 %}
|
||||||
|
{{ var.name }}
|
||||||
|
{% else %}
|
||||||
|
{{ var.name|join(' → ') }}
|
||||||
|
{% endif %}
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
{% if var.type == 'string' %}
|
||||||
|
<input name="{{ name }}" type="text" value="{{ var.value|e }}">
|
||||||
|
{% elseif var.type == 'integer' %}
|
||||||
|
<input name="{{ name }}" type="number" value="{{ var.value|e }}">
|
||||||
|
{% elseif var.type == 'boolean' %}
|
||||||
|
<input name="{{ name }}" type="checkbox" {% if var.value %}checked{% endif %}>
|
||||||
|
{% else %}
|
||||||
|
?
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if var.type == 'integer' or var.type == 'boolean' %}
|
||||||
|
<small>Default: <code>{{ var.default }}</code></small>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="minimal">
|
||||||
|
{{ var.type|e }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
{{ var.comment|join('<br>') }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<ul style="padding:0;text-align:center;list-style:none">
|
||||||
|
<li><input name="save" type="submit" value="{% trans 'Save changes' %}"></li>
|
||||||
|
</ul>
|
||||||
|
</form>
|
||||||
|
|
7
templates/mod/confirm.html
Normal file
7
templates/mod/confirm.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<p style="text-align:center;font-size:1.1em">
|
||||||
|
{% 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">
|
||||||
|
{% trans 'You are seeing this message because we were unable to serve a confirmation dialog, probably due to Javascript being disabled.' %}
|
||||||
|
</p>
|
||||||
|
|
139
templates/mod/dashboard.html
Normal file
139
templates/mod/dashboard.html
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
<fieldset>
|
||||||
|
<legend>{% trans 'Boards' %}</legend>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for board in boards %}
|
||||||
|
<li>
|
||||||
|
<a href="?/{{ config.board_path|sprintf(board.uri) }}{{ config.file_index }}">{{ config.board_abbreviation|sprintf(board.uri) }}</a>
|
||||||
|
-
|
||||||
|
{{ board.title|e }}
|
||||||
|
{% if board.subtitle %}
|
||||||
|
<small>— {{ board.subtitle|e }}</small>
|
||||||
|
{% endif %}
|
||||||
|
{% if mod|hasPermission(config.mod.manageboards) %}
|
||||||
|
<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>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>{% trans 'Messages' %}</legend>
|
||||||
|
<ul>
|
||||||
|
{% if mod|hasPermission(config.mod.noticeboard) %}
|
||||||
|
{% if noticeboard|count > 0 %}
|
||||||
|
<li>
|
||||||
|
{% trans 'Noticeboard' %}:
|
||||||
|
<ul>
|
||||||
|
{% for post in noticeboard %}
|
||||||
|
<li>
|
||||||
|
<a href="?/noticeboard#{{ post.id }}">
|
||||||
|
{% if post.subject %}
|
||||||
|
{{ post.subject|e }}
|
||||||
|
{% else %}
|
||||||
|
<em>{% trans 'no subject' %}</em>
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
<small class="unimportant">
|
||||||
|
— by
|
||||||
|
{% if post.username %}
|
||||||
|
{{ post.username|e }}
|
||||||
|
{% else %}
|
||||||
|
<em>deleted?</em>
|
||||||
|
{% endif %}
|
||||||
|
at
|
||||||
|
{{ post.time|date(config.post_date) }}
|
||||||
|
</small>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
<li><a href="?/noticeboard">{% trans 'View all entries' %}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
<li><a href="?/news">{% trans 'News' %}</a></li>
|
||||||
|
<li>
|
||||||
|
<a href="?/inbox">
|
||||||
|
{% trans 'PM inbox' %}
|
||||||
|
{% if unread_pms > 0 %}<strong>{%endif %}({{ unread_pms }} unread){% if unread_pms > 0 %}</strong>{%endif %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>{% trans 'Administration' %}</legend>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% if mod|hasPermission(config.mod.reports) %}
|
||||||
|
<li>
|
||||||
|
{% if reports > 0 %}<strong>{% endif %}
|
||||||
|
<a href="?/reports">{% trans 'Report queue' %} ({{ reports }})</a>
|
||||||
|
{% if reports > 0 %}</strong>{% endif %}
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if mod|hasPermission(config.mod.view_banlist) %}
|
||||||
|
<li><a href="?/bans">{% trans 'Ban list' %}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if mod|hasPermission(config.mod.manageusers) %}
|
||||||
|
<li><a href="?/users">{% trans 'Manage users' %}</a></li>
|
||||||
|
{% elseif mod|hasPermission(config.mod.change_password) %}
|
||||||
|
<li><a href="?/users/{{ mod.id }}">{% trans 'Change password' %}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if mod|hasPermission(config.mod.themes) %}
|
||||||
|
<li><a href="?/themes">{% trans 'Manage themes' %}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if mod|hasPermission(config.mod.modlog) %}
|
||||||
|
<li><a href="?/log">{% trans 'Moderation log' %}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if mod|hasPermission(config.mod.rebuild) %}
|
||||||
|
<li><a href="?/rebuild">{% trans 'Rebuild' %}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if mod|hasPermission(config.mod.show_config) %}
|
||||||
|
<li><a href="?/config">{% trans 'Configuration' %}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>{% trans 'Search' %}</legend>
|
||||||
|
|
||||||
|
{# TODO #}
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
{% if config.debug %}
|
||||||
|
<fieldset>
|
||||||
|
<legend>{% trans 'Debug' %}</legend>
|
||||||
|
<ul>
|
||||||
|
<li><a href="?/debug/antispam">{% trans 'Anti-spam' %}</a></li>
|
||||||
|
</ul>
|
||||||
|
</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>
|
||||||
|
|
65
templates/mod/debug/antispam.html
Normal file
65
templates/mod/debug/antispam.html
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<p style="text-align:center">
|
||||||
|
Most used (in active):
|
||||||
|
</p>
|
||||||
|
<table class="modlog" style="width:700px;margin:auto">
|
||||||
|
<tr>
|
||||||
|
<th>Board</th>
|
||||||
|
<th>Thread</th>
|
||||||
|
<th>Hash (SHA1)</th>
|
||||||
|
<th>Created</th>
|
||||||
|
<th>Expires</th>
|
||||||
|
<th>Passed</th>
|
||||||
|
</tr>
|
||||||
|
{% for hash in top %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ config.board_abbreviation|sprintf(hash.board) }}</td>
|
||||||
|
<td>
|
||||||
|
{% if hash.thread %}
|
||||||
|
{{ hash.thread }}
|
||||||
|
{% else %}
|
||||||
|
-
|
||||||
|
{% endif %}</td>
|
||||||
|
<td>
|
||||||
|
<small><code>{{ hash.hash }}</code></small>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span title="{{ hash.created|date(config.post_date) }}">{{ hash.created|ago }} ago</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if hash.expires %}
|
||||||
|
<span title="{{ hash.expires|date(config.post_date) }}">
|
||||||
|
{{ hash.expires|until }}
|
||||||
|
</span>
|
||||||
|
{% else %}
|
||||||
|
-
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>{{ hash.passed }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
<p style="text-align:center">
|
||||||
|
Total: <strong>{{ total }}</strong> (<strong>{{ expiring }}</strong> set to expire)
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form method="post" action="?/debug/antispam">
|
||||||
|
<table class="modlog" style="width:1%;white-space:nowrap;margin:auto">
|
||||||
|
<tr>
|
||||||
|
<th>Board</th>
|
||||||
|
<th>Thread</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="board" style="width:90px" value="{{ board }}">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="thread" style="width:90px" value="{{ thread }}">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="submit" name="filter" value="Filter">
|
||||||
|
<input type="submit" name="purge" value="Purge">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
36
templates/mod/inbox.html
Normal file
36
templates/mod/inbox.html
Normal 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 %}
|
47
templates/mod/log.html
Normal file
47
templates/mod/log.html
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<table class="modlog">
|
||||||
|
<tr>
|
||||||
|
<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">
|
||||||
|
{% 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>
|
||||||
|
</td>
|
||||||
|
<td class="minimal">
|
||||||
|
<span title="{{ log.time|date(config.post_date) }}">{{ log.time|ago }}</span>
|
||||||
|
</td>
|
||||||
|
<td class="minimal">
|
||||||
|
{% if log.board %}
|
||||||
|
<a href="?/{{ config.board_path|sprintf(log.board) }}{{ config.file_index }}">{{ config.board_abbreviation|sprintf(log.board) }}</a>
|
||||||
|
{% else %}
|
||||||
|
-
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ log.text }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% if count > logs|count %}
|
||||||
|
<p class="unimportant" style="text-align:center;word-wrap:break-word">
|
||||||
|
{% for i in range(0, (count - 1) / config.mod.modlog_page) %}
|
||||||
|
<a href="?/log/{{ i + 1 }}">[{{ i + 1 }}]</a>
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
|
@ -1,18 +1,17 @@
|
|||||||
{% if error %}<h2 style="text-align:center">{{ error }}</h2>{% endif %}
|
{% if error %}<h2 style="text-align:center">{{ error }}</h2>{% endif %}
|
||||||
<form action="" method="post">
|
<form action="" method="post">
|
||||||
{% if redirect %}<input type="hidden" name="redirect" value="{{ redirect }}" />{% endif %}
|
|
||||||
<table style="margin-top:25px;">
|
<table style="margin-top:25px;">
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
{% trans %}Username{% endtrans %}
|
{% trans 'Username' %}
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="username" size="20" maxlength="30" value="{{ username }}">
|
<input type="text" name="username" size="20" maxlength="30" value="{{ username|e }}">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
{% trans %}Password{% endtrans %}
|
{% trans 'Password' %}
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="password" name="password" size="20" maxlength="30" value="">
|
<input type="password" name="password" size="20" maxlength="30" value="">
|
41
templates/mod/move.html
Normal file
41
templates/mod/move.html
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<form action="?/{{ board }}/move/{{ post }}" method="post">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
{% trans 'Thread ID' %}
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
>>>{{ config.board_abbreviation|sprintf(board) }}{{ post }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
{% trans 'Leave shadow thread' %}
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<input type="checkbox" name="shadow" checked>
|
||||||
|
<span class="unimportant">({% trans 'locks thread; replies to it with a link.' %})</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Target board' %}</th>
|
||||||
|
<td>
|
||||||
|
<ul style="list-style:none;padding:0">
|
||||||
|
{% for targetboard in boards if targetboard.uri != board %}
|
||||||
|
<li>
|
||||||
|
<input type="radio" name="board" value="{{ targetboard.uri }}" id="ban-board-{{ targetboard.uri }}">
|
||||||
|
<label style="display:inline" for="ban-board-{{ targetboard.uri }}">
|
||||||
|
{{ config.board_abbreviation|sprintf(targetboard.uri) }} - {{ targetboard.title|e }}
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<ul style="padding:0;text-align:center;list-style:none">
|
||||||
|
<li><input type="submit" value="{% trans 'Move thread' %}"></li>
|
||||||
|
</ul>
|
||||||
|
</form>
|
||||||
|
|
18
templates/mod/new_pm.html
Normal file
18
templates/mod/new_pm.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<form action="?/new_PM/{{ username|e }}" method="post">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>To</th>
|
||||||
|
{% if mod|hasPermission(config.mod.editusers) %}
|
||||||
|
<td><a href="?/users/{{ id }}">{{ username|e }}</a></td>
|
||||||
|
{% else %}
|
||||||
|
<td>{{ username|e }}</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Message</th>
|
||||||
|
<td><textarea name="message" rows="10" cols="40">{{ message }}</textarea></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p style="text-align:center"><input type="submit" value="{% trans 'Send message' %}"></p>
|
||||||
|
</form>
|
70
templates/mod/news.html
Normal file
70
templates/mod/news.html
Normal 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">
|
||||||
|
— {% 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 %}
|
65
templates/mod/noticeboard.html
Normal file
65
templates/mod/noticeboard.html
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
{% if mod|hasPermission(config.mod.noticeboard_post) %}
|
||||||
|
<fieldset>
|
||||||
|
<legend>{% trans 'New post' %}</legend>
|
||||||
|
<form style="margin:0" action="" method="post">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Name' %}</th>
|
||||||
|
<td>{{ mod.username|e }}</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>{% trans 'Body' %}</th>
|
||||||
|
<td><textarea name="body" style="width:100%;height:100px"></textarea></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p style="text-align:center">
|
||||||
|
<input type="submit" value="{% trans 'Post to noticeboard' %}" />
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</fieldset>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for post in noticeboard %}
|
||||||
|
<div class="ban">
|
||||||
|
{% if mod|hasPermission(config.mod.noticeboard_delete) %}
|
||||||
|
<span style="float:right;padding:2px">
|
||||||
|
<a class="unimportant" href="?/noticeboard/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">
|
||||||
|
— {% trans 'by' %}
|
||||||
|
{% if post.username %}
|
||||||
|
{{ post.username|e }}
|
||||||
|
{% else %}
|
||||||
|
<em>{% trans 'deleted?' %}</em>
|
||||||
|
{% endif %}
|
||||||
|
{% trans 'at' %}
|
||||||
|
{{ post.time|date(config.post_date) }}
|
||||||
|
</small>
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
{{ post.body }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if count > noticeboard|count %}
|
||||||
|
<p class="unimportant" style="text-align:center;word-wrap:break-word">
|
||||||
|
{% for i in range(0, (count - 1) / config.mod.noticeboard_page) %}
|
||||||
|
<a href="?/noticeboard/{{ i + 1 }}">[{{ i + 1 }}]</a>
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
44
templates/mod/pm.html
Normal file
44
templates/mod/pm.html
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<form action="" method="post">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'From' %}</th>
|
||||||
|
{% if username %}
|
||||||
|
<td><a href="?/new_PM/{{ username|e }}">{{ username|e }}</a></td>
|
||||||
|
{% else %}
|
||||||
|
<td><em>{% trans 'deleted?' %}</em></td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% if to != mod.id %}
|
||||||
|
<tr>
|
||||||
|
<th>To</th>
|
||||||
|
{% if to_username %}
|
||||||
|
<td><a href="?/new_PM/{{ to_username|e }}">{{ to_username|e }}</a></td>
|
||||||
|
{% else %}
|
||||||
|
<td><em>{% trans 'deleted?' %}</em></td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Date' %}</th>
|
||||||
|
<td>{{ time|date(config.post_date) }} <small>({{ time|ago }} ago)</small></td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<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="{% trans 'Delete forever' %}">
|
||||||
|
</li>
|
||||||
|
{% if mod|hasPermission(config.mod.create_pm) %}
|
||||||
|
<li style="padding:5px 0">
|
||||||
|
<a href="?/PM/{{ id }}/reply">
|
||||||
|
{% trans 'Reply with quote' %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</form>
|
71
templates/mod/rebuild.html
Normal file
71
templates/mod/rebuild.html
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<form style="width:300px;margin:auto" action="?/rebuild" method="post">
|
||||||
|
<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>{% trans 'Toggle all' %}</strong></label>
|
||||||
|
<script>
|
||||||
|
function toggleall(val) {
|
||||||
|
/* TODO: something more suitable for all browsers? */
|
||||||
|
var elements = document.getElementById('rebuild').querySelectorAll('input');
|
||||||
|
for (i in elements) {
|
||||||
|
elements[i].checked = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input type="checkbox" name="rebuild_cache" id="rebuild_cache" checked>
|
||||||
|
<label for="rebuild_cache">{% trans 'Flush cache' %}</label>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input type="checkbox" name="rebuild_javascript" id="rebuild_javascript" checked>
|
||||||
|
<label for="rebuild_javascript">{% trans 'Rebuild Javascript' %}</label>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input type="checkbox" name="rebuild_index" id="rebuild_index" checked>
|
||||||
|
<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">{% trans 'Rebuild thread pages' %}</label>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input type="checkbox" name="rebuild_themes" id="rebuild_themes" checked>
|
||||||
|
<label for="rebuild_themes">{% trans 'Rebuild themes' %}</label>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input type="checkbox" name="rebuild_posts" id="rebuild_posts">
|
||||||
|
<label for="rebuild_posts">{% trans 'Rebuild replies' %}</label>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<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>{% trans 'All boards' %}</strong></label>
|
||||||
|
<script>
|
||||||
|
function toggleallboards(val) {
|
||||||
|
/* TODO: something more suitable for all browsers? */
|
||||||
|
var elements = document.getElementById('boards').querySelectorAll('input');
|
||||||
|
for (i in elements) {
|
||||||
|
elements[i].checked = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</li>
|
||||||
|
{% for board in boards %}
|
||||||
|
<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|e }}
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p style="text-align:center">
|
||||||
|
<input type="submit" value="{% trans 'Rebuild' %}" name="rebuild">
|
||||||
|
</p>
|
||||||
|
</form>
|
12
templates/mod/rebuilt.html
Normal file
12
templates/mod/rebuilt.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<div class="ban">
|
||||||
|
<h2>{% trans 'Rebuilt' %}</h2>
|
||||||
|
<ul>
|
||||||
|
{% for log in logs %}
|
||||||
|
<li>{{ log }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
<a href="?/rebuild">{% trans 'Go back and rebuild again' %}</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
26
templates/mod/report.html
Normal file
26
templates/mod/report.html
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<div class="report">
|
||||||
|
<hr>
|
||||||
|
{% trans 'Board' %}: <a href="?/{{ report.board }}/{{ config.file_index }}">{{ config.board_abbreviation|sprintf(report.board) }}</a>
|
||||||
|
<br>
|
||||||
|
{% trans 'Reason' %}: {{ report.reason }}
|
||||||
|
<br>
|
||||||
|
{% trans 'Report date' %}: {{ report.time|date(config.post_date) }}
|
||||||
|
<br>
|
||||||
|
{% if mod|hasPermission(config.mod.show_ip, report.board) %}
|
||||||
|
{% 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="{% 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="{% trans 'Discard all abuse reports by this IP address' %}" href="?/reports/{{ report.id }}/dismissall">Dismiss+</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
6
templates/mod/reports.html
Normal file
6
templates/mod/reports.html
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{% if reports %}
|
||||||
|
{{ reports }}
|
||||||
|
{% else %}
|
||||||
|
<p style="text-align:center" class="unimportant">({% trans 'There are no reports.' %})</p>
|
||||||
|
{% endif %}
|
||||||
|
|
27
templates/mod/theme_config.html
Normal file
27
templates/mod/theme_config.html
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<form action="" method="post">
|
||||||
|
{% if not config %}
|
||||||
|
<p style="text-align:center" class="unimportant">(No configuration required.)</p>
|
||||||
|
{% else %}
|
||||||
|
<table>
|
||||||
|
{% for conf in theme.config %}
|
||||||
|
<tr>
|
||||||
|
<th>{{ conf.title }}</th>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="{{ conf.name }}"
|
||||||
|
{% if settings[conf.name] %}value="{{ settings[conf.name] }}"{% else %}{% if conf.default %}value="{{ conf.default }}"{% endif %}{% endif %}
|
||||||
|
{% if conf.size %}
|
||||||
|
size="{{ conf.size }}"
|
||||||
|
{% endif %}
|
||||||
|
/>
|
||||||
|
{% if conf.comment %}
|
||||||
|
<span class="unimportant">{{ conf.comment }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
<p style="text-align:center">
|
||||||
|
<input name="install" type="submit" value="{% trans 'Install theme' %}" />
|
||||||
|
</p>
|
||||||
|
</form>
|
9
templates/mod/theme_installed.html
Normal file
9
templates/mod/theme_installed.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% if message %}
|
||||||
|
<div style="border:1px dashed maroon;padding:20px;margin:auto;max-width:800px">{{ message }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if result %}
|
||||||
|
<p style="text-align:center">{% trans 'Successfully installed and built theme.' %}</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<p style="text-align:center"><a href="?/themes">{% trans 'Go back to themes' %}</a>.</p>
|
2
templates/mod/theme_rebuilt.html
Normal file
2
templates/mod/theme_rebuilt.html
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<p style="text-align:center">{{ 'Successfully rebuilt the <strong>%s</strong> theme.'|trans|sprintf(theme_name) }}</p>
|
||||||
|
<p style="text-align:center"><a href="?/themes">{% trans 'Go back to themes' %}</a>.</p>
|
40
templates/mod/themes.html
Normal file
40
templates/mod/themes.html
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{% if themes|count == 0 %}
|
||||||
|
<p style="text-align:center" class="unimportant">({% trans 'There are no themes available.' %})</p>
|
||||||
|
{% else %}
|
||||||
|
<table class="modlog">
|
||||||
|
{% for theme_name, theme in themes %}
|
||||||
|
<tr>
|
||||||
|
<th class="minimal">{% trans 'Name' %}</th>
|
||||||
|
<td>{{ theme.name }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="minimal">{% trans 'Version' %}</th>
|
||||||
|
<td>{{ theme.version }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="minimal">{% trans 'Description' %}</th>
|
||||||
|
<td>{{ theme.description }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="minimal">{% trans 'Thumbnail' %}</th>
|
||||||
|
<td>
|
||||||
|
<img style="float:none;margin:4px{% if theme_name in themes_in_use %};border:2px solid red;padding:4px{% endif %}" src="{{ config.dir.themes_uri }}/{{ theme_name }}/thumb.png" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="minimal">{% trans 'Actions' %}</th>
|
||||||
|
<td><ul style="padding:0 20px">
|
||||||
|
<li><a title=" {% trans 'Use theme' %}" href="?/themes/{{ theme_name }}">
|
||||||
|
{% if theme_name in themes_in_use %}{% trans 'Reconfigure' %}{% else %}{% trans 'Install' %}{% endif %}
|
||||||
|
</a></li>
|
||||||
|
{% if theme_name in themes_in_use %}
|
||||||
|
<li><a href="?/themes/{{ theme_name }}/rebuild">{% trans 'Rebuild' %}</a></li>
|
||||||
|
<li><a href="?/themes/{{ theme_name }}/uninstall" onclick="return confirm('Are you sure you want to uninstall this theme?');">{% trans 'Uninstall' %}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul></td>
|
||||||
|
</tr>
|
||||||
|
<tr style="height:40px"><td colspan="2"><hr/></td></tr>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
125
templates/mod/user.html
Normal file
125
templates/mod/user.html
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
{% if new %}
|
||||||
|
{% set action = '?/users/new' %}
|
||||||
|
{% else %}
|
||||||
|
{% set action = '?/users/' ~ user.id %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form action="{{ action }}" method="post">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Username' %}</th>
|
||||||
|
<td>
|
||||||
|
{% 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 }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Password' %}{% if not new %} <small style="font-weight:normal">({% trans 'new; optional' %})</small>{% endif %}</th>
|
||||||
|
<td>
|
||||||
|
{% 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>{% trans 'Boards' %}</th>
|
||||||
|
<td>
|
||||||
|
<ul style="padding:0 5px;list-style:none">
|
||||||
|
<li>
|
||||||
|
<input type="checkbox" id="allboards" name="allboards"
|
||||||
|
{% if '*' in user.boards %} checked{% endif %}
|
||||||
|
{% if not mod|hasPermission(config.mod.editusers) %}
|
||||||
|
disabled
|
||||||
|
{% endif %}
|
||||||
|
>
|
||||||
|
<label for="allboards">"*" - {% trans 'All boards' %}</label>
|
||||||
|
</li>
|
||||||
|
{% for board in boards %}
|
||||||
|
<li>
|
||||||
|
<input type="checkbox" id="board_{{ board.uri }}" name="board_{{ board.uri }}"
|
||||||
|
{% if board.uri in user.boards %} checked{% endif %}
|
||||||
|
{% if not mod|hasPermission(config.mod.editusers) %}
|
||||||
|
disabled
|
||||||
|
{% endif %}
|
||||||
|
>
|
||||||
|
<label for="board_{{ board.uri }}">
|
||||||
|
{{ config.board_abbreviation|sprintf(board.uri) }}
|
||||||
|
-
|
||||||
|
{{ board.title|e }}
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
{% if logs|count > 0 %}
|
||||||
|
<table class="modlog" style="width:600px">
|
||||||
|
<tr>
|
||||||
|
<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="?/IP/{{ log.ip }}">{{ log.ip }}</a>
|
||||||
|
</td>
|
||||||
|
<td class="minimal">
|
||||||
|
<span title="{{ log.time|date(config.post_date) }}">{{ log.time|ago }}</span>
|
||||||
|
</td>
|
||||||
|
<td class="minimal">
|
||||||
|
{% if log.board %}
|
||||||
|
<a href="?/{{ config.board_path|sprintf(log.board) }}{{ config.file_index }}">{{ config.board_abbreviation|sprintf(log.board) }}</a>
|
||||||
|
{% else %}
|
||||||
|
-
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ log.text }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
|
71
templates/mod/users.html
Normal file
71
templates/mod/users.html
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<table class="modlog" style="width:auto">
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'ID' %}</th>
|
||||||
|
<th>{% trans 'Username' %}</th>
|
||||||
|
<th>{% trans 'Type' %}</th>
|
||||||
|
<th>{% trans 'Boards' %}</th>
|
||||||
|
{% if mod|hasPermission(config.mod.modlog) %}
|
||||||
|
<th>{% trans 'Last action' %}</th>
|
||||||
|
{% endif %}
|
||||||
|
<th>…</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% for user in users %}
|
||||||
|
<tr>
|
||||||
|
<td><small>{{ user.id }}</small></td>
|
||||||
|
<td>{{ user.username|e }}</td>
|
||||||
|
<td>
|
||||||
|
{% if user.type == constant('JANITOR') %}{% trans 'Janitor' %}
|
||||||
|
{% elseif user.type == constant('MOD') %}{% trans 'Mod' %}
|
||||||
|
{% elseif user.type == constant('ADMIN') %}{% trans 'Admin' %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% 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>
|
||||||
|
{% if mod|hasPermission(config.mod.modlog) %}
|
||||||
|
<td>
|
||||||
|
{% if user.last %}
|
||||||
|
<span title="{{ user.action|e }}">{{ user.last|ago }}</span>
|
||||||
|
{% else %}
|
||||||
|
<em>{% trans 'never' %}</em>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
<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="{% trans 'Promote' %}">▲</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="{% trans 'Demote' %}">▼</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if mod|hasPermission(config.mod.editusers) or (mod|hasPermission(config.mod.change_password) and mod.id == user.id) %}
|
||||||
|
<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|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 %}
|
||||||
|
|
163
templates/mod/view_ip.html
Normal file
163
templates/mod/view_ip.html
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
{% for board_posts in posts %}
|
||||||
|
<fieldset>
|
||||||
|
<legend>
|
||||||
|
<a href="?/{{ config.board_path|sprintf(board_posts.board.uri) }}{{ config.file_index }}">
|
||||||
|
{{ config.board_abbreviation|sprintf(board_posts.board.uri) }}
|
||||||
|
-
|
||||||
|
{{ board_posts.board.title|e }}
|
||||||
|
</a>
|
||||||
|
</legend>
|
||||||
|
{{ board_posts.posts|join('<hr>') }}
|
||||||
|
</fieldset>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if mod|hasPermission(config.mod.view_notes) %}
|
||||||
|
<fieldset id="notes">
|
||||||
|
<legend>
|
||||||
|
{% 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>{% trans 'Staff' %}</th>
|
||||||
|
<th>{% trans 'Note' %}</th>
|
||||||
|
<th>{% trans 'Date' %}</th>
|
||||||
|
{% if mod|hasPermission(config.mod.remove_notes) %}
|
||||||
|
<th>{% trans 'Actions' %}</th>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% for note in notes %}
|
||||||
|
<tr>
|
||||||
|
<td class="minimal">
|
||||||
|
{% if note.username %}
|
||||||
|
<a href="?/new_PM/{{ note.username|e }}">{{ note.username|e }}</a>
|
||||||
|
{% else %}
|
||||||
|
<em>{% trans 'deleted?' %}</em>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ note.body }}
|
||||||
|
</td>
|
||||||
|
<td class="minimal">
|
||||||
|
{{ note.time|date(config.post_date) }}
|
||||||
|
</td>
|
||||||
|
{% if mod|hasPermission(config.mod.remove_notes) %}
|
||||||
|
<td class="minimal">
|
||||||
|
<a href="?/IP/{{ ip }}/remove_note/{{ note.id }}">
|
||||||
|
<small>[{% trans 'remove' %}]</small>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if mod|hasPermission(config.mod.create_notes) %}
|
||||||
|
<form action="" method="post" style="margin:0">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Staff' %}</th>
|
||||||
|
<td>{{ mod.username|e }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<label for="note">{% trans 'Note' %}</label>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<textarea id="note" name="note" rows="5" cols="30"></textarea>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td><input type="submit" value="{% trans 'New note' %}"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</fieldset>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if bans|count > 0 and mod|hasPermission(config.mod.view_ban) %}
|
||||||
|
<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>{% trans 'Status' %}</th>
|
||||||
|
<td>
|
||||||
|
{% if config.mod.view_banexpired and ban.expires != 0 and ban.expires < time() %}
|
||||||
|
{% trans 'Expired' %}
|
||||||
|
{% else %}
|
||||||
|
{% trans 'Active' %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'IP' %}</th>
|
||||||
|
<td>{{ ban.ip }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Reason' %}</th>
|
||||||
|
<td>
|
||||||
|
{% if ban.reason %}
|
||||||
|
{{ ban.reason }}
|
||||||
|
{% else %}
|
||||||
|
<em>{% trans 'no reason' %}</em>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Board' %}</th>
|
||||||
|
<td>
|
||||||
|
{% if ban.board %}
|
||||||
|
{{ config.board_abbreviation|sprintf(ban.board) }}
|
||||||
|
{% else %}
|
||||||
|
<em>{% trans 'all boards' %}</em>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Set' %}</th>
|
||||||
|
<td>{{ ban.set|date(config.post_date) }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Expires' %}</th>
|
||||||
|
<td>
|
||||||
|
{% if ban.expires %}
|
||||||
|
{{ ban.expires|date(config.post_date) }}
|
||||||
|
{% else %}
|
||||||
|
<em>{% trans 'never' %}</em>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Staff' %}</th>
|
||||||
|
<td>
|
||||||
|
{% if ban.username %}
|
||||||
|
{{ ban.username|e }}
|
||||||
|
{% else %}
|
||||||
|
<em>{% trans 'deleted?' %}</em>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<input type="hidden" name="ban_id" value="{{ ban.id }}">
|
||||||
|
<input type="submit" name="unban" value="{% trans 'Remove ban' %}">
|
||||||
|
</form>
|
||||||
|
{% endfor %}
|
||||||
|
</fieldset>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if mod|hasPermission(config.mod.ban) %}
|
||||||
|
<fieldset>
|
||||||
|
<legend>{% trans 'New ban' %}</legend>
|
||||||
|
{% set redirect = '?/IP/' ~ ip ~ '#bans' %}
|
||||||
|
{% include 'mod/ban_form.html' %}
|
||||||
|
</fieldset>
|
||||||
|
{% endif %}
|
@ -1,11 +1,11 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
<link rel="stylesheet" media="screen" href="{{ config.url_stylesheet }}">
|
<link rel="stylesheet" media="screen" href="{{ config.url_stylesheet }}">
|
||||||
{% if config.url_favicon %}<link rel="shortcut icon" href="{{ config.url_favicon }}">{% endif %}
|
{% if config.url_favicon %}<link rel="shortcut icon" href="{{ config.url_favicon }}">{% endif %}
|
||||||
<title>{{ title }}</title>
|
<title>{{ title }}</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-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 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 %}
|
{% if not nojavascript %}<script type="text/javascript" src="{{ config.url_javascript }}"></script>{% endif %}
|
||||||
</head>
|
</head>
|
||||||
@ -17,7 +17,7 @@
|
|||||||
{% if subtitle %}
|
{% if subtitle %}
|
||||||
{{ subtitle }}
|
{{ subtitle }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if mod %}<p><a href="?/">{% trans %}Return to dashboard{% endtrans %}</a></p>{% endif %}
|
{% if mod and not hide_dashboard_link %}<p><a href="?/">{% trans %}Return to dashboard{% endtrans %}</a></p>{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
{{ body }}
|
{{ body }}
|
||||||
|
@ -44,9 +44,9 @@
|
|||||||
$theme['build_function'] = 'basic_build';
|
$theme['build_function'] = 'basic_build';
|
||||||
$theme['install_callback'] = 'build_install';
|
$theme['install_callback'] = 'build_install';
|
||||||
|
|
||||||
if(!function_exists('build_install')) {
|
if (!function_exists('build_install')) {
|
||||||
function build_install($settings) {
|
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.');
|
return Array(false, '<strong>' . utf8tohtml($settings['no_recent']) . '</strong> is not a non-negative integer.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
public static function build($action, $settings) {
|
public static function build($action, $settings) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if($action == 'all' || $action == 'news')
|
if ($action == 'all' || $action == 'news')
|
||||||
file_write($config['dir']['home'] . $settings['file'], Basic::homepage($settings));
|
file_write($config['dir']['home'] . $settings['file'], Basic::homepage($settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,11 +54,11 @@ Requires $config[\'categories\'].';
|
|||||||
$theme['build_function'] = 'categories_build';
|
$theme['build_function'] = 'categories_build';
|
||||||
$theme['install_callback'] = 'categories_install';
|
$theme['install_callback'] = 'categories_install';
|
||||||
|
|
||||||
if(!function_exists('categories_install')) {
|
if (!function_exists('categories_install')) {
|
||||||
function categories_install($settings) {
|
function categories_install($settings) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if(!isset($config['categories'])) {
|
if (!isset($config['categories'])) {
|
||||||
return Array(false, '<h2>Prerequisites not met!</h2>' .
|
return Array(false, '<h2>Prerequisites not met!</h2>' .
|
||||||
'This theme requires $config[\'boards\'] and $config[\'categories\'] to be set.');
|
'This theme requires $config[\'boards\'] and $config[\'categories\'] to be set.');
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
</legend>
|
</legend>
|
||||||
{% for board in boards %}
|
{% for board in boards %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ board.uri }}">{{ board.title }}</a>
|
<a href="{{ board.uri }}">{{ board.title|e }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
@ -15,13 +15,13 @@
|
|||||||
public static function build($action, $settings) {
|
public static function build($action, $settings) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if($action == 'all')
|
if ($action == 'all')
|
||||||
file_write($config['dir']['home'] . $settings['file_main'], Categories::homepage($settings));
|
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));
|
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));
|
file_write($config['dir']['home'] . $settings['file_news'], Categories::news($settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,10 +52,10 @@
|
|||||||
|
|
||||||
$categories = $config['categories'];
|
$categories = $config['categories'];
|
||||||
|
|
||||||
foreach($categories as &$boards) {
|
foreach ($categories as &$boards) {
|
||||||
foreach($boards as &$board) {
|
foreach ($boards as &$board) {
|
||||||
$title = boardTitle($board);
|
$title = boardTitle($board);
|
||||||
if(!$title)
|
if (!$title)
|
||||||
$title = $board; // board doesn't exist, but for some reason you want to display it anyway
|
$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));
|
$board = Array('title' => $title, 'uri' => sprintf($config['board_path'], $board));
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
{% for board in boards %}
|
{% for board in boards %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ config.board_path|sprintf(board.uri) }}">
|
<a href="{{ config.board_path|sprintf(board.uri) }}">
|
||||||
{{ board.title }}
|
{{ board.title|e }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -15,13 +15,13 @@
|
|||||||
public static function build($action, $settings) {
|
public static function build($action, $settings) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if($action == 'all')
|
if ($action == 'all')
|
||||||
file_write($config['dir']['home'] . $settings['file_main'], Frameset::homepage($settings));
|
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));
|
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));
|
file_write($config['dir']['home'] . $settings['file_news'], Frameset::news($settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,11 +60,11 @@
|
|||||||
$theme['build_function'] = 'recentposts_build';
|
$theme['build_function'] = 'recentposts_build';
|
||||||
$theme['install_callback'] = 'recentposts_install';
|
$theme['install_callback'] = 'recentposts_install';
|
||||||
|
|
||||||
if(!function_exists('recentposts_install')) {
|
if (!function_exists('recentposts_install')) {
|
||||||
function recentposts_install($settings) {
|
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.');
|
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.');
|
return Array(false, '<strong>' . utf8tohtml($settings['limit_posts']) . '</strong> is not a non-negative integer.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,13 +17,13 @@
|
|||||||
public function build($action, $settings) {
|
public function build($action, $settings) {
|
||||||
global $config, $_theme;
|
global $config, $_theme;
|
||||||
|
|
||||||
if($action == 'all') {
|
if ($action == 'all') {
|
||||||
copy('templates/themes/recent/recent.css', $config['dir']['home'] . $settings['css']);
|
copy('templates/themes/recent/recent.css', $config['dir']['home'] . $settings['css']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->excluded = explode(' ', $settings['exclude']);
|
$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));
|
file_write($config['dir']['home'] . $settings['html'], $this->homepage($settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,15 +38,15 @@
|
|||||||
$boards = listBoards();
|
$boards = listBoards();
|
||||||
|
|
||||||
$query = '';
|
$query = '';
|
||||||
foreach($boards as &$_board) {
|
foreach ($boards as &$_board) {
|
||||||
if(in_array($_board['uri'], $this->excluded))
|
if (in_array($_board['uri'], $this->excluded))
|
||||||
continue;
|
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 .= 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 = preg_replace('/UNION ALL $/', 'ORDER BY `time` DESC LIMIT ' . (int)$settings['limit_images'], $query);
|
||||||
$query = query($query) or error(db_error());
|
$query = query($query) or error(db_error());
|
||||||
|
|
||||||
while($post = $query->fetch()) {
|
while ($post = $query->fetch()) {
|
||||||
openBoard($post['board']);
|
openBoard($post['board']);
|
||||||
|
|
||||||
// board settings won't be available in the template file, so generate links now
|
// board settings won't be available in the template file, so generate links now
|
||||||
@ -58,15 +58,15 @@
|
|||||||
|
|
||||||
|
|
||||||
$query = '';
|
$query = '';
|
||||||
foreach($boards as &$_board) {
|
foreach ($boards as &$_board) {
|
||||||
if(in_array($_board['uri'], $this->excluded))
|
if (in_array($_board['uri'], $this->excluded))
|
||||||
continue;
|
continue;
|
||||||
$query .= sprintf("SELECT *, '%s' AS `board` FROM `posts_%s` UNION ALL ", $_board['uri'], $_board['uri']);
|
$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 = preg_replace('/UNION ALL $/', 'ORDER BY `time` DESC LIMIT ' . (int)$settings['limit_posts'], $query);
|
||||||
$query = query($query) or error(db_error());
|
$query = query($query) or error(db_error());
|
||||||
|
|
||||||
while($post = $query->fetch()) {
|
while ($post = $query->fetch()) {
|
||||||
openBoard($post['board']);
|
openBoard($post['board']);
|
||||||
|
|
||||||
$post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], ($post['thread'] ? $post['thread'] : $post['id'])) . '#' . $post['id'];
|
$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
|
// Total posts
|
||||||
$query = 'SELECT SUM(`top`) AS `count` FROM (';
|
$query = 'SELECT SUM(`top`) AS `count` FROM (';
|
||||||
foreach($boards as &$_board) {
|
foreach ($boards as &$_board) {
|
||||||
if(in_array($_board['uri'], $this->excluded))
|
if (in_array($_board['uri'], $this->excluded))
|
||||||
continue;
|
continue;
|
||||||
$query .= sprintf("SELECT MAX(`id`) AS `top` FROM `posts_%s` UNION ALL ", $_board['uri']);
|
$query .= sprintf("SELECT MAX(`id`) AS `top` FROM `posts_%s` UNION ALL ", $_board['uri']);
|
||||||
}
|
}
|
||||||
@ -90,8 +90,8 @@
|
|||||||
|
|
||||||
// Unique IPs
|
// Unique IPs
|
||||||
$query = 'SELECT COUNT(DISTINCT(`ip`)) AS `count` FROM (';
|
$query = 'SELECT COUNT(DISTINCT(`ip`)) AS `count` FROM (';
|
||||||
foreach($boards as &$_board) {
|
foreach ($boards as &$_board) {
|
||||||
if(in_array($_board['uri'], $this->excluded))
|
if (in_array($_board['uri'], $this->excluded))
|
||||||
continue;
|
continue;
|
||||||
$query .= sprintf("SELECT `ip` FROM `posts_%s` UNION ALL ", $_board['uri']);
|
$query .= sprintf("SELECT `ip` FROM `posts_%s` UNION ALL ", $_board['uri']);
|
||||||
}
|
}
|
||||||
@ -102,8 +102,8 @@
|
|||||||
|
|
||||||
// Active content
|
// Active content
|
||||||
$query = 'SELECT SUM(`filesize`) AS `count` FROM (';
|
$query = 'SELECT SUM(`filesize`) AS `count` FROM (';
|
||||||
foreach($boards as &$_board) {
|
foreach ($boards as &$_board) {
|
||||||
if(in_array($_board['uri'], $this->excluded))
|
if (in_array($_board['uri'], $this->excluded))
|
||||||
continue;
|
continue;
|
||||||
$query .= sprintf("SELECT `filesize` FROM `posts_%s` UNION ALL ", $_board['uri']);
|
$query .= sprintf("SELECT `filesize` FROM `posts_%s` UNION ALL ", $_board['uri']);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
$__boards = listBoards();
|
$__boards = listBoards();
|
||||||
$__default_boards = Array();
|
$__default_boards = Array();
|
||||||
foreach($__boards as $__board)
|
foreach ($__boards as $__board)
|
||||||
$__default_boards[] = $__board['uri'];
|
$__default_boards[] = $__board['uri'];
|
||||||
|
|
||||||
$theme['config'][] = Array(
|
$theme['config'][] = Array(
|
||||||
@ -83,31 +83,31 @@
|
|||||||
);
|
);
|
||||||
|
|
||||||
$theme['install_callback'] = 'rrdtool_install';
|
$theme['install_callback'] = 'rrdtool_install';
|
||||||
if(!function_exists('rrdtool_install')) {
|
if (!function_exists('rrdtool_install')) {
|
||||||
function rrdtool_install($settings) {
|
function rrdtool_install($settings) {
|
||||||
global $config;
|
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.');
|
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>!');
|
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>!');
|
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>!');
|
return Array(false, 'Invalid rate: <strong>' . $settings['rate'] . '</strong>!');
|
||||||
|
|
||||||
$job = '*/' . $settings['interval'] . ' * * * * php -q ' . str_replace('\\', '/', dirname(__FILE__)) . '/cron.php' . PHP_EOL;
|
$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');
|
$crontab = tempnam($config['tmp'], 'tinyboard-rrdtool');
|
||||||
file_write($crontab, $job);
|
file_write($crontab, $job);
|
||||||
@system('crontab ' . escapeshellarg($crontab), $ret);
|
@system('crontab ' . escapeshellarg($crontab), $ret);
|
||||||
unlink($crontab);
|
unlink($crontab);
|
||||||
|
|
||||||
if($ret === 0)
|
if ($ret === 0)
|
||||||
return ''; // it seems to install okay?
|
return ''; // it seems to install okay?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
public function build($action, $settings) {
|
public function build($action, $settings) {
|
||||||
global $config, $_theme, $argv;
|
global $config, $_theme, $argv;
|
||||||
|
|
||||||
if(!$settings) {
|
if (!$settings) {
|
||||||
error('This theme is not currently installed.');
|
error('This theme is not currently installed.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,18 +26,18 @@
|
|||||||
// exclude boards from the "combined" graph
|
// exclude boards from the "combined" graph
|
||||||
$this->combined_exclude = Array();
|
$this->combined_exclude = Array();
|
||||||
|
|
||||||
if($action == 'cron') {
|
if ($action == 'cron') {
|
||||||
if(!file_exists($settings['path']))
|
if (!file_exists($settings['path']))
|
||||||
mkdir($settings['path']);
|
mkdir($settings['path']);
|
||||||
if(!file_exists($settings['images']))
|
if (!file_exists($settings['images']))
|
||||||
mkdir($settings['images']);
|
mkdir($settings['images']);
|
||||||
|
|
||||||
foreach($this->boards as &$board) {
|
foreach ($this->boards as &$board) {
|
||||||
$file = $settings['path'] . '/' . $board . '.rrd';
|
$file = $settings['path'] . '/' . $board . '.rrd';
|
||||||
|
|
||||||
if(!file_exists($file)) {
|
if (!file_exists($file)) {
|
||||||
// Create graph
|
// Create graph
|
||||||
if(!rrd_create($file, Array(
|
if (!rrd_create($file, Array(
|
||||||
'-s 60',
|
'-s 60',
|
||||||
'DS:posts:COUNTER:86400:0:10000',
|
'DS:posts:COUNTER:86400:0:10000',
|
||||||
|
|
||||||
@ -59,22 +59,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// debug just the graphing (not updating) with the --debug switch
|
// 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
|
// Update graph
|
||||||
$query = query(sprintf("SELECT MAX(`id`) AS `count` FROM `posts_%s`", $board));
|
$query = query(sprintf("SELECT MAX(`id`) AS `count` FROM `posts_%s`", $board));
|
||||||
$count = $query->fetch();
|
$count = $query->fetch();
|
||||||
$count = $count['count'];
|
$count = $count['count'];
|
||||||
|
|
||||||
if(!rrd_update($file, Array(
|
if (!rrd_update($file, Array(
|
||||||
'-t',
|
'-t',
|
||||||
'posts',
|
'posts',
|
||||||
'N:' . $count)))
|
'N:' . $count)))
|
||||||
error('RRDtool failed: ' . htmlentities(rrd_error()));
|
error('RRDtool failed: ' . htmlentities(rrd_error()));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($this->spans as &$span) {
|
foreach ($this->spans as &$span) {
|
||||||
// Graph graph
|
// Graph graph
|
||||||
if(!rrd_graph($settings['images'] . '/' . $board . '-' . $span . '.png', Array(
|
if (!rrd_graph($settings['images'] . '/' . $board . '-' . $span . '.png', Array(
|
||||||
'-s -1' . $span,
|
'-s -1' . $span,
|
||||||
'-t Posts on ' . sprintf($config['board_abbreviation'], $board) .' this ' . $span,
|
'-t Posts on ' . sprintf($config['board_abbreviation'], $board) .' this ' . $span,
|
||||||
'--lazy',
|
'--lazy',
|
||||||
@ -105,7 +105,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// combined graph
|
// combined graph
|
||||||
foreach($this->spans as &$span) {
|
foreach ($this->spans as &$span) {
|
||||||
$options = Array(
|
$options = Array(
|
||||||
'-s -1' . $span,
|
'-s -1' . $span,
|
||||||
'-t Posts this ' . $span,
|
'-t Posts this ' . $span,
|
||||||
@ -129,8 +129,8 @@
|
|||||||
$c = 1;
|
$c = 1;
|
||||||
$cc = 0;
|
$cc = 0;
|
||||||
$red = 2;
|
$red = 2;
|
||||||
foreach($this->boards as &$board) {
|
foreach ($this->boards as &$board) {
|
||||||
if(in_array($board, $this->combined_exclude))
|
if (in_array($board, $this->combined_exclude))
|
||||||
continue;
|
continue;
|
||||||
$color = str_pad(dechex($red*85), 2, '0', STR_PAD_LEFT) .
|
$color = str_pad(dechex($red*85), 2, '0', STR_PAD_LEFT) .
|
||||||
str_pad(dechex($green*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);
|
sprintf($config['board_abbreviation'], $board);
|
||||||
|
|
||||||
// Randomize colors using this horrible undocumented algorithm I threw together while debugging
|
// Randomize colors using this horrible undocumented algorithm I threw together while debugging
|
||||||
if($c == 0)
|
if ($c == 0)
|
||||||
$red++;
|
$red++;
|
||||||
elseif($c == 1)
|
elseif ($c == 1)
|
||||||
$green++;
|
$green++;
|
||||||
elseif($c == 2)
|
elseif ($c == 2)
|
||||||
$blue++;
|
$blue++;
|
||||||
elseif($c == 3)
|
elseif ($c == 3)
|
||||||
$green--;
|
$green--;
|
||||||
elseif($c == 4)
|
elseif ($c == 4)
|
||||||
$red--;
|
$red--;
|
||||||
|
|
||||||
$cc++;
|
$cc++;
|
||||||
if($cc > 2) {
|
if ($cc > 2) {
|
||||||
$c++;
|
$c++;
|
||||||
$cc = 0;
|
$cc = 0;
|
||||||
}
|
}
|
||||||
if($c>4) $c = 0;
|
if ($c > 4)
|
||||||
|
$c = 0;
|
||||||
|
|
||||||
if($red>3) $red = 0;
|
if ($red > 3)
|
||||||
if($green>3) $green = 0;
|
$red = 0;
|
||||||
if($blue>3) $blue = 0;
|
if ($green > 3)
|
||||||
|
$green = 0;
|
||||||
|
if ($blue > 3)
|
||||||
|
$blue = 0;
|
||||||
}
|
}
|
||||||
$options[] = 'HRULE:0#000000';
|
$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()));
|
error('RRDtool failed: ' . htmlentities(rrd_error()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
<link rel="stylesheet" media="screen" href="{{ config.url_stylesheet }}">
|
<link rel="stylesheet" media="screen" href="{{ config.url_stylesheet }}">
|
||||||
{% if config.url_favicon %}<link rel="shortcut icon" href="{{ config.url_favicon }}">{% endif %}
|
{% if config.url_favicon %}<link rel="shortcut icon" href="{{ config.url_favicon }}">{% endif %}
|
||||||
<title>{{ board.url }} - {{ board.name }}</title>
|
<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, user-scalable=yes">
|
||||||
<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.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 config.default_stylesheet.1 != '' %}<link rel="stylesheet" type="text/css" id="stylesheet" href="{{ config.uri_stylesheets }}{{ config.default_stylesheet.1 }}">{% endif %}
|
||||||
{% if not nojavascript %}
|
{% if not nojavascript %}
|
||||||
@ -29,17 +29,16 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
{% endraw %}</style>{% endif %}
|
{% endraw %}</style>{% endif %}
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{{ boardlist.top }}
|
{{ 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 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 %}
|
{% 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>
|
<header>
|
||||||
<h1>{{ board.url }} - {{ board.name }}</h1>
|
<h1>{{ board.url }} - {{ board.title|e }}</h1>
|
||||||
<div class="subtitle">
|
<div class="subtitle">
|
||||||
{% if board.title %}
|
{% if board.subtitle %}
|
||||||
{{ board.title }}
|
{{ board.subtitle|e }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if mod %}<p><a href="?/">{% trans %}Return to dashboard{% endtrans %}</a></p>{% endif %}
|
{% if mod %}<p><a href="?/">{% trans %}Return to dashboard{% endtrans %}</a></p>{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user