From 3c9161db65db8447e431d3381bbc1c04c3ea3362 Mon Sep 17 00:00:00 2001 From: Terence Simpson Date: Wed, 21 Dec 2011 16:38:39 +0000 Subject: [PATCH] * 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. --- Bantracker/README.txt | 31 +++++++- Bantracker/cgi/bans.cgi | 137 ++++++++++++++++++++------------- Bantracker/cgi/bantracker.conf | 8 ++ Bantracker/config.py | 9 +++ bans.cgi | 2 +- bans.tmpl | 2 +- empty.tmpl | 2 +- 7 files changed, 130 insertions(+), 61 deletions(-) create mode 100644 Bantracker/cgi/bantracker.conf diff --git a/Bantracker/README.txt b/Bantracker/README.txt index c663ae8..c515712 100644 --- a/Bantracker/README.txt +++ b/Bantracker/README.txt @@ -6,9 +6,6 @@ You can use the @mark [] [] command to manually add an entry to the bantracker without having to actially 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: 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: supybot.plugins.bantracker.enabled 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 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. + diff --git a/Bantracker/cgi/bans.cgi b/Bantracker/cgi/bans.cgi index 3707127..214a0c9 100755 --- a/Bantracker/cgi/bans.cgi +++ b/Bantracker/cgi/bans.cgi @@ -13,7 +13,6 @@ # ### -import os import sys import time import urllib @@ -24,10 +23,12 @@ config = ConfigParser.RawConfigParser() config.add_section('webpage') # 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', '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: config.readfp(open(CONFIG_FILENAME)) @@ -45,14 +46,14 @@ except: print "Content-Type: text/html" print print "

Failed to load the module commoncgi

" - print "

Check that the config option PLUGIN_PATH in '%s' is correct.

" % CONFIG_FILENAME + print "

Check that the config option PLUGIN_PATH in '%s' is correct.

" % CONFIG_FILENAME ##< Is this "private" information? sys.exit(-1) db = config.get('webpage', 'database') num_per_page = config.getint('webpage', 'results_per_page') anonymous_access = config.getboolean('webpage', 'anonymous_access') - -pagename = os.path.basename(sys.argv[0]) +irc_network = config.get('webpage', 'irc_network') +irc_channel = config.get('webpage', 'irc_channel') t1 = time.time() @@ -60,7 +61,7 @@ try: con = sqlite.connect(db) cur = con.cursor() 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') def db_execute(query, args): @@ -68,7 +69,7 @@ def db_execute(query, args): cur.execute(query, args) return cur 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') # Login check @@ -83,9 +84,9 @@ except: pass # Session handling -if form.has_key('sess'): +if 'sess' in form: cookie['sess'] = form['sess'].value -if cookie.has_key('sess'): +if 'sess' in cookie: sess = cookie['sess'].value try: 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: print "Sorry, bantracker is not available for anonymous users
" - print "Join #ubuntu-ops on irc.freenode.net to discuss bans" + print 'Join %s on %s to descuss bans.' % (irc_network, irc_channel[1:], irc_channel, irc_network) send_page('bans.tmpl') +haveQuery = False + def urlencode(**kwargs): """Return the url options as a string, inserting additional ones if given.""" d = dict([ (i.name, i.value) for i in form.list ]) d.update(kwargs) 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 -if form.has_key('log'): +if 'log' in form: log_id = form['log'].value plain = False mark = False @@ -114,13 +141,13 @@ if form.has_key('log'): regex = False 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 - if form.has_key('mark'): + if 'mark' in form: mark = True 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_value = 'checked="checked"' @@ -138,7 +165,7 @@ if form.has_key('log'): if not plain: print '
' - print '
' % pagename + print ' ' print '
' print ' ' % q(log_id) print ' ' @@ -159,7 +186,11 @@ if form.has_key('log'): if mark: 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: escaped = re.escape(mark_value).replace('%', '.*') mark = re.compile(escaped, re.I) @@ -182,7 +213,7 @@ if form.has_key('log'): print '

