Conflicts:
	templates/page.html
This commit is contained in:
czaks 2013-06-21 16:41:39 -04:00
commit 24a520485d
13 changed files with 126 additions and 55 deletions

View File

@ -326,6 +326,11 @@
// Reply limit (stops bumping thread when this is reached)
$config['reply_limit'] = 250;
// Image hard limit (stops allowing new image replies when this is reached if not zero)
$config['image_hard_limit'] = 0;
// Reply hard limit (stops allowing new replies when this is reached if not zero)
$config['reply_hard_limit'] = 0;
// Strip repeating characters when making hashes
$config['robot_enable'] = false;
$config['robot_strip_repeating'] = true;
@ -696,6 +701,8 @@
$config['error']['noboard'] = _('Invalid board!');
$config['error']['nonexistant'] = _('Thread specified does not exist.');
$config['error']['locked'] = _('Thread locked. You may not reply at this time.');
$config['error']['reply_hard_limit'] = _('Thread has reached its maximum reply limit.');
$config['error']['image_hard_limit'] = _('Thread has reached its maximum image limit.');
$config['error']['nopost'] = _('You didn\'t make a post.');
$config['error']['flood'] = _('Flood detected; Post discarded.');
$config['error']['spam'] = _('Your request looks automated; Post discarded.');
@ -723,6 +730,7 @@
$config['error']['captcha'] = _('You seem to have mistyped the verification.');
// Moderator errors
$config['error']['toomanyunban'] = _('You are only allowed to unban %s users at a time. You tried to unban %u users.');
$config['error']['invalid'] = _('Invalid username and/or password.');
$config['error']['notamod'] = _('You are not a mod…');
$config['error']['invalidafter'] = _('Invalid username and/or password. Your user may have been deleted or changed.');
@ -811,6 +819,9 @@
* ====================
*/
// Limit how many bans can be removed via the ban list. (Set too -1 to remove limit.)
$config['mod']['unban_limit'] = 5;
// Whether or not to lock moderator sessions to the IP address that was logged in with.
$config['mod']['lock_ip'] = true;

View File

