Skip to content

Commit

Permalink
new banlist implementation; also includes a public banlist
Browse files Browse the repository at this point in the history
  • Loading branch information
czaks committed Oct 8, 2014
1 parent 906764a commit 9b3fa77
Show file tree
Hide file tree
Showing 10 changed files with 424 additions and 156 deletions.
90 changes: 66 additions & 24 deletions inc/bans.php
Expand Up @@ -148,49 +148,86 @@ static public function find($ip, $board = false, $get_mod_info = false) {

return $ban_list;
}

static public function list_all($offset = 0, $limit = 9001) {
$offset = (int)$offset;
$limit = (int)$limit;


static public function stream_json($out = false, $filter_ips = false, $filter_staff = false, $board_access = false) {
$query = query("SELECT ``bans``.*, `username` FROM ``bans``
LEFT JOIN ``mods`` ON ``mods``.`id` = `creator`
ORDER BY `created` DESC LIMIT $offset, $limit") or error(db_error());
$bans = $query->fetchAll(PDO::FETCH_ASSOC);

foreach ($bans as &$ban) {
$ban['mask'] = self::range_to_string(array($ban['ipstart'], $ban['ipend']));
}

return $bans;
}

static public function count($board = false) {
if (!$board) {
$query = prepare("SELECT COUNT(*) FROM ``bans``");
} else {
$query = prepare("SELECT COUNT(*) FROM ``bans`` WHERE `board` = :board");
ORDER BY `created` DESC") or error(db_error());
$bans = $query->fetchAll(PDO::FETCH_ASSOC);

if ($board_access && $board_access[0] == '*') $board_access = false;

$out ? fputs($out, "[") : print("[");

$end = end($bans);

foreach ($bans as &$ban) {
$ban['mask'] = self::range_to_string(array($ban['ipstart'], $ban['ipend']));

if ($ban['post']) {
$post = json_decode($ban['post']);
$ban['message'] = $post->body;
}
unset($ban['ipstart'], $ban['ipend'], $ban['post'], $ban['creator']);

if ($board_access === false || in_array ($ban['board'], $board_access)) {
$ban['access'] = true;
}

if (filter_var($ban['mask'], FILTER_VALIDATE_IP) !== false) {
$ban['single_addr'] = true;
}
if ($filter_staff || ($board_access !== false && !in_array($ban['board'], $board_access))) {
$ban['username'] = '?';
}
if ($filter_ips || ($board_access !== false && !in_array($ban['board'], $board_access))) {
list($ban['mask'], $subnet) = explode("/", $ban['mask']);
$ban['mask'] = preg_split("/[\.:]/", $ban['mask']);
$ban['mask'] = array_slice($ban['mask'], 0, 2);
$ban['mask'] = implode(".", $ban['mask']);
$ban['mask'] .= ".*";
if (isset ($subnet)) {
$ban['mask'] .= "/$subnet";
}
$ban['masked'] = true;
}

$json = json_encode($ban);
$out ? fputs($out, $json) : print($json);

if ($ban['id'] != $end['id']) {
$out ? fputs($out, ",") : print(",");
}
}
$query->bindValue(':board', $board);
$query->execute() or error(db_error());
return (int)$query->fetchColumn();

$out ? fputs($out, "]") : print("]");

}

static public function seen($ban_id) {
$query = query("UPDATE ``bans`` SET `seen` = 1 WHERE `id` = " . (int)$ban_id) or error(db_error());
rebuildThemes('bans');
}

static public function purge() {
$query = query("DELETE FROM ``bans`` WHERE `expires` IS NOT NULL AND `expires` < " . time() . " AND `seen` = 1") or error(db_error());
rebuildThemes('bans');
}

static public function delete($ban_id, $modlog = false) {
static public function delete($ban_id, $modlog = false, $boards = false, $dont_rebuild = false) {
global $config;

if ($boards && $boards[0] == '*') $boards = false;

if ($modlog) {
$query = query("SELECT `ipstart`, `ipend` FROM ``bans`` WHERE `id` = " . (int)$ban_id) or error(db_error());
if (!$ban = $query->fetch(PDO::FETCH_ASSOC)) {
// Ban doesn't exist
return false;
}

if ($boards !== false && !in_array($ban['board'], $boards))
error($config['error']['noaccess']);

$mask = self::range_to_string(array($ban['ipstart'], $ban['ipend']));

Expand All @@ -199,6 +236,8 @@ static public function delete($ban_id, $modlog = false) {
}

query("DELETE FROM ``bans`` WHERE `id` = " . (int)$ban_id) or error(db_error());

if (!$dont_rebuild) rebuildThemes('bans');

return true;
}
Expand Down Expand Up @@ -265,6 +304,9 @@ static public function new_ban($mask, $reason, $length = false, $ban_board = fal
' (<small>#' . $pdo->lastInsertId() . '</small>)' .
' with ' . ($reason ? 'reason: ' . utf8tohtml($reason) . '' : 'no reason'));
}

rebuildThemes('bans');

return $pdo->lastInsertId();
}
}
42 changes: 22 additions & 20 deletions inc/mod/pages.php
Expand Up @@ -766,7 +766,7 @@ function mod_page_ip($ip) {
if (!hasPermission($config['mod']['unban']))
error($config['error']['noaccess']);

Bans::delete($_POST['ban_id'], true);
Bans::delete($_POST['ban_id'], true, $mod['boards']);

header('Location: ?/IP/' . $ip . '#bans', true, $config['redirect_http']);
return;
Expand Down Expand Up @@ -863,18 +863,16 @@ function mod_ban() {
require_once 'inc/mod/ban.php';

Bans::new_ban($_POST['ip'], $_POST['reason'], $_POST['length'], $_POST['board'] == '*' ? false : $_POST['board']);

if (isset($_POST['redirect']))
header('Location: ' . $_POST['redirect'], true, $config['redirect_http']);
else
header('Location: ?/', true, $config['redirect_http']);
}

function mod_bans($page_no = 1) {
function mod_bans() {
global $config;

if ($page_no < 1)
error($config['error']['404']);
global $mod;

if (!hasPermission($config['mod']['view_banlist']))
error($config['error']['noaccess']);
Expand All @@ -892,29 +890,33 @@ function mod_bans($page_no = 1) {
error(sprintf($config['error']['toomanyunban'], $config['mod']['unban_limit'], count($unban)));

foreach ($unban as $id) {
Bans::delete($id, true);
Bans::delete($id, true, $mod['boards'], true);
}
rebuildThemes('bans');
header('Location: ?/bans', true, $config['redirect_http']);
return;
}

$bans = Bans::list_all(($page_no - 1) * $config['mod']['banlist_page'], $config['mod']['banlist_page']);

if (empty($bans) && $page_no > 1)
error($config['error']['404']);

foreach ($bans as &$ban) {
if (filter_var($ban['mask'], FILTER_VALIDATE_IP) !== false)
$ban['single_addr'] = true;
}

mod_page(_('Ban list'), 'mod/ban_list.html', array(
'bans' => $bans,
'count' => Bans::count(),
'token' => make_secure_link_token('bans')
'mod' => $mod,
'boards' => json_encode($mod['boards']),
'token' => make_secure_link_token('bans'),
'token_json' => make_secure_link_token('bans.json')
));
}

function mod_bans_json() {
global $config, $mod;

if (!hasPermission($config['mod']['ban']))
error($config['error']['noaccess']);

// Compress the json for faster loads
if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) ob_start("ob_gzhandler");

Bans::stream_json(false, false, !hasPermission($config['mod']['view_banstaff']), $mod['boards']);
}

function mod_ban_appeals() {
global $config, $board;

Expand Down
10 changes: 0 additions & 10 deletions js/local-time.js
Expand Up @@ -25,16 +25,6 @@ onready(function(){
return [Math.pow(10, count - num.toString().length), num].join('').substr(1);
};

var datelocale =
{ days: [_('Sunday'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday')]
, shortDays: [_("Sun"), _("Mon"), _("Tue"), _("Wed"), _("Thu"), _("Fri"), _("Sat")]
, months: [_('January'), _('February'), _('March'), _('April'), _('May'), _('June'), _('July'), _('August'), _('September'), _('October'), _('November'), _('December')]
, shortMonths: [_('Jan'), _('Feb'), _('Mar'), _('Apr'), _('May'), _('Jun'), _('Jul'), _('Aug'), _('Sep'), _('Oct'), _('Nov'), _('Dec')]
, AM: _('AM')
, PM: _('PM')
, am: _('am')
, pm: _('pm')
};
var dateformat = (typeof strftime === 'undefined') ? function(t) {
return zeropad(t.getMonth() + 1, 2) + "/" + zeropad(t.getDate(), 2) + "/" + t.getFullYear().toString().substring(2) +
" (" + [_("Sun"), _("Mon"), _("Tue"), _("Wed"), _("Thu"), _("Fri"), _("Sat"), _("Sun")][t.getDay()] + ") " +
Expand Down
157 changes: 157 additions & 0 deletions js/mod/ban-list.js
@@ -0,0 +1,157 @@
var banlist_init = function(token, my_boards, inMod) {
inMod = !inMod;

var lt;

var selected = {};

var time = function() { return Date.now()/1000|0; }

$.getJSON(inMod ? ("?/bans.json/"+token) : token, function(t) {
$("#banlist").on("new-row", function(e, drow, el) {
var sel = selected[drow.id];
if (sel) {
$(el).find('input.unban').prop("checked", true);
}
$(el).find('input.unban').on("click", function() {
selected[drow.id] = $(this).prop("checked");
});


if (drow.expires && drow.expires != 0 && drow.expires < time()) {
$(el).find("td").css("text-decoration", "line-through");
}
});

var selall = "<input type='checkbox' id='select-all' style='float: left;'>";

lt = $("#banlist").longtable({
mask: {name: selall+_("IP address"), width: "220px", fmt: function(f) {
var pre = "";
if (inMod && f.access) {
pre = "<input type='checkbox' class='unban'>";
}

if (inMod && f.single_addr && !f.masked) {
return pre+"<a href='?/IP/"+f.mask+"'>"+f.mask+"</a>";
}
return pre+f.mask;
} },
reason: {name: _("Reason"), width: "calc(100% - 715px - 6 * 4px)", fmt: function(f) {
var add = "", suf = '';
if (f.seen == 1) add += "<i class='fa fa-check' title='"+_("Seen")+"'></i>";
if (f.message) {
add += "<i class='fa fa-comment' title='"+_("Message for which user was banned is included")+"'></i>";
suf = "<br /><br /><strong>"+_("Message:")+"</strong><br />"+f.message;
}

if (add) { add = "<div style='float: right;'>"+add+"</div>"; }

if (f.reason) return add + f.reason + suf;
else return add + "-" + suf;
} },
board: {name: _("Board"), width: "60px", fmt: function(f) {
if (f.board) return "/"+f.board+"/";
else return "<em>"+_("all")+"</em>";
} },
created: {name: _("Set"), width: "100px", fmt: function(f) {
return ago(f.created) + _(" ago"); // in AGO form
} },
// duration?
expires: {name: _("Expires"), width: "235px", fmt: function(f) {
if (!f.expires || f.expires == 0) return "<em>"+_("never")+"</em>";
return strftime(window.post_date, new Date((f.expires|0)*1000), datelocale) +
((f.expires < time()) ? "" : " <small>"+_("in ")+until(f.expires|0)+"</small>");
} },
username: {name: _("Staff"), width: "100px", fmt: function(f) {
var pre='',suf='',un=f.username;
if (inMod && f.username && f.username != '?') {
pre = "<a href='?/new_PM/"+f.username+"'>";
suf = "</a>";
}
if (!f.username) {
un = "<em>"+_("system")+"</em>";
}
return pre + un + suf;
} }
}, {}, t);

$("#select-all").click(function(e) {
var $this = $(this);
$("input.unban").prop("checked", $this.prop("checked"));
lt.get_data().forEach(function(v) { v.access && (selected[v.id] = $this.prop("checked")); });
e.stopPropagation();
});

var filter = function(e) {
if ($("#only_mine").prop("checked") && ($.inArray(e.board, my_boards) === -1)) return false;
if ($("#only_not_expired").prop("checked") && e.expires && e.expires != 0 && e.expires < time()) return false;
if ($("#search").val()) {
var terms = $("#search").val().split(" ");

var fields = ["mask", "reason", "board", "staff", "message"];

var ret_false = false;
terms.forEach(function(t) {
var fs = fields;

var re = /^(mask|reason|board|staff|message):/, ma;
if (ma = t.match(re)) {
fs = [ma[1]];
t = t.replace(re, "");
}

var found = false
fs.forEach(function(f) {
if (e[f] && e[f].indexOf(t) !== -1) {
found = true;
}
});
if (!found) ret_false = true;
});

if (ret_false) return false;
}

return true;
};

$("#only_mine, #only_not_expired, #search").on("click input", function() {
lt.set_filter(filter);
});
lt.set_filter(filter);

$(".banform").on("submit", function() { return false; });

$("#unban").on("click", function() {
$(".banform .hiddens").remove();
$("<input type='hidden' name='unban' value='unban' class='hiddens'>").appendTo(".banform");

$.each(selected, function(e) {
$("<input type='hidden' name='ban_"+e+"' value='unban' class='hiddens'>").appendTo(".banform");
});

$(".banform").off("submit").submit();
});

if (device_type == 'desktop') {
// Stick topbar
var stick_on = $(".banlist-opts").offset().top;
var state = true;
$(window).on("scroll resize", function() {
if ($(window).scrollTop() > stick_on && state == true) {
$("body").css("margin-top", $(".banlist-opts").height());
$(".banlist-opts").addClass("boardlist top").detach().prependTo("body");
$("#banlist tr:not(.row)").addClass("tblhead").detach().appendTo(".banlist-opts");
state = !state;
}
else if ($(window).scrollTop() < stick_on && state == false) {
$("body").css("margin-top", "auto");
$(".banlist-opts").removeClass("boardlist top").detach().prependTo(".banform");
$(".tblhead").detach().prependTo("#banlist");
state = !state;
}
});
}
});
}
2 changes: 1 addition & 1 deletion mod.php
Expand Up @@ -62,7 +62,7 @@ function strip_array($var) {

'/ban' => 'secure_POST ban', // new ban
'/bans' => 'secure_POST bans', // ban list
'/bans/(\d+)' => 'secure_POST bans', // ban list
'/bans.json' => 'secure bans_json', // ban list JSON
'/ban-appeals' => 'secure_POST ban_appeals', // view ban appeals

'/recent/(\d+)' => 'recent_posts', // view recent posts
Expand Down

0 comments on commit 9b3fa77

Please sign in to comment.