' print '
' - print ' ' % pagename + print ' ' print '
' print ' Add a comment' print '
' @@ -196,16 +227,20 @@ if form.has_key('log'): # Main page # 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)) comm = cur.fetchall() if not len(comm): - cur.execute('INSERT INTO comments (ban_id, who, comment, time) VALUES (%s, %s, %s, %s)', - (form['comment_id'].value,user,form['comment'].value,pickle.dumps(datetime.datetime.now(pytz.UTC)))) - con.commit() + try: + cur.execute('INSERT INTO comments (ban_id, who, comment, time) VALUES (%s, %s, %s, %s)', + (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 -print '' % pagename +print '' # Personal data print '
' @@ -213,13 +248,15 @@ if user: print 'Logged in as: %s
' % user 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 -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 else: tz = 'UTC' + cookie['tz'] = tz + print ' %s' \ @@ -264,7 +291,7 @@ def makeInput(name, label, before=False, type="checkbox", extra=''): # Search form print '' if not haveQuery: # sqlite2 sucks, getting the last bans takes a lot of time. # 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 '
' send_page('bans.tmpl') @@ -297,7 +326,7 @@ def getBans(id=None, mask=None, kicks=True, oldbans=True, bans=True, floodbots=T args = [] where = [] if id: - where.append("id = %s") + where.append("id=%s") args.append(id) if mask: 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: where.append("operator NOT LIKE 'floodbot%%'") if operator: - where.append("operator LIKE %s") + where.append("operator LIKE %s") ## LIKE or ==? --tsimpson args.append(operator) if channel: - where.append("channel LIKE %s") + where.append("channel LIKE %s") ## LIKE or ==? --tsimpson args.append(channel) if not kicks: where.append("mask LIKE '%%!%%'") @@ -359,13 +388,13 @@ def getQueryTerm(query, term): return (query, None) page = 0 -if form.has_key('page'): +if 'page' in form: page = int(form['page'].value) bans = [] ban_count = 0 query = oper = chan = None -if form.has_key('query'): +if 'query' in form: query = form['query'].value if query and query.isdigit(): @@ -373,9 +402,9 @@ if query and query.isdigit(): ban_count = len(bans) if not bans: - if form.has_key('channel'): + if 'channe' in form: chan = form['channel'].value - if form.has_key('operator'): + if 'operator' in form: oper = form['operator'].value bans, ban_count = getBans(mask=query, kicks=isOn('kicks'), oldbans=isOn('oldbans'), @@ -397,7 +426,7 @@ def _sortf(x1,x2,field): if x1[field] > x2[field]: return 1 return 0 -if form.has_key('sort'): +if 'sort' in form: try: field = int(form['sort'].value) except: @@ -408,7 +437,7 @@ if form.has_key('sort'): if field >= 10: bans.reverse() -if 'query' in form or 'operator' in form or 'channel' in form: +if haveQuery: if not ban_count: print '
Nothing found.
' elif ban_count == 1: @@ -422,7 +451,7 @@ if bans: print '·' num_pages = int(math.ceil(ban_count / float(num_per_page))) for i in range(num_pages): - print '%d ·' % (pagename, urlencode(page=i), i + 1) + print '%d ·' % (urlencode(page=i), i + 1) print '
' else: # nothign to show @@ -448,7 +477,7 @@ for h in [ ('Channel', 0, 45), if v < 10: h[1] += 10 except: pass - #print '%s' % (h[2], pagename, h[1], h[0]) + #print '%s' % (h[2], h[1], h[0]) print '%s' % (h[2], h[0]) print 'Log' print 'ID' @@ -484,8 +513,8 @@ for b in bans: # Log link print """ Show log inline - | full - """ % (b[6], b[6], pagename, b[6]) + | full + """ % (b[6], b[6], b[6]) # ID print '%d' % (b[6], b[6]) @@ -496,7 +525,7 @@ for b in bans: print '' else: print "" - 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() if len(comments) == 0: print '' @@ -512,7 +541,7 @@ for b in bans: if user: print """Add comment""" % b[6] print """