@ -118,7 +118,7 @@ function pm_snippet($body, $len=null) {
// calculate strlen() so we can add "..." after if needed
$strlen = mb_strlen($body);
$body = substr($body, 0, $len);
$body = mb_substr($body, 0, $len);
// Re-escape the characters.
return '<em>' . utf8tohtml($body) . ($strlen > $len ? '&hellip;' : '') . '</em>';
@ -204,7 +204,7 @@ function truncate($body, $url, $max_lines = false, $max_chars = false) {
}
} else {
// remove broken HTML entity at the end (if existent)
$body = preg_replace('/&[^;]+$/', '', $body);
$body = preg_replace('/&[^;]*$/', '', $body);
}
$body .= '<span class="toolong">Post too long. Click <a href="' . $url . '">here</a> to view the full text.</span>';
@ -213,6 +213,39 @@ function truncate($body, $url, $max_lines = false, $max_chars = false) {
return $body;
}
function bidi_cleanup($str){
# Closes all embedded RTL and LTR unicode formatting blocks in a string so that
# it can be used inside another without controlling its direction.
# More info: http://www.iamcal.com/understanding-bidirectional-text/
#
# LRE - U+202A - 0xE2 0x80 0xAA
# RLE - U+202B - 0xE2 0x80 0xAB
# LRO - U+202D - 0xE2 0x80 0xAD
# RLO - U+202E - 0xE2 0x80 0xAE
#
# PDF - U+202C - 0xE2 0x80 0xAC
#
$explicits = '\xE2\x80\xAA|\xE2\x80\xAB|\xE2\x80\xAD|\xE2\x80\xAE';
$pdf = '\xE2\x80\xAC';
$stack = 0;
$str = preg_replace_callback("!(?<explicits>$explicits)|(?<pdf>$pdf)!", function($match) use (&$stack) {
if (isset($match['explicits']) && $match['explicits']) {
$stack++;
} else {
if ($stack)
$stack--;
else
return '';
}
return $match[0];
}, $str);
for ($i=0; $i<$stack; $i++){
$str .= "\xE2\x80\xAC";
}
return $str;
}
function secure_link_confirm($text, $title, $confirm_message, $href) {
global $config;

View File

@ -328,11 +328,19 @@ function setupBoard($array) {
}
function openBoard($uri) {
$board = getBoardInfo($uri);
if ($board) {
setupBoard($board);
return true;
}
return false;
}
function getBoardInfo($uri) {
global $config;
if ($config['cache']['enabled'] && ($board = cache::get('board_' . $uri))) {
setupBoard($board);
return true;
return $board;
}
$query = prepare("SELECT * FROM `boards` WHERE `uri` = :uri LIMIT 1");
@ -342,27 +350,16 @@ function openBoard($uri) {
if ($board = $query->fetch()) {
if ($config['cache']['enabled'])
cache::set('board_' . $uri, $board);
setupBoard($board);
return true;
return $board;
}
return false;
}
function boardTitle($uri) {
global $config;
if ($config['cache']['enabled'] && ($board = cache::get('board_' . $uri))) {
$board = getBoardInfo($uri);
if ($board)
return $board['title'];
}
$query = prepare("SELECT `title` FROM `boards` WHERE `uri` = :uri LIMIT 1");
$query->bindValue(':uri', $uri);
$query->execute() or error(db_error($query));
if ($title = $query->fetch()) {
return $title['title'];
}
return false;
}
@ -725,13 +722,13 @@ function post(array $post) {
$query->bindValue(':password', $post['password']);
$query->bindValue(':ip', isset($post['ip']) ? $post['ip'] : $_SERVER['REMOTE_ADDR']);
if ($post['op'] && $post['mod'] && $post['sticky']) {
if ($post['op'] && $post['mod'] && isset($post['sticky']) && $post['sticky']) {
$query->bindValue(':sticky', 1, PDO::PARAM_INT);
} else {
$query->bindValue(':sticky', 0, PDO::PARAM_INT);
}
if ($post['op'] && $post['mod'] && $post['locked']) {
if ($post['op'] && $post['mod'] && isset($post['locked']) && $post['locked']) {
$query->bindValue(':locked', 1, PDO::PARAM_INT);
} else {
$query->bindValue(':locked', 0, PDO::PARAM_INT);
@ -986,12 +983,8 @@ function index($page, $mod=false) {
$replies = array_reverse($posts->fetchAll(PDO::FETCH_ASSOC));
if (count($replies) == ($th['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview'])) {
$count = prepare(sprintf("SELECT COUNT(`id`) as `num` FROM `posts_%s` WHERE `thread` = :thread UNION ALL SELECT COUNT(`id`) FROM `posts_%s` WHERE `file` IS NOT NULL AND `thread` = :thread", $board['uri'], $board['uri']));
$count->bindValue(':thread', $th['id'], PDO::PARAM_INT);
$count->execute() or error(db_error($count));
$count = $count->fetchAll(PDO::FETCH_COLUMN);
$omitted = array('post_count' => $count[0], 'image_count' => $count[1]);
$count = numPosts($th['id']);
$omitted = array('post_count' => $count['replies'], 'image_count' => $count['images']);
} else {
$omitted = false;
}
@ -1134,14 +1127,19 @@ function checkRobot($body) {
return false;
}
// Returns an associative array with 'replies' and 'images' keys
function numPosts($id) {
global $board;
$query = prepare(sprintf("SELECT COUNT(*) as `count` FROM `posts_%s` WHERE `thread` = :thread", $board['uri']));
$query = prepare(sprintf("SELECT COUNT(*) as `num` FROM `posts_%s` WHERE `thread` = :thread UNION ALL SELECT COUNT(*) FROM `posts_%s` WHERE `file` IS NOT NULL AND `thread` = :thread", $board['uri'], $board['uri']));
$query->bindValue(':thread', $id, PDO::PARAM_INT);
$query->execute() or error(db_error($query));
$result = $query->fetch();
return $result['count'];
$num_posts = $query->fetch();
$num_posts = $num_posts['num'];
$num_images = $query->fetch();
$num_images = $num_images['num'];
return array('replies' => $num_posts, 'images' => $num_images);
}
function muteTime() {
@ -1365,8 +1363,8 @@ function unicodify($body) {
// En and em- dashes are rendered exactly the same in
// most monospace fonts (they look the same in code
// editors).
$body = str_replace('--', '&ndash;', $body); // en dash
$body = str_replace('---', '&mdash;', $body); // em dash
$body = str_replace('--', '&ndash;', $body); // en dash
return $body;
}

View File

@ -25,6 +25,7 @@ class Twig_Extensions_Extension_Tinyboard extends Twig_Extension
'until' => new Twig_Filter_Function('until'),
'split' => new Twig_Filter_Function('twig_split_filter'),
'push' => new Twig_Filter_Function('twig_push_filter'),
'bidi_cleanup' => new Twig_Filter_Function('bidi_cleanup'),
'addslashes' => new Twig_Filter_Function('addslashes')
);
}
@ -57,8 +58,7 @@ class Twig_Extensions_Extension_Tinyboard extends Twig_Extension
}
function twig_timezone_function() {
// there's probably a much easier way of doing this
return sprintf("%s%02d", ($hr = (int)floor(($tz = date('Z')) / 3600)) > 0 ? '+' : '-', abs($hr)) . ':' . sprintf("%02d", (($tz / 3600) - $hr) * 60);
return 'Z';
}
function twig_split_filter($str, $delim) {
@ -75,7 +75,7 @@ function twig_remove_whitespace_filter($data) {
}
function twig_date_filter($date, $format) {
return strftime($format, $date);
return gmstrftime($format, $date);
}
function twig_hasPermission_filter($mod, $permission, $board = null) {

View File

@ -128,7 +128,7 @@ if (isset($_COOKIE[$config['cookies']['mod']])) {
function create_pm_header() {
global $mod, $config;
if ($config['cache']['enabled'] && ($header = cache::get('pm_unread_' . $mod['id'])) !== false) {
if ($config['cache']['enabled'] && ($header = cache::get('pm_unread_' . $mod['id'])) != false) {
if ($header === true)
return false;

View File

@ -92,7 +92,7 @@ function mod_dashboard() {
}
}
if (!$config['cache']['enabled'] || ($args['unread_pms'] = cache::get('pm_unreadcount_' . $mod['id'])) === false) {
if (!$config['cache']['enabled'] || ($args['unread_pms'] = cache::get('pm_unreadcount_' . $mod['id'])) == false) {
$query = prepare('SELECT COUNT(*) FROM `pms` WHERE `to` = :id AND `unread` = 1');
$query->bindValue(':id', $mod['id']);
$query->execute() or error(db_error($query));
@ -651,7 +651,8 @@ function mod_bans($page_no = 1) {
if (preg_match('/^ban_(\d+)$/', $name, $match))
$unban[] = $match[1];
}
if (isset($config['mod']['unban_limit'])){
if (count($unban) <= $config['mod']['unban_limit'] || $config['mod']['unban_limit'] == -1){
if (!empty($unban)) {
query('DELETE FROM `bans` WHERE `id` = ' . implode(' OR `id` = ', $unban)) or error(db_error());
@ -659,7 +660,21 @@ function mod_bans($page_no = 1) {
modLog("Removed ban #{$id}");
}
}
} else {
error(sprintf($config['error']['toomanyunban'], $config['mod']['unban_limit'], count($unban) ));
}
} else {
if (!empty($unban)) {
query('DELETE FROM `bans` WHERE `id` = ' . implode(' OR `id` = ', $unban)) or error(db_error());
foreach ($unban as $id) {
modLog("Removed ban #{$id}");
}
}
}
header('Location: ?/bans', true, $config['redirect_http']);
}
@ -1855,6 +1870,7 @@ function mod_theme_configure($theme_name) {
'result' => $result,
'message' => $message,
));
return;
}
$settings = themeSettings($theme_name);

View File

@ -17,6 +17,9 @@ $(document).ready(function(){
if($('div.banner').length == 0)
return; // not index
if($(".post.op").size() != 1)
return; //not thread page
var poll_interval;
var poll = function() {

View File

@ -20,6 +20,8 @@ onready(function(){
if(id = $link.text().match(/^>>(\d+)$/)) {
id = id[1];
} else {
return;
}
var $post = false;

View File

@ -105,7 +105,7 @@ $new_pages = array();
foreach ($pages as $key => $callback) {
if (preg_match('/^secure /', $callback))
$key .= '(/(?P<token>[a-f0-9]{8}))?';
$new_pages[@$key[0] == '!' ? $key : "!^$key$!"] = $callback;
$new_pages[@$key[0] == '!' ? $key : '!^' . $key . '(?:&[^&=]+=[^&]*)*$!'] = $callback;
}
$pages = $new_pages;

View File

@ -310,11 +310,19 @@ if (isset($_POST['delete'])) {
}
}
// Check if thread is locked
// but allow mods to post
if (!$post['op'] && !hasPermission($config['mod']['postinlocked'], $board['uri'])) {
if ($thread['locked'])
if (!$post['op']) {
// Check if thread is locked
// but allow mods to post
if ($thread['locked'] && !hasPermission($config['mod']['postinlocked'], $board['uri']))
error($config['error']['locked']);
$numposts = numPosts($post['thread']);
if ($config['reply_hard_limit'] != 0 && $config['reply_hard_limit'] <= $numposts['replies'])
error($config['error']['reply_hard_limit']);
if ($post['has_file'] && $config['image_hard_limit'] != 0 && $config['image_hard_limit'] <= $numposts['images'])
error($config['error']['image_hard_limit']);
}
if ($post['has_file']) {
@ -644,7 +652,7 @@ if (isset($_POST['delete'])) {
buildThread($post['op'] ? $id : $post['thread']);
if (!$post['op'] && strtolower($post['email']) != 'sage' && !$thread['sage'] && ($config['reply_limit'] == 0 || numPosts($post['thread']) < $config['reply_limit'])) {
if (!$post['op'] && strtolower($post['email']) != 'sage' && !$thread['sage'] && ($config['reply_limit'] == 0 || $numposts['replies']+1 < $config['reply_limit'])) {
bumpThread($post['thread']);
}

View File

@ -105,7 +105,7 @@ function generatePassword() {
function dopost(form) {
if (form.elements['name']) {
localStorage.name = form.elements['name'].value.replace(/ ##.+$/, '');
localStorage.name = form.elements['name'].value.replace(/( |^)## .+$/, '');
}
if (form.elements['email'] && form.elements['email'].value != 'sage') {
localStorage.email = form.elements['email'].value;

View File

@ -7,14 +7,14 @@
<label for="delete_{{ post.id }}">
{% if post.subject|length > 0 %}
{# show subject #}
<span class="subject">{{ post.subject }}</span>
<span class="subject">{{ post.subject|bidi_cleanup }}</span>
{% endif %}
{% if post.email|length > 0 %}
{# start email #}
<a class="email" href="mailto:{{ post.email }}">
{% endif %}
{% set capcode = post.capcode|capcode %}
<span {% if capcode.name %}style="{{ capcode.name }}" {% endif %}class="name">{{ post.name }}</span>
<span {% if capcode.name %}style="{{ capcode.name }}" {% endif %}class="name">{{ post.name|bidi_cleanup }}</span>
{% if post.trip|length > 0 %}
<span {% if capcode.trip %}style="{{ capcode.trip }}" {% endif %}class="trip">{{ post.trip }}</span>
{% endif %}
@ -66,9 +66,9 @@
{% if config.show_filename and post.filename %}
,
{% if post.filename|length > config.max_filename_display %}
<span title="{{ post.filename }}">{{ post.filename|truncate(config.max_filename_display) }}</span>
<span class="postfilename" title="{{ post.filename|bidi_cleanup }}">{{ post.filename|truncate(config.max_filename_display)|bidi_cleanup }}</span>
{% else %}
{{ post.filename }}
<span class="postfilename">{{ post.filename|bidi_cleanup }}</span>
{% endif %}
{% endif %}
{% if post.thumb != 'file' and config.image_identification %}

View File

@ -23,9 +23,9 @@
{% if config.show_filename and post.filename %}
,
{% if post.filename|length > config.max_filename_display %}
<span title="{{ post.filename }}">{{ post.filename|truncate(config.max_filename_display) }}</span>
<span class="postfilename" title="{{ post.filename|bidi_cleanup }}">{{ post.filename|truncate(config.max_filename_display)|bidi_cleanup }}</span>
{% else %}
{{ post.filename }}
<span class="postfilename">{{ post.filename|bidi_cleanup }}</span>
{% endif %}
{% endif %}
{% if post.thumb != 'file' and config.image_identification %}
@ -61,14 +61,14 @@
<label for="delete_{{ post.id }}">
{% if post.subject|length > 0 %}
{# show subject #}
<span class="subject">{{ post.subject }}</span>
<span class="subject">{{ post.subject|bidi_cleanup }}</span>
{% endif %}
{% if post.email|length > 0 %}
{# start email #}
<a class="email" href="mailto:{{ post.email }}">
{% endif %}
{% set capcode = post.capcode|capcode %}
<span {% if capcode.name %}style="{{ capcode.name }}" {% endif %}class="name">{{ post.name }}</span>
<span {% if capcode.name %}style="{{ capcode.name }}" {% endif %}class="name">{{ post.name|bidi_cleanup }}</span>
{% if post.trip|length > 0 %}
<span {% if capcode.trip %}style="{{ capcode.trip }}" {% endif %}class="trip">{{ post.trip }}</span>
{% endif %}