czaks
10 years ago
10 changed files with 424 additions and 156 deletions
@ -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; |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
} |
@ -1,104 +1,41 @@ |
|||||
{% if bans|count == 0 %} |
<script src='main.js'></script> |
||||
<p style="text-align:center" class="unimportant">({% trans 'There are no active bans.' %})</p> |
<script src='js/jquery.min.js'></script> |
||||
{% else %} |
<script src='js/mobile-style.js'></script> |
||||
<form action="?/bans" method="post"> |
<script src='js/strftime.min.js'></script> |
||||
<input type="hidden" name="token" value="{{ token }}"> |
<script src='js/longtable/longtable.js'></script> |
||||
<table class="mod" style="width:100%"> |
<script src='js/mod/ban-list.js'></script> |
||||
<tr> |
<link rel='stylesheet' href='stylesheets/longtable/longtable.css'> |
||||
<th>{% trans 'IP address/mask' %}</th> |
<link rel='stylesheet' href='stylesheets/mod/ban-list.css'> |
||||
<th>{% trans 'Reason' %}</th> |
|
||||
<th>{% trans 'Board' %}</th> |
<form action="?/bans" method="post" class="banform"> |
||||
<th>{% trans 'Set' %}</th> |
{% if token %} |
||||
<th>{% trans 'Duration' %}</th> |
<input type="hidden" name="token" value="{{ token }}"> |
||||
<th>{% trans 'Expires' %}</th> |
{% endif %} |
||||
<th>{% trans 'Seen' %}</th> |
<div class='banlist-opts'> |
||||
<th>{% trans 'Staff' %}</th> |
<div class='checkboxes'> |
||||
</tr> |
{% if mod and mod.boards[0] != '*' %} |
||||
{% for ban in bans %} |
<label><input type="checkbox" id="only_mine"> {% trans %}Show only bans from boards I moderate{% endtrans %}</label> |
||||
<tr{% if ban.expires != 0 and ban.expires < time() %} style="text-decoration:line-through"{% endif %}> |
{% endif %} |
||||
<td style="white-space: nowrap"> |
<label><input type="checkbox" id="only_not_expired"> {% trans %}Show only active bans{% endtrans %}</label> |
||||
<input type="checkbox" name="ban_{{ ban.id }}"> |
</div> |
||||
{% if ban.single_addr %} |
<div class='buttons'> |
||||
<a href="?/IP/{{ ban.mask }}">{{ ban.mask }}</a> |
<input type="text" id="search" placeholder="{% trans %}Search{% endtrans %}"> |
||||
{% else %} |
{% if mod %} |
||||
{{ ban.mask }} |
<input type="submit" name="unban" id="unban" value="{% trans 'Unban selected' %}"> |
||||
{% endif %} |
{% endif %} |
||||
</td> |
</div> |
||||
<td> |
|
||||
{% if ban.reason %} |
<br class='clear'> |
||||
{{ ban.reason }} |
</div> |
||||
{% 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.created|date(config.post_date) }}"> |
|
||||
{{ ban.created|ago }} ago |
|
||||
</span> |
|
||||
</td> |
|
||||
<td style="white-space: nowrap"> |
|
||||
{% if ban.expires == 0 %} |
|
||||
- |
|
||||
{% else %} |
|
||||
{{ (ban.expires - ban.created + 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.seen %} |
|
||||
{% trans 'Yes' %} |
|
||||
{% else %} |
|
||||
{% trans 'No' %} |
|
||||
{% 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 %} |
<table class="mod" style="width:100%" id="banlist"> |
||||
{% endif %} |
|
||||
{% elseif ban.creator == -1 %} |
|
||||
<em>system</em> |
|
||||
{% else %} |
|
||||
<em>{% trans 'deleted?' %}</em> |
|
||||
{% endif %} |
|
||||
</td> |
|
||||
</tr> |
|
||||
{% endfor %} |
|
||||
</table> |
</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 %} |
|
||||
|
|
||||
|
</form> |
||||
|
{% if token_json %} |
||||
|
<script>$(function(){ banlist_init("{{ token_json }}", {{ boards }}); });</script> |
||||
|
{% else %} |
||||
|
<script>$(function(){ banlist_init("{{ uri_json }}", {{ boards }}, true); });</script> |
||||
|
{% endif %} |
||||
|
@ -0,0 +1,33 @@ |
|||||
|
<?php |
||||
|
$theme = Array(); |
||||
|
|
||||
|
// Theme name |
||||
|
$theme['name'] = 'Public Banlist'; |
||||
|
// Description (you can use Tinyboard markup here) |
||||
|
$theme['description'] = |
||||
|
'Shows a public list of bans, that were issued on all boards. Basically, this theme |
||||
|
copies the banlist interface from moderation panel.'; |
||||
|
$theme['version'] = 'v0.1'; |
||||
|
|
||||
|
// Theme configuration |
||||
|
$theme['config'] = Array(); |
||||
|
|
||||
|
$theme['config'][] = Array( |
||||
|
'title' => 'JSON feed file', |
||||
|
'name' => 'file_json', |
||||
|
'type' => 'text', |
||||
|
'default' => 'bans.json', |
||||
|
'comment' => '(eg. "bans.json")' |
||||
|
); |
||||
|
|
||||
|
$theme['config'][] = Array( |
||||
|
'title' => 'Main HTML file', |
||||
|
'name' => 'file_bans', |
||||
|
'type' => 'text', |
||||
|
'default' => 'bans.html', |
||||
|
'comment' => '(eg. "bans.html")' |
||||
|
); |
||||
|
|
||||
|
// Unique function name for building everything |
||||
|
$theme['build_function'] = 'pbanlist_build'; |
||||
|
?> |
@ -0,0 +1,56 @@ |
|||||
|
<?php |
||||
|
require 'info.php'; |
||||
|
|
||||
|
function pbanlist_build($action, $settings, $board) { |
||||
|
// Possible values for $action: |
||||
|
// - all (rebuild everything, initialization) |
||||
|
// - news (news has been updated) |
||||
|
// - boards (board list changed) |
||||
|
// - bans (ban list changed) |
||||
|
|
||||
|
PBanlist::build($action, $settings); |
||||
|
} |
||||
|
|
||||
|
// Wrap functions in a class so they don't interfere with normal Tinyboard operations |
||||
|
class PBanlist { |
||||
|
public static function build($action, $settings) { |
||||
|
global $config; |
||||
|
|
||||
|
if ($action == 'all') |
||||
|
file_write($config['dir']['home'] . $settings['file_bans'], PBanlist::homepage($settings)); |
||||
|
|
||||
|
if ($action == 'all' || $action == 'bans') |
||||
|
file_write($config['dir']['home'] . $settings['file_json'], PBanlist::gen_json($settings)); |
||||
|
} |
||||
|
|
||||
|
public static function gen_json($settings) { |
||||
|
ob_start(); |
||||
|
Bans::stream_json(false, false, !hasPermission($config['mod']['view_banstaff']), $mod['boards']); |
||||
|
$out = ob_get_contents(); |
||||
|
ob_end_clean(); |
||||
|
return $out; |
||||
|
} |
||||
|
|
||||
|
// Build homepage |
||||
|
public static function homepage($settings) { |
||||
|
global $config; |
||||
|
|
||||
|
return Element('page.html', array( |
||||
|
'config' => $config, |
||||
|
'mod' => false, |
||||
|
'hide_dashboard_link' => true, |
||||
|
'title' => _("Ban list"), |
||||
|
'subtitle' => "", |
||||
|
'nojavascript' => true, |
||||
|
'body' => Element('mod/ban_list.html', array( |
||||
|
'mod' => false, |
||||
|
'boards' => "[]", |
||||
|
'token' => false, |
||||
|
'token_json' => false, |
||||
|
'uri_json' => $config['dir']['home'] . $settings['file_json'], |
||||
|
)) |
||||
|
)); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
?> |
Loading…
Reference in new issue