Browse Source

Merge branch 'master' of https://github.com/savetheinternet/Tinyboard

Conflicts:
	templates/page.html
pull/40/head
czaks 11 years ago
parent
commit
24a520485d
  1. 11
      inc/config.php
  2. 37
      inc/display.php
  3. 54
      inc/functions.php
  4. 6
      inc/lib/Twig/Extensions/Extension/Tinyboard.php
  5. 2
      inc/mod/auth.php
  6. 20
      inc/mod/pages.php
  7. 3
      js/auto-reload.js
  8. 2
      js/post-hover.js
  9. 2
      mod.php
  10. 20
      post.php
  11. 2
      templates/main.js
  12. 8
      templates/post_reply.html
  13. 14
      templates/post_thread.html

11
inc/config.php

@ -326,6 +326,11 @@
// Reply limit (stops bumping thread when this is reached) // Reply limit (stops bumping thread when this is reached)
$config['reply_limit'] = 250; $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 // Strip repeating characters when making hashes
$config['robot_enable'] = false; $config['robot_enable'] = false;
$config['robot_strip_repeating'] = true; $config['robot_strip_repeating'] = true;
@ -696,6 +701,8 @@
$config['error']['noboard'] = _('Invalid board!'); $config['error']['noboard'] = _('Invalid board!');
$config['error']['nonexistant'] = _('Thread specified does not exist.'); $config['error']['nonexistant'] = _('Thread specified does not exist.');
$config['error']['locked'] = _('Thread locked. You may not reply at this time.'); $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']['nopost'] = _('You didn\'t make a post.');
$config['error']['flood'] = _('Flood detected; Post discarded.'); $config['error']['flood'] = _('Flood detected; Post discarded.');
$config['error']['spam'] = _('Your request looks automated; 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.'); $config['error']['captcha'] = _('You seem to have mistyped the verification.');
// Moderator errors // 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']['invalid'] = _('Invalid username and/or password.');
$config['error']['notamod'] = _('You are not a mod…'); $config['error']['notamod'] = _('You are not a mod…');
$config['error']['invalidafter'] = _('Invalid username and/or password. Your user may have been deleted or changed.'); $config['error']['invalidafter'] = _('Invalid username and/or password. Your user may have been deleted or changed.');
@ -810,6 +818,9 @@
* Mod settings * 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. // Whether or not to lock moderator sessions to the IP address that was logged in with.
$config['mod']['lock_ip'] = true; $config['mod']['lock_ip'] = true;

37
inc/display.php

