* Update symlinks in the root.
* Bantracker/cgi/bans.cgi: * Use action="" in forms, which default to whatever the current URL is (without query or fragment). * Make sure errors are printed to sys.stderr, so they show up in the right pace. * Added irc_network and irc_channel config options, so it's not hard-coded. * replace "X.has_key(Y)" with "Y in X", has_key is "depricated" and removed in 3.x (forward planning) * added isTrue() and isFalse() to test if a form value evaluates to boolean. * True or False, repectivly. Use these in isOn(). * If a bad regex is passed in the log view, show that it was an error. * Wrap INSERT statements in a try block. * Put the generation time in a (X)HTML comment. * Bantracker/config.py: Add SQL to create INDEX. * Bantracker/README.txt: Update with extra information on setting up the web interface.
This commit is contained in:
parent
e3669b4465
commit
3c9161db65
|
@ -6,9 +6,6 @@ You can use the @mark <nick|hostmask> [<channel>] [<comment>]
|
||||||
command to manually add an entry to the bantracker without having to actially
|
command to manually add an entry to the bantracker without having to actially
|
||||||
kick/ban someone.
|
kick/ban someone.
|
||||||
|
|
||||||
It also uses commoncgi.py which should be on your sys.path (or as you can see in
|
|
||||||
the script, sys.path is modified to include the dir of commoncgi.py)
|
|
||||||
|
|
||||||
The schema of the SQLite2 database:
|
The schema of the SQLite2 database:
|
||||||
|
|
||||||
CREATE TABLE bans (
|
CREATE TABLE bans (
|
||||||
|
@ -39,6 +36,32 @@ set supybot.plugins.bantracker.database to its filename. Then enable it, either
|
||||||
per-channel or globally, by setting the channel variable:
|
per-channel or globally, by setting the channel variable:
|
||||||
supybot.plugins.bantracker.enabled
|
supybot.plugins.bantracker.enabled
|
||||||
You can create the database by using the "sqlite" command-line tool by passing
|
You can create the database by using the "sqlite" command-line tool by passing
|
||||||
the file name and then copy/paste the above table schema.
|
the file name and then copy/paste the above table schema. Then type ".quit" to
|
||||||
|
save and exit.
|
||||||
If you choose to enable this plugin during the initial setup (with the command
|
If you choose to enable this plugin during the initial setup (with the command
|
||||||
supybot-wizard), then the database will be created automatically for you.
|
supybot-wizard), then the database will be created automatically for you.
|
||||||
|
|
||||||
|
If you wish to use the web interface, it also uses commoncgi.py which should be
|
||||||
|
on your sys.path (or as you can see in cgt/bans.cgi, sys.path is modified to
|
||||||
|
include the dir of commoncgi.py).
|
||||||
|
You should place the contents of the cgi/ directory somewhere accessible by
|
||||||
|
your web server, and modify the CONFIG_FILENAME variable near the top of the
|
||||||
|
script to point to the location of your bantracker.conf.
|
||||||
|
Then modify the bantracker.conf file to reflect the proper values for your
|
||||||
|
setup.
|
||||||
|
|
||||||
|
The meanings of the entries in bantracker.conf are:
|
||||||
|
Key Type Description
|
||||||
|
anonymous_access Boolean True if annonmous access is allowed, otherwise
|
||||||
|
False.
|
||||||
|
database String The full path to the SQLite bantracker database.
|
||||||
|
results_per_page Number The maximum number of results that should be shown
|
||||||
|
per page.
|
||||||
|
plugin_path String The full path to the directory that contains the
|
||||||
|
commoncgi.py file.
|
||||||
|
irc_network String
|
||||||
|
The DNS name of the IRC network anonymous users are
|
||||||
|
directed to when anonymous access is disabled.
|
||||||
|
irc_channel String The channel name anonymous users are directed to
|
||||||
|
when anonmous access is disabled.
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#
|
#
|
||||||
###
|
###
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import urllib
|
import urllib
|
||||||
|
@ -24,10 +23,12 @@ config = ConfigParser.RawConfigParser()
|
||||||
config.add_section('webpage')
|
config.add_section('webpage')
|
||||||
|
|
||||||
# set default values
|
# set default values
|
||||||
config.set('webpage', 'database', 'bans.db')
|
config.set('webpage', 'database', '/home/bot/data/bans.db')
|
||||||
config.set('webpage', 'results_per_page', '100')
|
config.set('webpage', 'results_per_page', '100')
|
||||||
config.set('webpage', 'anonymous_access', 'True')
|
config.set('webpage', 'anonymous_access', 'True')
|
||||||
config.set('webpage', 'PLUGIN_PATH', '')
|
config.set('webpage', 'PLUGIN_PATH', '/var/www/bot')
|
||||||
|
config.set('webpage', 'irc_network', 'irc.freenode.net')
|
||||||
|
config.set('webpage', 'irc_channel', '#ubuntu-ops')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
config.readfp(open(CONFIG_FILENAME))
|
config.readfp(open(CONFIG_FILENAME))
|
||||||
|
@ -45,14 +46,14 @@ except:
|
||||||
print "Content-Type: text/html"
|
print "Content-Type: text/html"
|
||||||
print
|
print
|
||||||
print "<p>Failed to load the module commoncgi</p>"
|
print "<p>Failed to load the module commoncgi</p>"
|
||||||
print "<p>Check that the config option PLUGIN_PATH in '%s' is correct.</p>" % CONFIG_FILENAME
|
print "<p>Check that the config option PLUGIN_PATH in '%s' is correct.</p>" % CONFIG_FILENAME ##< Is this "private" information?
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
db = config.get('webpage', 'database')
|
db = config.get('webpage', 'database')
|
||||||
num_per_page = config.getint('webpage', 'results_per_page')
|
num_per_page = config.getint('webpage', 'results_per_page')
|
||||||
anonymous_access = config.getboolean('webpage', 'anonymous_access')
|
anonymous_access = config.getboolean('webpage', 'anonymous_access')
|
||||||
|
irc_network = config.get('webpage', 'irc_network')
|
||||||
pagename = os.path.basename(sys.argv[0])
|
irc_channel = config.get('webpage', 'irc_channel')
|
||||||
|
|
||||||
t1 = time.time()
|
t1 = time.time()
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ try:
|
||||||
con = sqlite.connect(db)
|
con = sqlite.connect(db)
|
||||||
cur = con.cursor()
|
cur = con.cursor()
|
||||||
except sqlite.DatabaseError:
|
except sqlite.DatabaseError:
|
||||||
print "Unable to connect to to database '%s'" % db
|
print >> sys.stderr, "Unable to connect to to database '%s'" % db
|
||||||
send_page('bans.tmpl')
|
send_page('bans.tmpl')
|
||||||
|
|
||||||
def db_execute(query, args):
|
def db_execute(query, args):
|
||||||
|
@ -68,7 +69,7 @@ def db_execute(query, args):
|
||||||
cur.execute(query, args)
|
cur.execute(query, args)
|
||||||
return cur
|
return cur
|
||||||
except sqlite.OperationalError:
|
except sqlite.OperationalError:
|
||||||
print "The database is locked, wait a bit and try again."
|
print >> sys.stderr, "The database is locked, wait a bit and try again."
|
||||||
send_page('bans.tmpl')
|
send_page('bans.tmpl')
|
||||||
|
|
||||||
# Login check
|
# Login check
|
||||||
|
@ -83,9 +84,9 @@ except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Session handling
|
# Session handling
|
||||||
if form.has_key('sess'):
|
if 'sess' in form:
|
||||||
cookie['sess'] = form['sess'].value
|
cookie['sess'] = form['sess'].value
|
||||||
if cookie.has_key('sess'):
|
if 'sess' in cookie:
|
||||||
sess = cookie['sess'].value
|
sess = cookie['sess'].value
|
||||||
try:
|
try:
|
||||||
cur.execute('SELECT user FROM sessions WHERE session_id=%s',(sess,))
|
cur.execute('SELECT user FROM sessions WHERE session_id=%s',(sess,))
|
||||||
|
@ -96,17 +97,43 @@ if cookie.has_key('sess'):
|
||||||
|
|
||||||
if not user and not anonymous_access:
|
if not user and not anonymous_access:
|
||||||
print "Sorry, bantracker is not available for anonymous users<br />"
|
print "Sorry, bantracker is not available for anonymous users<br />"
|
||||||
print "Join <a href=irc://irc.freenode.net/ubuntu-ops>#ubuntu-ops</a> on irc.freenode.net to discuss bans"
|
print 'Join <a href="irc://%s/%s">%s</a> on %s to descuss bans.' % (irc_network, irc_channel[1:], irc_channel, irc_network)
|
||||||
send_page('bans.tmpl')
|
send_page('bans.tmpl')
|
||||||
|
|
||||||
|
haveQuery = False
|
||||||
|
|
||||||
def urlencode(**kwargs):
|
def urlencode(**kwargs):
|
||||||
"""Return the url options as a string, inserting additional ones if given."""
|
"""Return the url options as a string, inserting additional ones if given."""
|
||||||
d = dict([ (i.name, i.value) for i in form.list ])
|
d = dict([ (i.name, i.value) for i in form.list ])
|
||||||
d.update(kwargs)
|
d.update(kwargs)
|
||||||
return urllib.urlencode(d.items())
|
return urllib.urlencode(d.items())
|
||||||
|
|
||||||
|
def isTrue(value):
|
||||||
|
"""Returns True if the form value is one of "1", "true", "yes", or "on", case insensitive"""
|
||||||
|
if not value:
|
||||||
|
return False
|
||||||
|
return value.lower() in ('1', 'true', 'yes', 'on')
|
||||||
|
|
||||||
|
def isFalse(value):
|
||||||
|
"""Returns True if the form value is one of "0", "false", "no", or "off", case insensitive"""
|
||||||
|
if not value:
|
||||||
|
return False
|
||||||
|
return value.lower() in ('0', 'false', 'no', 'off')
|
||||||
|
|
||||||
|
def isOn(k):
|
||||||
|
global haveQuery
|
||||||
|
default = not haveQuery
|
||||||
|
if not k in form:
|
||||||
|
return default
|
||||||
|
if isTrue(form[k].value):
|
||||||
|
return True
|
||||||
|
if isFalse(form[k].value):
|
||||||
|
return False
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
# Log
|
# Log
|
||||||
if form.has_key('log'):
|
if 'log' in form:
|
||||||
log_id = form['log'].value
|
log_id = form['log'].value
|
||||||
plain = False
|
plain = False
|
||||||
mark = False
|
mark = False
|
||||||
|
@ -114,13 +141,13 @@ if form.has_key('log'):
|
||||||
regex = False
|
regex = False
|
||||||
regex_value = ''
|
regex_value = ''
|
||||||
|
|
||||||
if form.has_key('plain') and form['plain'].value.lower() in ('1', 'true', 'on'):
|
if 'plain' in form and isTrue(form['plain'].value):
|
||||||
plain = True
|
plain = True
|
||||||
|
|
||||||
if form.has_key('mark'):
|
if 'mark' in form:
|
||||||
mark = True
|
mark = True
|
||||||
mark_value = form['mark'].value
|
mark_value = form['mark'].value
|
||||||
if form.has_key('regex') and form['regex'].value in ('1', 'true', 'on'):
|
if 'regex' in form and isTrue(form['regex'].value)
|
||||||
regex = True
|
regex = True
|
||||||
regex_value = 'checked="checked"'
|
regex_value = 'checked="checked"'
|
||||||
|
|
||||||
|
@ -138,7 +165,7 @@ if form.has_key('log'):
|
||||||
|
|
||||||
if not plain:
|
if not plain:
|
||||||
print ' <div class="main">'
|
print ' <div class="main">'
|
||||||
print ' <form id="hform" action="%s" method="get">' % pagename
|
print ' <form id="hform" action="" method="get">'
|
||||||
print ' <fieldset>'
|
print ' <fieldset>'
|
||||||
print ' <input type="hidden" name="log" id="log" value="%s">' % q(log_id)
|
print ' <input type="hidden" name="log" id="log" value="%s">' % q(log_id)
|
||||||
print ' <label for="mark">Highlight:</label>'
|
print ' <label for="mark">Highlight:</label>'
|
||||||
|
@ -159,7 +186,11 @@ if form.has_key('log'):
|
||||||
|
|
||||||
if mark:
|
if mark:
|
||||||
if regex:
|
if regex:
|
||||||
mark = re.compile(mark_value, re.I)
|
try:
|
||||||
|
mark = re.compile(mark_value, re.I)
|
||||||
|
except:
|
||||||
|
print >> sys.stderr, "Malformed regex %r" % mark_value
|
||||||
|
mark = False
|
||||||
else:
|
else:
|
||||||
escaped = re.escape(mark_value).replace('%', '.*')
|
escaped = re.escape(mark_value).replace('%', '.*')
|
||||||
mark = re.compile(escaped, re.I)
|
mark = re.compile(escaped, re.I)
|
||||||
|
@ -182,7 +213,7 @@ if form.has_key('log'):
|
||||||
|
|
||||||
print '</div><br />'
|
print '</div><br />'
|
||||||
print '<div>'
|
print '<div>'
|
||||||
print ' <form id="comment_form" action="%s" method="post">' % pagename
|
print ' <form id="comment_form" action="" method="post">'
|
||||||
print ' <fieldset>'
|
print ' <fieldset>'
|
||||||
print ' <legend>Add a comment</legend>'
|
print ' <legend>Add a comment</legend>'
|
||||||
print ' <textarea cols="50" rows="5" class="input" name="comment"></textarea><br />'
|
print ' <textarea cols="50" rows="5" class="input" name="comment"></textarea><br />'
|
||||||
|
@ -196,16 +227,20 @@ if form.has_key('log'):
|
||||||
|
|
||||||
# Main page
|
# Main page
|
||||||
# Process comments
|
# Process comments
|
||||||
if form.has_key('comment') and form.has_key('comment_id') and user:
|
if 'comment' in form and 'comment_id' in form and user:
|
||||||
cur.execute('SELECT ban_id FROM comments WHERE ban_id=%s and comment=%s', (form['comment_id'].value, form['comment'].value))
|
cur.execute('SELECT ban_id FROM comments WHERE ban_id=%s and comment=%s', (form['comment_id'].value, form['comment'].value))
|
||||||
comm = cur.fetchall()
|
comm = cur.fetchall()
|
||||||
if not len(comm):
|
if not len(comm):
|
||||||
cur.execute('INSERT INTO comments (ban_id, who, comment, time) VALUES (%s, %s, %s, %s)',
|
try:
|
||||||
(form['comment_id'].value,user,form['comment'].value,pickle.dumps(datetime.datetime.now(pytz.UTC))))
|
cur.execute('INSERT INTO comments (ban_id, who, comment, time) VALUES (%s, %s, %s, %s)',
|
||||||
con.commit()
|
(form['comment_id'].value, user,form['comment'].value, pickle.dumps(datetime.datetime.now(pytz.UTC))))
|
||||||
|
con.commit()
|
||||||
|
except sqlite.DatabaseError:
|
||||||
|
con.rollback()
|
||||||
|
print >> sys.stderr, "Sorry, failed to submit comment to the database. Please try again later."
|
||||||
|
|
||||||
# Write the page
|
# Write the page
|
||||||
print '<form action="%s" method="POST">' % pagename
|
print '<form action="" method="POST">'
|
||||||
|
|
||||||
# Personal data
|
# Personal data
|
||||||
print '<div class="pdata">'
|
print '<div class="pdata">'
|
||||||
|
@ -213,13 +248,15 @@ if user:
|
||||||
print 'Logged in as: %s <br /> ' % user
|
print 'Logged in as: %s <br /> ' % user
|
||||||
|
|
||||||
print 'Timezone: '
|
print 'Timezone: '
|
||||||
if form.has_key('tz') and form['tz'].value in pytz.common_timezones:
|
if 'tz' in form and form['tz'].value in pytz.common_timezones:
|
||||||
tz = form['tz'].value
|
tz = form['tz'].value
|
||||||
elif cookie.has_key('tz') and cookie['tz'].value in pytz.common_timezones:
|
elif 'tz' in cookie and cookie['tz'].value in pytz.common_timezones:
|
||||||
tz = cookie['tz'].value
|
tz = cookie['tz'].value
|
||||||
else:
|
else:
|
||||||
tz = 'UTC'
|
tz = 'UTC'
|
||||||
|
|
||||||
cookie['tz'] = tz
|
cookie['tz'] = tz
|
||||||
|
|
||||||
print '<select class="input" name="tz">'
|
print '<select class="input" name="tz">'
|
||||||
for zone in pytz.common_timezones:
|
for zone in pytz.common_timezones:
|
||||||
if zone == tz:
|
if zone == tz:
|
||||||
|
@ -233,17 +270,7 @@ print '</div>'
|
||||||
|
|
||||||
tz = pytz.timezone(tz)
|
tz = pytz.timezone(tz)
|
||||||
|
|
||||||
haveQuery = 'query' in form or 'channel' in form or 'operator' in form
|
haveQuery = 'query' in form or 'channel' in form or 'operator' in form
|
||||||
|
|
||||||
def isOn(k):
|
|
||||||
default = not haveQuery
|
|
||||||
if not form.has_key(k):
|
|
||||||
return default
|
|
||||||
if form[k].value.lower() in ('on', '1', 'true', 'yes'):
|
|
||||||
return True
|
|
||||||
if form[k].value.lower() in ('off', '0', 'false', 'no'):
|
|
||||||
return False
|
|
||||||
return default
|
|
||||||
|
|
||||||
def makeInput(name, label, before=False, type="checkbox", extra=''):
|
def makeInput(name, label, before=False, type="checkbox", extra=''):
|
||||||
if before:
|
if before:
|
||||||
|
@ -253,7 +280,7 @@ def makeInput(name, label, before=False, type="checkbox", extra=''):
|
||||||
if isOn(name):
|
if isOn(name):
|
||||||
value = ' checked="checked"'
|
value = ' checked="checked"'
|
||||||
else:
|
else:
|
||||||
if form.has_key(name):
|
if name in form:
|
||||||
value = ' value="%s"' % form[name].value,
|
value = ' value="%s"' % form[name].value,
|
||||||
|
|
||||||
print '<input class="input" type="%s" name="%s" id="%s"%s /> %s' \
|
print '<input class="input" type="%s" name="%s" id="%s"%s /> %s' \
|
||||||
|
@ -264,7 +291,7 @@ def makeInput(name, label, before=False, type="checkbox", extra=''):
|
||||||
|
|
||||||
# Search form
|
# Search form
|
||||||
print '<div class="search">'
|
print '<div class="search">'
|
||||||
print '<form action="%s" method="GET">' % pagename
|
print '<form action="" method="GET">'
|
||||||
makeInput("channel", "Channel:", True, "text")
|
makeInput("channel", "Channel:", True, "text")
|
||||||
makeInput("operator", "Operator:", True, "text")
|
makeInput("operator", "Operator:", True, "text")
|
||||||
makeInput("query", "Search:", True, "text", extra="(% and _ are wildcards)")
|
makeInput("query", "Search:", True, "text", extra="(% and _ are wildcards)")
|
||||||
|
@ -287,6 +314,8 @@ print '</form></div>'
|
||||||
if not haveQuery:
|
if not haveQuery:
|
||||||
# sqlite2 sucks, getting the last bans takes a lot of time.
|
# sqlite2 sucks, getting the last bans takes a lot of time.
|
||||||
# so lets disable that so at least the page loads quickly.
|
# so lets disable that so at least the page loads quickly.
|
||||||
|
## Maybe we should include a link on the main page for those who do want
|
||||||
|
## to list the latest bans? --tsimpson
|
||||||
print '<div style="clear: both"></div>'
|
print '<div style="clear: both"></div>'
|
||||||
send_page('bans.tmpl')
|
send_page('bans.tmpl')
|
||||||
|
|
||||||
|
@ -297,7 +326,7 @@ def getBans(id=None, mask=None, kicks=True, oldbans=True, bans=True, floodbots=T
|
||||||
args = []
|
args = []
|
||||||
where = []
|
where = []
|
||||||
if id:
|
if id:
|
||||||
where.append("id = %s")
|
where.append("id=%s")
|
||||||
args.append(id)
|
args.append(id)
|
||||||
if mask:
|
if mask:
|
||||||
where.append("mask LIKE %s")
|
where.append("mask LIKE %s")
|
||||||
|
@ -305,10 +334,10 @@ def getBans(id=None, mask=None, kicks=True, oldbans=True, bans=True, floodbots=T
|
||||||
if not floodbots:
|
if not floodbots:
|
||||||
where.append("operator NOT LIKE 'floodbot%%'")
|
where.append("operator NOT LIKE 'floodbot%%'")
|
||||||
if operator:
|
if operator:
|
||||||
where.append("operator LIKE %s")
|
where.append("operator LIKE %s") ## LIKE or ==? --tsimpson
|
||||||
args.append(operator)
|
args.append(operator)
|
||||||
if channel:
|
if channel:
|
||||||
where.append("channel LIKE %s")
|
where.append("channel LIKE %s") ## LIKE or ==? --tsimpson
|
||||||
args.append(channel)
|
args.append(channel)
|
||||||
if not kicks:
|
if not kicks:
|
||||||
where.append("mask LIKE '%%!%%'")
|
where.append("mask LIKE '%%!%%'")
|
||||||
|
@ -359,13 +388,13 @@ def getQueryTerm(query, term):
|
||||||
return (query, None)
|
return (query, None)
|
||||||
|
|
||||||
page = 0
|
page = 0
|
||||||
if form.has_key('page'):
|
if 'page' in form:
|
||||||
page = int(form['page'].value)
|
page = int(form['page'].value)
|
||||||
|
|
||||||
bans = []
|
bans = []
|
||||||
ban_count = 0
|
ban_count = 0
|
||||||
query = oper = chan = None
|
query = oper = chan = None
|
||||||
if form.has_key('query'):
|
if 'query' in form:
|
||||||
query = form['query'].value
|
query = form['query'].value
|
||||||
|
|
||||||
if query and query.isdigit():
|
if query and query.isdigit():
|
||||||
|
@ -373,9 +402,9 @@ if query and query.isdigit():
|
||||||
ban_count = len(bans)
|
ban_count = len(bans)
|
||||||
|
|
||||||
if not bans:
|
if not bans:
|
||||||
if form.has_key('channel'):
|
if 'channe' in form:
|
||||||
chan = form['channel'].value
|
chan = form['channel'].value
|
||||||
if form.has_key('operator'):
|
if 'operator' in form:
|
||||||
oper = form['operator'].value
|
oper = form['operator'].value
|
||||||
bans, ban_count = getBans(mask=query, kicks=isOn('kicks'),
|
bans, ban_count = getBans(mask=query, kicks=isOn('kicks'),
|
||||||
oldbans=isOn('oldbans'),
|
oldbans=isOn('oldbans'),
|
||||||
|
@ -397,7 +426,7 @@ def _sortf(x1,x2,field):
|
||||||
if x1[field] > x2[field]: return 1
|
if x1[field] > x2[field]: return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if form.has_key('sort'):
|
if 'sort' in form:
|
||||||
try:
|
try:
|
||||||
field = int(form['sort'].value)
|
field = int(form['sort'].value)
|
||||||
except:
|
except:
|
||||||
|
@ -408,7 +437,7 @@ if form.has_key('sort'):
|
||||||
if field >= 10:
|
if field >= 10:
|
||||||
bans.reverse()
|
bans.reverse()
|
||||||
|
|
||||||
if 'query' in form or 'operator' in form or 'channel' in form:
|
if haveQuery:
|
||||||
if not ban_count:
|
if not ban_count:
|
||||||
print '<div style="clear: both">Nothing found.</div>'
|
print '<div style="clear: both">Nothing found.</div>'
|
||||||
elif ban_count == 1:
|
elif ban_count == 1:
|
||||||
|
@ -422,7 +451,7 @@ if bans:
|
||||||
print '·'
|
print '·'
|
||||||
num_pages = int(math.ceil(ban_count / float(num_per_page)))
|
num_pages = int(math.ceil(ban_count / float(num_per_page)))
|
||||||
for i in range(num_pages):
|
for i in range(num_pages):
|
||||||
print '<a href="%s?%s">%d</a> ·' % (pagename, urlencode(page=i), i + 1)
|
print '<a href="?%s">%d</a> ·' % (urlencode(page=i), i + 1)
|
||||||
print '</div>'
|
print '</div>'
|
||||||
else:
|
else:
|
||||||
# nothign to show
|
# nothign to show
|
||||||
|
@ -448,7 +477,7 @@ for h in [ ('Channel', 0, 45),
|
||||||
if v < 10: h[1] += 10
|
if v < 10: h[1] += 10
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
#print '<th style="width: %s%%"><a href="%s?sort=%s">%s</a></th>' % (h[2], pagename, h[1], h[0])
|
#print '<th style="width: %s%%"><a href="?sort=%s">%s</a></th>' % (h[2], h[1], h[0])
|
||||||
print '<th style="width: %s%%">%s</th>' % (h[2], h[0])
|
print '<th style="width: %s%%">%s</th>' % (h[2], h[0])
|
||||||
print '<th style="width: 15%">Log</th>'
|
print '<th style="width: 15%">Log</th>'
|
||||||
print '<th>ID</th>'
|
print '<th>ID</th>'
|
||||||
|
@ -484,8 +513,8 @@ for b in bans:
|
||||||
# Log link
|
# Log link
|
||||||
print """<td>
|
print """<td>
|
||||||
Show log <a class="pseudolink" id="loglink-%s" onclick="showlog('%s')">inline</a>
|
Show log <a class="pseudolink" id="loglink-%s" onclick="showlog('%s')">inline</a>
|
||||||
| <a href="%s?log=%d">full</a>
|
| <a href="?log=%d">full</a>
|
||||||
</td>""" % (b[6], b[6], pagename, b[6])
|
</td>""" % (b[6], b[6], b[6])
|
||||||
|
|
||||||
# ID
|
# ID
|
||||||
print '<td id="id-%d">%d</td>' % (b[6], b[6])
|
print '<td id="id-%d">%d</td>' % (b[6], b[6])
|
||||||
|
@ -496,7 +525,7 @@ for b in bans:
|
||||||
print '<tr class="bg2">'
|
print '<tr class="bg2">'
|
||||||
else:
|
else:
|
||||||
print "<tr>"
|
print "<tr>"
|
||||||
db_execute('SELECT who, comment, time FROM comments WHERE ban_id = %d', (b[6],))
|
db_execute('SELECT who, comment, time FROM comments WHERE ban_id=%d', (b[6],))
|
||||||
comments = cur.fetchall()
|
comments = cur.fetchall()
|
||||||
if len(comments) == 0:
|
if len(comments) == 0:
|
||||||
print '<td colspan="5" class="comment">'
|
print '<td colspan="5" class="comment">'
|
||||||
|
@ -512,7 +541,7 @@ for b in bans:
|
||||||
if user:
|
if user:
|
||||||
print """<span class="pseudolink" onclick="toggle('%s','comment')">Add comment</span>""" % b[6]
|
print """<span class="pseudolink" onclick="toggle('%s','comment')">Add comment</span>""" % b[6]
|
||||||
print """<div class="invisible" id="comment_%s"><br />""" % b[6]
|
print """<div class="invisible" id="comment_%s"><br />""" % b[6]
|
||||||
print """ <form action="%s" method="POST">""" % pagename
|
print """ <form action="" method="post">"""
|
||||||
print """ <textarea cols="50" rows="5" class="input" name="comment"></textarea><br />"""
|
print """ <textarea cols="50" rows="5" class="input" name="comment"></textarea><br />"""
|
||||||
print """ <input type="hidden" name="comment_id" value="%s" />""" % b[6]
|
print """ <input type="hidden" name="comment_id" value="%s" />""" % b[6]
|
||||||
print """ <input class="submit" type="submit" value="Send" />"""
|
print """ <input class="submit" type="submit" value="Send" />"""
|
||||||
|
@ -526,7 +555,7 @@ print '</table>'
|
||||||
|
|
||||||
t2 = time.time()
|
t2 = time.time()
|
||||||
|
|
||||||
print "Generated in %.4f seconds<br/>" % (t2 - t1)
|
print "<!-- Generated in %.4f seconds -->" % (t2 - t1)
|
||||||
|
|
||||||
# Aaaaaaaaaaaaaaaaand send!
|
# Aaaaaaaaaaaaaaaaand send!
|
||||||
send_page('bans.tmpl')
|
send_page('bans.tmpl')
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
[webpage]
|
||||||
|
anonymous_access = True
|
||||||
|
database = /home/bot/data/bans.db
|
||||||
|
irc_network = irc.freenode.net
|
||||||
|
results_per_page = 100
|
||||||
|
irc_channel = #ubuntu-ops
|
||||||
|
plugin_path = /var/www/bot
|
||||||
|
|
|
@ -160,6 +160,8 @@ def configure(advanced):
|
||||||
)""")
|
)""")
|
||||||
#"""
|
#"""
|
||||||
|
|
||||||
|
cur.execute("CREATE INDEX comments_ban_id ON comments(ban_id)")
|
||||||
|
|
||||||
except:
|
except:
|
||||||
con.rollback()
|
con.rollback()
|
||||||
raise
|
raise
|
||||||
|
@ -169,6 +171,13 @@ def configure(advanced):
|
||||||
cur.close()
|
cur.close()
|
||||||
con.close()
|
con.close()
|
||||||
|
|
||||||
|
## Notes on setting up the web interface.
|
||||||
|
output("If you wish to use the web interface to Bantracker, please copy the cgi")
|
||||||
|
output("direcdtory to somewhere accessible from your webserver. Remember to modify")
|
||||||
|
output("the CONFIG_FILENAME variable in cgi/bans.cgi, and modify the")
|
||||||
|
output("bantracker.conf configuration file with the appropriate information.")
|
||||||
|
output("See the README.txt file for more information.")
|
||||||
|
|
||||||
Bantracker = conf.registerPlugin('Bantracker')
|
Bantracker = conf.registerPlugin('Bantracker')
|
||||||
conf.registerChannelValue(Bantracker, 'enabled',
|
conf.registerChannelValue(Bantracker, 'enabled',
|
||||||
registry.Boolean(False, """Enable the bantracker"""))
|
registry.Boolean(False, """Enable the bantracker"""))
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Bantracker/empty.tmpl
|
Bantracker/cgi/empty.tmpl
|
Loading…
Reference in New Issue