Merge branch 'master' of https://github.com/savetheinternet/Tinyboard
Conflicts: templates/page.html
This commit is contained in:
commit
24a520485d
@ -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.');
|
||||
@ -810,6 +818,9 @@
|
||||
* Mod settings
|
||||
* ====================
|
||||
*/
|
||||
|
||||
// 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;
|
||||
|
@ -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 ? '…' : '') . '</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;
|
||||
|
||||
|
@ -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('--', '–', $body); // en dash
|
||||
$body = str_replace('---', '—', $body); // em dash
|
||||
$body = str_replace('--', '–', $body); // en dash
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -16,6 +16,9 @@
|
||||
$(document).ready(function(){
|
||||
if($('div.banner').length == 0)
|
||||
return; // not index
|
||||
|
||||
if($(".post.op").size() != 1)
|
||||
return; //not thread page
|
||||
|
||||
var poll_interval;
|
||||
|
||||
|
@ -20,6 +20,8 @@ onready(function(){
|
||||
|
||||
if(id = $link.text().match(/^>>(\d+)$/)) {
|
||||
id = id[1];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
var $post = false;
|
||||
|
2
mod.php
2
mod.php
@ -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;
|
||||
|
||||
|
20
post.php
20
post.php
@ -310,13 +310,21 @@ 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']) {
|
||||
$size = $_FILES['file']['size'];
|
||||
if ($size > $config['max_filesize'])
|
||||
@ -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']);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 %}
|
||||
|
@ -22,11 +22,11 @@
|
||||
{% endif %}
|
||||
{% 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>
|
||||
{% else %}
|
||||
{{ post.filename }}
|
||||
{% endif %}
|
||||
{% if post.filename|length > config.max_filename_display %}
|
||||
<span class="postfilename" title="{{ post.filename|bidi_cleanup }}">{{ post.filename|truncate(config.max_filename_display)|bidi_cleanup }}</span>
|
||||
{% else %}
|
||||
<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 %}
|
||||
|
Loading…
Reference in New Issue
Block a user