@ -118,7 +118,7 @@ function pm_snippet($body, $len=null) {
// calculate strlen() so we can add "..." after if needed // calculate strlen() so we can add "..." after if needed
$strlen = mb_strlen($body); $strlen = mb_strlen($body);
$body = substr($body, 0, $len); $body = mb_substr($body, 0, $len);
// Re-escape the characters. // Re-escape the characters.
return '<em>' . utf8tohtml($body) . ($strlen > $len ? '&hellip;' : '') . '</em>'; return '<em>' . utf8tohtml($body) . ($strlen > $len ? '&hellip;' : '') . '</em>';
@ -204,7 +204,7 @@ function truncate($body, $url, $max_lines = false, $max_chars = false) {
} }
} else { } else {
// remove broken HTML entity at the end (if existent) // 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>'; $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; 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) { function secure_link_confirm($text, $title, $confirm_message, $href) {
global $config; global $config;

54
inc/functions.php

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

6
inc/lib/Twig/Extensions/Extension/Tinyboard.php

@ -25,6 +25,7 @@ class Twig_Extensions_Extension_Tinyboard extends Twig_Extension
'until' => new Twig_Filter_Function('until'), 'until' => new Twig_Filter_Function('until'),
'split' => new Twig_Filter_Function('twig_split_filter'), 'split' => new Twig_Filter_Function('twig_split_filter'),
'push' => new Twig_Filter_Function('twig_push_filter'), 'push' => new Twig_Filter_Function('twig_push_filter'),
'bidi_cleanup' => new Twig_Filter_Function('bidi_cleanup'),
'addslashes' => new Twig_Filter_Function('addslashes') 'addslashes' => new Twig_Filter_Function('addslashes')
); );
} }
@ -57,8 +58,7 @@ class Twig_Extensions_Extension_Tinyboard extends Twig_Extension
} }
function twig_timezone_function() { function twig_timezone_function() {
// there's probably a much easier way of doing this return 'Z';
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) { function twig_split_filter($str, $delim) {
@ -75,7 +75,7 @@ function twig_remove_whitespace_filter($data) {
} }
function twig_date_filter($date, $format) { function twig_date_filter($date, $format) {
return strftime($format, $date); return gmstrftime($format, $date);
} }
function twig_hasPermission_filter($mod, $permission, $board = null) { function twig_hasPermission_filter($mod, $permission, $board = null) {

2
inc/mod/auth.php

@ -128,7 +128,7 @@ if (isset($_COOKIE[$config['cookies']['mod']])) {
function create_pm_header() { function create_pm_header() {
global $mod, $config; 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) if ($header === true)
return false; return false;

20
inc/mod/pages.php

@ -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 = prepare('SELECT COUNT(*) FROM `pms` WHERE `to` = :id AND `unread` = 1');
$query->bindValue(':id', $mod['id']); $query->bindValue(':id', $mod['id']);
$query->execute() or error(db_error($query)); $query->execute() or error(db_error($query));
@ -651,7 +651,8 @@ function mod_bans($page_no = 1) {
if (preg_match('/^ban_(\d+)$/', $name, $match)) if (preg_match('/^ban_(\d+)$/', $name, $match))
$unban[] = $match[1]; $unban[] = $match[1];
} }
if (isset($config['mod']['unban_limit'])){
if (count($unban) <= $config['mod']['unban_limit'] || $config['mod']['unban_limit'] == -1){
if (!empty($unban)) { if (!empty($unban)) {
query('DELETE FROM `bans` WHERE `id` = ' . implode(' OR `id` = ', $unban)) or error(db_error()); 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}"); 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']); header('Location: ?/bans', true, $config['redirect_http']);
} }
@ -1855,6 +1870,7 @@ function mod_theme_configure($theme_name) {
'result' => $result, 'result' => $result,
'message' => $message, 'message' => $message,
)); ));
return;
} }
$settings = themeSettings($theme_name); $settings = themeSettings($theme_name);

3
js/auto-reload.js

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

2
js/post-hover.js

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

2
mod.php

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

20
post.php

@ -310,13 +310,21 @@ if (isset($_POST['delete'])) {
} }
} }
// Check if thread is locked if (!$post['op']) {
// but allow mods to post // Check if thread is locked
if (!$post['op'] && !hasPermission($config['mod']['postinlocked'], $board['uri'])) { // but allow mods to post
if ($thread['locked']) if ($thread['locked'] && !hasPermission($config['mod']['postinlocked'], $board['uri']))
error($config['error']['locked']); 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']) { if ($post['has_file']) {
$size = $_FILES['file']['size']; $size = $_FILES['file']['size'];
if ($size > $config['max_filesize']) if ($size > $config['max_filesize'])
@ -644,7 +652,7 @@ if (isset($_POST['delete'])) {
buildThread($post['op'] ? $id : $post['thread']); 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']); bumpThread($post['thread']);
} }

2
templates/main.js

@ -105,7 +105,7 @@ function generatePassword() {
function dopost(form) { function dopost(form) {
if (form.elements['name']) { 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') { if (form.elements['email'] && form.elements['email'].value != 'sage') {
localStorage.email = form.elements['email'].value; localStorage.email = form.elements['email'].value;

8
templates/post_reply.html

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

14
templates/post_thread.html

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

Loading…
Cancel
Save