raw
logotron_genesis.kv     1 #!/usr/bin/python
logotron_genesis.kv 2
logotron_genesis.kv 3 ##############################################################################
logotron_genesis.kv 4 import ConfigParser, sys
logotron_genesis.kv 5 import psycopg2, psycopg2.extras
logotron_genesis.kv 6 import psycopg2.extensions
logotron_genesis.kv 7 psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
logotron_genesis.kv 8 psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)
logotron_genesis.kv 9 import time
logotron_genesis.kv 10 import datetime
logotron_genesis.kv 11 from datetime import timedelta
logotron_genesis.kv 12 import sys
logotron_genesis.kv 13 reload(sys)
logotron_genesis.kv 14 sys.setdefaultencoding('utf8')
logotron_genesis.kv 15 import os
logotron_genesis.kv 16 import threading
logotron_genesis.kv 17 import re
sept_fixes.kv 18 import shlex
logotron_genesis.kv 19 from datetime import datetime
logotron_genesis.kv 20 from urlparse import urljoin
raw_line_export.kv 21 from flask import Flask, request, session, url_for, redirect, Response, \
logotron_genesis.kv 22 render_template, abort, g, flash, _app_ctx_stack, make_response, \
logotron_genesis.kv 23 jsonify
logotron_genesis.kv 24 from flask import Flask
logotron_genesis.kv 25 ##############################################################################
logotron_genesis.kv 26
logotron_genesis.kv 27 ##############################################################################
logotron_genesis.kv 28 # Single mandatory arg: config file path
logotron_genesis.kv 29 if len(sys.argv[1:]) != 1:
logotron_genesis.kv 30 # If no args, print usage and exit:
logotron_genesis.kv 31 print sys.argv[0] + " CONFIG"
logotron_genesis.kv 32 exit(0)
logotron_genesis.kv 33
logotron_genesis.kv 34 # Read Config from given conf file
logotron_genesis.kv 35 config_path = os.path.abspath(sys.argv[1])
logotron_genesis.kv 36 cfg = ConfigParser.ConfigParser()
logotron_genesis.kv 37 cfg.readfp(open(config_path))
logotron_genesis.kv 38
logotron_genesis.kv 39 try:
logotron_genesis.kv 40 # IRCism:
logotron_genesis.kv 41 Nick = cfg.get("irc", "nick")
logotron_genesis.kv 42 Channels = [x.strip() for x in cfg.get("irc", "chans").split(',')]
logotron_genesis.kv 43 Bots = [x.strip() for x in cfg.get("logotron", "bots").split(',')]
logotron_genesis.kv 44 Bots.append(Nick) # Add our own bot to the bot list
logotron_genesis.kv 45 # DBism:
logotron_genesis.kv 46 DB_Name = cfg.get("db", "db_name")
logotron_genesis.kv 47 DB_User = cfg.get("db", "db_user")
raw_line_export.kv 48 DB_DEBUG = int(cfg.get("db", "db_debug"))
logotron_genesis.kv 49 # Logism:
logotron_genesis.kv 50 Base_URL = cfg.get("logotron", "base_url")
logotron_genesis.kv 51 Era = int(cfg.get("logotron", "era"))
raw_line_export.kv 52 DEBUG = int(cfg.get("logotron", "www_dbg"))
raw_line_export.kv 53 Max_Raw_Ln = int(cfg.get("logotron", "max_raw"))
logotron_genesis.kv 54 # WWW:
logotron_genesis.kv 55 WWW_Port = int(cfg.get("logotron", "www_port"))
logotron_genesis.kv 56
logotron_genesis.kv 57 except Exception as e:
logotron_genesis.kv 58 print "Invalid config: ", e
logotron_genesis.kv 59 exit(1)
logotron_genesis.kv 60
logotron_genesis.kv 61 ##############################################################################
logotron_genesis.kv 62
logotron_genesis.kv 63 ##############################################################################
logotron_genesis.kv 64 ### Knobs not made into config yet ###
logotron_genesis.kv 65 Default_Chan = Channels[0]
logotron_genesis.kv 66 Min_Query_Length = 3
logotron_genesis.kv 67 Max_Search_Results = 1000
logotron_genesis.kv 68
logotron_genesis.kv 69 ## Format for Date in Log Lines
logotron_genesis.kv 70 Date_Short_Format = "%Y-%m-%d"
logotron_genesis.kv 71 ##############################################################################
logotron_genesis.kv 72
logotron_genesis.kv 73 app = Flask(__name__)
logotron_genesis.kv 74 app.config.from_object(__name__)
logotron_genesis.kv 75
logotron_genesis.kv 76 def get_db():
logotron_genesis.kv 77 db = getattr(g, 'db', None)
logotron_genesis.kv 78 if db is None:
logotron_genesis.kv 79 db = g.db = psycopg2.connect("dbname=%s user=%s" % (DB_Name, DB_User))
logotron_genesis.kv 80 return db
logotron_genesis.kv 81
logotron_genesis.kv 82 def close_db():
logotron_genesis.kv 83 if hasattr(g, 'db'):
logotron_genesis.kv 84 g.db.close()
logotron_genesis.kv 85
logotron_genesis.kv 86 @app.before_request
logotron_genesis.kv 87 def before_request():
logotron_genesis.kv 88 g.db = get_db()
logotron_genesis.kv 89
logotron_genesis.kv 90 @app.teardown_request
logotron_genesis.kv 91 def teardown_request(exception):
logotron_genesis.kv 92 close_db()
logotron_genesis.kv 93
logotron_genesis.kv 94 def query_db(query, args=(), one=False):
logotron_genesis.kv 95 cur = get_db().cursor(cursor_factory=psycopg2.extras.RealDictCursor)
logotron_genesis.kv 96 if (DB_DEBUG): print "query: '{0}'".format(query)
logotron_genesis.kv 97 cur.execute(query, args)
logotron_genesis.kv 98 rv = cur.fetchone() if one else cur.fetchall()
logotron_genesis.kv 99 if (DB_DEBUG): print "query res: '{0}'".format(rv)
logotron_genesis.kv 100 return rv
logotron_genesis.kv 101
logotron_genesis.kv 102 def exec_db(query, args=()):
logotron_genesis.kv 103 cur = get_db().cursor(cursor_factory=psycopg2.extras.RealDictCursor)
logotron_genesis.kv 104 if (DB_DEBUG): print "query: '{0}'".format(query)
logotron_genesis.kv 105 if (DB_DEBUG): print "args: '{0}'".format(args)
logotron_genesis.kv 106 if (DB_DEBUG): print "EXEC:"
logotron_genesis.kv 107 cur.execute(query, args)
logotron_genesis.kv 108
logotron_genesis.kv 109 def getlast_db():
logotron_genesis.kv 110 cur = get_db().cursor(cursor_factory=psycopg2.extras.RealDictCursor)
logotron_genesis.kv 111 cur.execute('select lastval()')
logotron_genesis.kv 112 return cur.fetchone()['lastval']
logotron_genesis.kv 113
logotron_genesis.kv 114 def commit_db():
logotron_genesis.kv 115 cur = get_db().cursor(cursor_factory=psycopg2.extras.RealDictCursor)
logotron_genesis.kv 116 g.db.commit()
logotron_genesis.kv 117
logotron_genesis.kv 118 ##############################################################################
logotron_genesis.kv 119
logotron_genesis.kv 120 ## All eggogs redirect to main page
logotron_genesis.kv 121 @app.errorhandler(404)
logotron_genesis.kv 122 def page_not_found(error):
logotron_genesis.kv 123 return redirect(url_for('log'))
logotron_genesis.kv 124
logotron_genesis.kv 125 ##############################################################################
logotron_genesis.kv 126
logotron_genesis.kv 127 html_escape_table = {
logotron_genesis.kv 128 "&": "&",
logotron_genesis.kv 129 '"': """,
logotron_genesis.kv 130 "'": "'",
logotron_genesis.kv 131 ">": ">",
logotron_genesis.kv 132 "<": "&lt;",
logotron_genesis.kv 133 }
logotron_genesis.kv 134
logotron_genesis.kv 135 def html_escape(text):
logotron_genesis.kv 136 return "".join(html_escape_table.get(c,c) for c in text)
logotron_genesis.kv 137
logotron_genesis.kv 138 ##############################################################################
logotron_genesis.kv 139
logotron_genesis.kv 140 ## Get base URL
logotron_genesis.kv 141 def get_base():
logotron_genesis.kv 142 if DEBUG:
logotron_genesis.kv 143 return request.host_url
logotron_genesis.kv 144 return Base_URL
logotron_genesis.kv 145
logotron_genesis.kv 146
logotron_genesis.kv 147 # Get perma-URL corresponding to given log line
logotron_genesis.kv 148 def line_url(l):
logotron_genesis.kv 149 return "{0}log/{1}/{2}#{3}".format(get_base(),
logotron_genesis.kv 150 l['chan'],
logotron_genesis.kv 151 l['t'].strftime(Date_Short_Format),
logotron_genesis.kv 152 l['idx'])
logotron_genesis.kv 153
logotron_genesis.kv 154 def gen_chanlist(selected_chan):
logotron_genesis.kv 155 # Get current time
logotron_genesis.kv 156 now = datetime.now()
logotron_genesis.kv 157
logotron_genesis.kv 158 s = """<table align="center" class="chantable"><tr>"""
logotron_genesis.kv 159 for chan in Channels:
logotron_genesis.kv 160 chan_formed = chan
logotron_genesis.kv 161 if chan == selected_chan:
logotron_genesis.kv 162 chan_formed = "<span class='highlight'>" + chan + "</span>"
logotron_genesis.kv 163 s += """<th><a href="{0}log/{1}">{2}</a></th>""".format(
logotron_genesis.kv 164 get_base(), chan, chan_formed)
logotron_genesis.kv 165 s += "</tr><tr>"
logotron_genesis.kv 166
logotron_genesis.kv 167 for chan in Channels:
logotron_genesis.kv 168
logotron_genesis.kv 169 last_time = query_db(
logotron_genesis.kv 170 '''select t, idx from loglines where chan=%s
logotron_genesis.kv 171 and idx = (select max(idx) from loglines where chan=%s) ;''',
logotron_genesis.kv 172 [chan, chan], one=True)
logotron_genesis.kv 173
logotron_genesis.kv 174 last_time_txt = ""
logotron_genesis.kv 175 if last_time != None:
logotron_genesis.kv 176 span = (now - last_time['t'])
logotron_genesis.kv 177 days = span.days
logotron_genesis.kv 178 hours = span.seconds/3600
logotron_genesis.kv 179 minutes = (span.seconds%3600)/60
logotron_genesis.kv 180
logotron_genesis.kv 181 if days != 0:
logotron_genesis.kv 182 last_time_txt += '%dd ' % days
logotron_genesis.kv 183 if hours != 0:
logotron_genesis.kv 184 last_time_txt += '%dh ' % hours
logotron_genesis.kv 185 if minutes != 0:
logotron_genesis.kv 186 last_time_txt += '%dm' % minutes
logotron_genesis.kv 187
logotron_genesis.kv 188 s += """<td><i><a href="{0}log/{1}/{2}#{3}">{4}</a></i></td>""".format(
logotron_genesis.kv 189 get_base(),
logotron_genesis.kv 190 chan,
logotron_genesis.kv 191 last_time['t'].strftime(Date_Short_Format),
logotron_genesis.kv 192 last_time['idx'],
logotron_genesis.kv 193 last_time_txt)
logotron_genesis.kv 194
logotron_genesis.kv 195 else:
logotron_genesis.kv 196 last_time_txt = ""
logotron_genesis.kv 197 s += "<td></td>"
logotron_genesis.kv 198
logotron_genesis.kv 199 s += "</tr></table>"
logotron_genesis.kv 200 return s
logotron_genesis.kv 201
logotron_genesis.kv 202
logotron_genesis.kv 203 # Make above callable from inside htm templater:
logotron_genesis.kv 204 app.jinja_env.globals.update(gen_chanlist=gen_chanlist)
logotron_genesis.kv 205
logotron_genesis.kv 206
logotron_genesis.kv 207 # HTML Tag Regex
logotron_genesis.kv 208 tag_regex = re.compile("(<[^>]+>)")
logotron_genesis.kv 209
logotron_genesis.kv 210
logotron_genesis.kv 211 # Find the segments of a block of text which constitute HTML tags
logotron_genesis.kv 212 def get_link_intervals(str):
logotron_genesis.kv 213 links = []
logotron_genesis.kv 214 span = []
logotron_genesis.kv 215 for match in tag_regex.finditer(str):
logotron_genesis.kv 216 span = match.span()
logotron_genesis.kv 217 links += [span]
logotron_genesis.kv 218 return links
logotron_genesis.kv 219
logotron_genesis.kv 220
logotron_genesis.kv 221 # Highlight all matched tokens in given text
logotron_genesis.kv 222 def highlight_matches(strings, text):
logotron_genesis.kv 223 e = '(' + ('|'.join(strings)) + ')'
logotron_genesis.kv 224 return re.sub(e,
logotron_genesis.kv 225 r"""<span class='highlight'>\1</span>""",
logotron_genesis.kv 226 text,
logotron_genesis.kv 227 flags=re.I)
logotron_genesis.kv 228
logotron_genesis.kv 229
logotron_genesis.kv 230 # Highlight matched tokens in the display of a search result logline,
logotron_genesis.kv 231 # but leave HTML tags alone
logotron_genesis.kv 232 def highlight_text(strings, text):
logotron_genesis.kv 233 result = ""
logotron_genesis.kv 234 last = 0
logotron_genesis.kv 235 for i in get_link_intervals(text):
logotron_genesis.kv 236 i_start, i_end = i
logotron_genesis.kv 237 result += highlight_matches(strings, text[last:i_start])
logotron_genesis.kv 238 result += text[i_start:i_end] # the HTML tag, leave it alone
logotron_genesis.kv 239 last = i_end
logotron_genesis.kv 240 result += highlight_matches(strings, text[last:]) # last block
logotron_genesis.kv 241 return result
logotron_genesis.kv 242
logotron_genesis.kv 243
logotron_genesis.kv 244 # Regexps used in format_logline:
uniturds_etc.kv 245 boxlinks_re = re.compile(
uniturds_etc.kv 246 '\[\s*<a href="(http[^ \[\]]+)"[^>]*>[^ <]+</a>\s*\]\[([^\[\]]+)\]')
uniturds_etc.kv 247
logotron_genesis.kv 248 stdlinks_re = re.compile('(http[^ \[\]]+)')
logotron_genesis.kv 249
logotron_genesis.kv 250
logotron_genesis.kv 251 ## Format given log line for display
multsel_and_datef... 252 def format_logline(l, highlights = [], select=[]):
logotron_genesis.kv 253 payload = html_escape(l['payload'])
logotron_genesis.kv 254
logotron_genesis.kv 255 # Format ordinary links:
uniturds_etc.kv 256 payload = re.sub(stdlinks_re,
uniturds_etc.kv 257 r'<a href="\1" target=\'_blank\'>\1</a>', payload)
logotron_genesis.kv 258
logotron_genesis.kv 259 # Now also format [link][text] links :
uniturds_etc.kv 260 payload = re.sub(boxlinks_re,
uniturds_etc.kv 261 r'<a href="\1" target=\'_blank\'>\2</a>', payload)
logotron_genesis.kv 262
logotron_genesis.kv 263 # If this is a search result, illuminate the matched strings:
logotron_genesis.kv 264 if highlights != []:
logotron_genesis.kv 265 payload = highlight_text(highlights, payload)
logotron_genesis.kv 266
logotron_genesis.kv 267 bot = ""
logotron_genesis.kv 268 if l['speaker'] in Bots:
logotron_genesis.kv 269 bot = " bot"
logotron_genesis.kv 270
multsel_and_datef... 271 # default -- no selection
multsel_and_datef... 272 dclass = l['speaker']
multsel_and_datef... 273
multsel_and_datef... 274 # If selection is given:
multsel_and_datef... 275 if select != []:
multsel_and_datef... 276 ss, se = select
multsel_and_datef... 277 if ss <= l['idx'] <= se:
multsel_and_datef... 278 dclass = "highlight"
multsel_and_datef... 279
sept_fixes.kv 280 speaker = l['speaker']
sept_fixes.kv 281 separator = ":"
sept_fixes.kv 282
sept_fixes.kv 283 # If 'action', annotate:
sept_fixes.kv 284 if l['self']:
sept_fixes.kv 285 separator = ""
sept_fixes.kv 286 payload = "<i>" + payload + "</i>"
sept_fixes.kv 287 speaker = "<i>" + speaker + "</i>"
sept_fixes.kv 288
logotron_genesis.kv 289 # HTMLize the given line :
multsel_and_datef... 290 s = ("<div id='{0}' class='{6}{5}'>"
logotron_genesis.kv 291 "<a class='nick' title='{2}'"
sept_fixes.kv 292 " href=\"{3}\">{1}</a>{5} {4}</div>").format(l['idx'],
sept_fixes.kv 293 speaker,
sept_fixes.kv 294 l['t'],
sept_fixes.kv 295 line_url(l),
sept_fixes.kv 296 payload,
sept_fixes.kv 297 bot,
sept_fixes.kv 298 dclass,
sept_fixes.kv 299 separator)
logotron_genesis.kv 300 return s
logotron_genesis.kv 301
logotron_genesis.kv 302 # Make above callable from inside htm templater:
logotron_genesis.kv 303 app.jinja_env.globals.update(format_logline=format_logline)
logotron_genesis.kv 304
logotron_genesis.kv 305
logotron_genesis.kv 306 # Generate navbar for the given date:
logotron_genesis.kv 307 def generate_navbar(date, tail, chan):
logotron_genesis.kv 308 cur_day = datetime.strptime(date, Date_Short_Format)
logotron_genesis.kv 309 prev_day = cur_day - timedelta(days=1)
logotron_genesis.kv 310 prev_day_txt = prev_day.strftime(Date_Short_Format)
logotron_genesis.kv 311
logotron_genesis.kv 312 s = "<a href='{0}log/{1}/{2}'>&#x2190; {2}</a>".format(
logotron_genesis.kv 313 get_base(),
logotron_genesis.kv 314 chan,
logotron_genesis.kv 315 prev_day_txt)
logotron_genesis.kv 316
logotron_genesis.kv 317 if not tail:
logotron_genesis.kv 318 next_day = cur_day + timedelta(days=1)
logotron_genesis.kv 319 next_day_txt = next_day.strftime(Date_Short_Format)
logotron_genesis.kv 320 s = s + " | <a href='{0}log/{1}/{2}'>{2} &#x2192;</a>".format(
logotron_genesis.kv 321 get_base(),
logotron_genesis.kv 322 chan,
logotron_genesis.kv 323 next_day_txt)
logotron_genesis.kv 324
logotron_genesis.kv 325 return s
logotron_genesis.kv 326
logotron_genesis.kv 327 # Make above callable from inside htm templater:
logotron_genesis.kv 328 app.jinja_env.globals.update(generate_navbar=generate_navbar)
logotron_genesis.kv 329
logotron_genesis.kv 330
uniturds_etc.kv 331 @app.route('/rnd/<chan>')
uniturds_etc.kv 332 def rnd(chan):
uniturds_etc.kv 333 # Handle rubbish chan:
uniturds_etc.kv 334 if chan not in Channels:
uniturds_etc.kv 335 return redirect(url_for('log'))
uniturds_etc.kv 336
uniturds_etc.kv 337 rnd_line = query_db(
uniturds_etc.kv 338 '''select * from loglines where chan=%s
uniturds_etc.kv 339 order by random() limit 1 ;''',
uniturds_etc.kv 340 [chan], one=True)
uniturds_etc.kv 341
uniturds_etc.kv 342 return redirect(line_url(rnd_line))
uniturds_etc.kv 343
uniturds_etc.kv 344
logotron_genesis.kv 345 @app.route('/log/<chan>/<date>')
logotron_genesis.kv 346 @app.route('/log/<chan>', defaults={'date': None})
logotron_genesis.kv 347 @app.route('/log/', defaults={'chan': Default_Chan, 'date': None})
logotron_genesis.kv 348 @app.route('/log', defaults={'chan': Default_Chan, 'date': None})
logotron_genesis.kv 349 def log(chan, date):
logotron_genesis.kv 350 # Handle rubbish chan:
logotron_genesis.kv 351 if chan not in Channels:
logotron_genesis.kv 352 return redirect(url_for('log'))
logotron_genesis.kv 353
multsel_and_datef... 354 # Get possible selection start and end
multsel_and_datef... 355 sel_start = request.args.get('ss', default = 0, type = int)
multsel_and_datef... 356 sel_end = request.args.get('se', default = 0, type = int)
uniturds_etc.kv 357
uniturds_etc.kv 358 # Get possible 'reverse gear'
uniturds_etc.kv 359 rev = request.args.get('rev', default = 0, type = int)
multsel_and_datef... 360
logotron_genesis.kv 361 # Get current time
logotron_genesis.kv 362 now = datetime.now()
logotron_genesis.kv 363
logotron_genesis.kv 364 # Whether we are viewing 'current' tail
logotron_genesis.kv 365 tail = False
logotron_genesis.kv 366
logotron_genesis.kv 367 # If viewing 'current' log:
logotron_genesis.kv 368 if date == None:
logotron_genesis.kv 369 date = now.strftime(Date_Short_Format)
logotron_genesis.kv 370 tail = True
logotron_genesis.kv 371
logotron_genesis.kv 372 # Parse given date, and redirect to default log if rubbish:
logotron_genesis.kv 373 try:
logotron_genesis.kv 374 day_start = datetime.strptime(date, Date_Short_Format)
logotron_genesis.kv 375 except Exception, e:
logotron_genesis.kv 376 return redirect(url_for('log'))
logotron_genesis.kv 377
logotron_genesis.kv 378 # Determine the end of the interval being shown
logotron_genesis.kv 379 day_end = day_start + timedelta(days=1)
logotron_genesis.kv 380
multsel_and_datef... 381 # Enable 'tail' is day_end is after end of current day
rle_errata.kv 382 if day_end > now:
multsel_and_datef... 383 tail = True
multsel_and_datef... 384
logotron_genesis.kv 385 # Get the loglines from DB
logotron_genesis.kv 386 lines = query_db(
logotron_genesis.kv 387 '''select * from loglines where chan=%s
logotron_genesis.kv 388 and t between %s and %s order by idx asc;''',
logotron_genesis.kv 389 [chan, day_start, day_end], one=False)
logotron_genesis.kv 390
uniturds_etc.kv 391 # Optional 'reverse gear' knob:
uniturds_etc.kv 392 if rev == 1:
uniturds_etc.kv 393 lines.reverse()
uniturds_etc.kv 394
logotron_genesis.kv 395 # Return the HTMLized text
logotron_genesis.kv 396 return render_template('log.html',
logotron_genesis.kv 397 chan = chan,
logotron_genesis.kv 398 loglines = lines,
multsel_and_datef... 399 sel = (sel_start, sel_end),
logotron_genesis.kv 400 date = date,
uniturds_etc.kv 401 tail = tail,
uniturds_etc.kv 402 rev = not rev)
logotron_genesis.kv 403
logotron_genesis.kv 404
raw_line_export.kv 405 @app.route('/log-raw/<chan>')
raw_line_export.kv 406 def rawlog(chan):
raw_line_export.kv 407 res = ""
raw_line_export.kv 408
raw_line_export.kv 409 # Handle rubbish chan:
raw_line_export.kv 410 if chan not in Channels:
raw_line_export.kv 411 return Response("EGGOG: No such Channel!", mimetype='text/plain')
raw_line_export.kv 412
raw_line_export.kv 413 # Get start and end indices:
raw_line_export.kv 414 idx_start = request.args.get('istart', default = 0, type = int)
raw_line_export.kv 415 idx_end = request.args.get('iend', default = 0, type = int)
raw_line_export.kv 416
raw_line_export.kv 417 # Malformed bounds?
raw_line_export.kv 418 if idx_start > idx_end:
raw_line_export.kv 419 return Response("EGGOG: Start must precede End!",
raw_line_export.kv 420 mimetype='text/plain')
raw_line_export.kv 421
raw_line_export.kv 422 # Demanded too many in one burst ?
raw_line_export.kv 423 if (idx_end - idx_start) > Max_Raw_Ln :
raw_line_export.kv 424 return Response("EGGOG: May request Max. of %s Lines !" % Max_Raw_Ln,
raw_line_export.kv 425 mimetype='text/plain')
raw_line_export.kv 426
raw_line_export.kv 427 # Get the loglines from DB
raw_line_export.kv 428 lines = query_db(
raw_line_export.kv 429 '''select * from loglines where chan=%s
raw_line_export.kv 430 and idx between %s and %s order by idx asc;''',
raw_line_export.kv 431 [chan, idx_start, idx_end], one=False)
raw_line_export.kv 432
raw_line_export.kv 433 # Retrieve raw lines in classical Phf format:
raw_line_export.kv 434 for l in lines:
raw_line_export.kv 435 action = ""
raw_line_fix.kv 436 speaker = "%s;" % l['speaker']
raw_line_export.kv 437 if l['self']:
raw_line_export.kv 438 action = "*;"
raw_line_fix.kv 439 speaker = "%s " % l['speaker']
raw_line_fix.kv 440 res += "%s;%s;%s%s%s\n" % (l['idx'],
raw_line_export.kv 441 l['t'].strftime('%s'),
raw_line_export.kv 442 action,
raw_line_fix.kv 443 speaker,
raw_line_export.kv 444 l['payload'])
raw_line_export.kv 445
raw_line_export.kv 446 # Return plain text:
raw_line_export.kv 447 return Response(res, mimetype='text/plain')
raw_line_export.kv 448
logotron_genesis.kv 449
sept_fixes.kv 450 # "Tape" is a raw log containing entried from ALL logged chans:
sept_fixes.kv 451 @app.route('/tape')
sept_fixes.kv 452 def tape():
sept_fixes.kv 453 res = ""
sept_fixes.kv 454
sept_fixes.kv 455 # Get start and end indices:
sept_fixes.kv 456 idx_start = request.args.get('istart', default = 0, type = int)
sept_fixes.kv 457 idx_end = request.args.get('iend', default = 0, type = int)
sept_fixes.kv 458
sept_fixes.kv 459 # Malformed bounds?
sept_fixes.kv 460 if idx_start > idx_end:
sept_fixes.kv 461 return Response("EGGOG: Start must precede End!",
sept_fixes.kv 462 mimetype='text/plain')
sept_fixes.kv 463
sept_fixes.kv 464 # Demanded too many in one burst ?
sept_fixes.kv 465 if (idx_end - idx_start) > Max_Raw_Ln :
sept_fixes.kv 466 return Response("EGGOG: May request Max. of %s Lines !" % Max_Raw_Ln,
sept_fixes.kv 467 mimetype='text/plain')
sept_fixes.kv 468
sept_fixes.kv 469 # Get the loglines from DB
sept_fixes.kv 470 lines = query_db(
sept_fixes.kv 471 '''select * from loglines where
sept_fixes.kv 472 idx between %s and %s order by idx asc;''',
sept_fixes.kv 473 [idx_start, idx_end], one=False)
sept_fixes.kv 474
sept_fixes.kv 475 # Retrieve raw lines in Tape format:
sept_fixes.kv 476 for l in lines:
sept_fixes.kv 477 action = ""
sept_fixes.kv 478 speaker = "%s;" % l['speaker']
sept_fixes.kv 479 if l['self']:
sept_fixes.kv 480 action = "*;"
sept_fixes.kv 481 speaker = "%s " % l['speaker']
sept_fixes.kv 482 res += "%s;%s;%s;%s%s%s\n" % (l['chan'],
sept_fixes.kv 483 l['idx'],
sept_fixes.kv 484 l['t'].strftime('%s'),
sept_fixes.kv 485 action,
sept_fixes.kv 486 speaker,
sept_fixes.kv 487 l['payload'])
sept_fixes.kv 488
sept_fixes.kv 489 # Return plain text:
sept_fixes.kv 490 return Response(res, mimetype='text/plain')
sept_fixes.kv 491
sept_fixes.kv 492
logotron_genesis.kv 493 Name_Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"
logotron_genesis.kv 494
logotron_genesis.kv 495 def sanitize_speaker(s):
logotron_genesis.kv 496 return "".join([ch for ch in s if ch in Name_Chars])
logotron_genesis.kv 497
logotron_genesis.kv 498
logotron_genesis.kv 499 def re_escape(s):
logotron_genesis.kv 500 return re.sub(r"[(){}\[\].*?|^$\\+-]", r"\\\g<0>", s)
logotron_genesis.kv 501
logotron_genesis.kv 502 # Search knob. Supports 'chan' parameter.
logotron_genesis.kv 503 @app.route('/log-search')
logotron_genesis.kv 504 def logsearch():
logotron_genesis.kv 505 # The query params:
logotron_genesis.kv 506 chan = request.args.get('chan', default = Default_Chan, type = str)
logotron_genesis.kv 507 query = request.args.get('q', default = '', type = str)
logotron_genesis.kv 508 # page_num = request.args.get('page', default = 0, type = int)
logotron_genesis.kv 509
logotron_genesis.kv 510 # Handle rubbish chan:
logotron_genesis.kv 511 if chan not in Channels:
logotron_genesis.kv 512 return redirect(url_for('log'))
logotron_genesis.kv 513
logotron_genesis.kv 514 nres = 0
logotron_genesis.kv 515 searchres = []
logotron_genesis.kv 516 tokens_orig = []
logotron_genesis.kv 517 search_head = "Query is too short!"
logotron_genesis.kv 518 # Forbid query that is too short:
logotron_genesis.kv 519 if len(query) >= Min_Query_Length:
logotron_genesis.kv 520 # Get the search tokens to use:
sept_fixes.kv 521 tokens = shlex.split(query)
logotron_genesis.kv 522 tokens_standard = []
logotron_genesis.kv 523 from_users = []
logotron_genesis.kv 524
logotron_genesis.kv 525 # separate out "from:foo" tokens and ordinary:
logotron_genesis.kv 526 for t in tokens:
logotron_genesis.kv 527 if t.startswith("from:") or t.startswith("f:"):
logotron_genesis.kv 528 from_users.append(t.split(':')[1]) # Record user for 'from' query
logotron_genesis.kv 529 else:
logotron_genesis.kv 530 tokens_standard.append(t)
logotron_genesis.kv 531
logotron_genesis.kv 532 from_users = ['%' + sanitize_speaker(t) + '%' for t in from_users]
logotron_genesis.kv 533 tokens_orig = [re_escape(t) for t in tokens_standard]
logotron_genesis.kv 534 tokens_formed = ['%' + t + '%' for t in tokens_orig]
logotron_genesis.kv 535
logotron_genesis.kv 536 # Query is usable; perform the search on DB and get the finds
logotron_genesis.kv 537 if from_users == []:
logotron_genesis.kv 538 searchres = query_db(
logotron_genesis.kv 539 '''select * from loglines where chan=%s
logotron_genesis.kv 540 and payload ilike all(%s) order by idx desc limit %s;''',
logotron_genesis.kv 541 [chan,
logotron_genesis.kv 542 tokens_formed,
logotron_genesis.kv 543 Max_Search_Results], one=False)
logotron_genesis.kv 544 else:
logotron_genesis.kv 545 searchres = query_db(
logotron_genesis.kv 546 '''select * from loglines where chan=%s
logotron_genesis.kv 547 and speaker ilike any(%s)
logotron_genesis.kv 548 and payload ilike all(%s) order by idx desc limit %s;''',
logotron_genesis.kv 549 [chan,
logotron_genesis.kv 550 from_users,
logotron_genesis.kv 551 tokens_formed,
logotron_genesis.kv 552 Max_Search_Results], one=False)
logotron_genesis.kv 553
logotron_genesis.kv 554
logotron_genesis.kv 555 # Number of entries found
logotron_genesis.kv 556 nres = len(searchres)
logotron_genesis.kv 557 search_head = "<b>{0}</b> entries found in {1} for <b>'{2}'</b> :".format(
logotron_genesis.kv 558 nres, chan, html_escape(query))
logotron_genesis.kv 559
logotron_genesis.kv 560 # No paging support just yet:
logotron_genesis.kv 561 return render_template('searchres.html',
logotron_genesis.kv 562 query = query,
logotron_genesis.kv 563 nres = nres,
logotron_genesis.kv 564 chan = chan,
logotron_genesis.kv 565 search_head = search_head,
logotron_genesis.kv 566 tokens = tokens_orig,
logotron_genesis.kv 567 loglines = searchres)
logotron_genesis.kv 568
logotron_genesis.kv 569
logotron_genesis.kv 570 # Comment this out if you don't have one
logotron_genesis.kv 571 @app.route('/favicon.ico')
logotron_genesis.kv 572 def favicon():
logotron_genesis.kv 573 return redirect(url_for('static', filename='favicon.ico'))
logotron_genesis.kv 574
logotron_genesis.kv 575
logotron_genesis.kv 576 ## App Mode
logotron_genesis.kv 577 if __name__ == '__main__':
logotron_genesis.kv 578 app.run(threaded=True, port=WWW_Port)