from flask import Flask, abort, request, render_template, url_for import math import MySQLdb import MySQLdb.cursors import datetime as dt app = Flask(__name__) PAGE_SIZE=20 # TODO: Search def now(): # TODO: If it's January and no races have been run this year, return last year return dt.datetime.now() @app.route('/') @app.route('/list') @app.route('/list/') # title = { races, rankings, runners, licence } @app.route('/list/<title>/<int:year>') def list(title=None, year=None): ''' Set defaults for the index page ''' if year is None and title is None: year = now().year title = 'runners' if title not in ( 'races', 'rankings', 'runners', 'licence', ): abort(404) start = int(request.args.get('start', '0')) limit = int(request.args.get('limit', PAGE_SIZE)) results = read_db(start, limit, listing=title, year=year) return render_template('list-'+title+'.html', ltype='listing', title=title, year=year, results=results, start=start, limit=limit, request=request, now=now(), PAGE_SIZE=PAGE_SIZE) @app.route('/all') @app.route('/all/<int:year>') @app.route('/all/<int:year>/<title>') # this does nothing, and is simply here to prevent title from being added to the query string def index(title=None, year=None): start = int(request.args.get('start', '0')) limit = int(request.args.get('limit', PAGE_SIZE)) results = read_db(start, limit, year=year) return render_template('index.html', ltype='index', year=year, results=results, start=start, limit=limit, request=request, now=now(), PAGE_SIZE=PAGE_SIZE) @app.route('/race/<int:year>/<title>') def race(year=None, title=None): start = int(request.args.get('start', '0')) limit = int(request.args.get('limit', PAGE_SIZE)) results = read_db(start, limit, event=title, year=year) return render_template('index.html', ltype='race', title=title, year=year, results=results, start=start, limit=limit, request=request, now=now(), PAGE_SIZE=PAGE_SIZE) @app.route('/person/<title>') @app.route('/person/<title>/<int:year>') def person(title=None, year=None): start = int(request.args.get('start', '0')) limit = int(request.args.get('limit', PAGE_SIZE)) results = read_db(start, limit, person=title, year=year) return render_template('index.html', ltype='person', title=title, year=year, results=results, start=start, limit=limit, request=request, now=now(), PAGE_SIZE=PAGE_SIZE) @app.route('/licence/<int:year>') @app.route('/licence/<int:year>/<title>') def licence(year=now().year, title=None): start = int(request.args.get('start', '0')) limit = int(request.args.get('limit', PAGE_SIZE)) results = read_db(start, limit, licence=title, year=year) return render_template('index.html', ltype='licence', title=title, year=year, results=results, start=start, limit=limit, request=request, now=now(), PAGE_SIZE=PAGE_SIZE) def read_db(start=0, limit=PAGE_SIZE, listing=None, event=None, person=None, licence=None, year=None): db = MySQLdb.connect(user = 'aac', passwd = 'saOAcCWHg4LaoSSA', db = 'AAC', cursorclass = MySQLdb.cursors.DictCursor) c = db.cursor() count = 0 select = '*' where = 'WHERE club LIKE "AAC"' group = '' order = 'date DESC, event, position' close = '' if event: where += ' AND event LIKE "{}"'.format(event) if person: where += ' AND CONCAT_WS(" ", name, surname) LIKE "{}"'.format(person) if licence: where += ' AND licence LIKE "{}"'.format(licence) if year: firstdate = dt.datetime.min lastdate = dt.datetime.max firstdate = firstdate.replace(year=int(year)) lastdate = lastdate.replace(year=int(year)) where += ' AND date > "{}" AND date < "{}"'.format(firstdate, lastdate) if listing: if listing == 'races': select = 'event, date' group = 'GROUP BY event' elif listing == 'runners': select = 'CONCAT_WS(" ", name, surname) person, FORMAT(SUM(distance),0) total' where += ' AND CONCAT_WS(" ", name, surname) NOT LIKE "%NO RETURN%"' where += ' AND CONCAT_WS(" ", name, surname) NOT LIKE "%BLANK CARD%"' group = 'GROUP BY CONCAT_WS(" ", name, surname)' order = 'SUM(distance) DESC, surname' elif listing == 'rankings': select = 'CONCAT_WS(" ", name, surname) person, SUM(position) positions, COUNT(event) races, SUM(position)/COUNT(event) podiums, FORMAT(SUM(position)/COUNT(event),1) score' group = 'GROUP BY CONCAT_WS(" ", name, surname)' order = 'podiums, races DESC' elif listing == 'licence': select = 'licence, date, CONCAT_WS(" ", name, surname) person' group = 'GROUP BY licence' order = 'surname, date DESC' sql = 'SELECT {} FROM `results` {} {} ORDER BY {} LIMIT {},{} {};'.format(select, where, group, order, start, limit, close) #app.logger.debug(sql) c.execute(sql) queryresults = c.fetchall() select = 'COUNT(*)' if listing: if listing == 'races': select = 'COUNT(*) FROM ( SELECT COUNT(event)' close = ') races' elif listing == 'runners': select = 'COUNT(*) FROM ( SELECT COUNT(name)' group = 'GROUP BY CONCAT_WS(" ", name, surname)' close = ') runners' elif listing == 'rankings': select = 'COUNT(*) FROM ( SELECT COUNT(name)' group = 'GROUP BY CONCAT_WS(" ", name, surname)' close = ') rankings' elif listing == 'licence': pass sql = 'SELECT {} FROM `results` {} {} {};'.format(select, where, group, close) #app.logger.debug(sql) c.execute(sql) countresult = c.fetchone() for x in countresult.keys(): count = countresult[x] app.logger.debug(count) return { 'count': int(count), 'rows': queryresults } @app.template_filter('pace') def pace(time): return (dt.datetime(1,1,1) + time).strftime('%M:%S') @app.template_filter('year') def year(time): return time.strftime('%Y') @app.template_filter('cleandate') def clean_date(time): if time.month == 1 and time.day == 1: return time.strftime('%Y') return time.strftime('%Y-%m-%d') @app.template_filter('ordinal') def ordinal(n): return "%d%s" % (n,"tsnrhtdd"[(math.floor(n/10)%10!=1)*(n%10<4)*n%10::4]) if __name__ == '__main__': app.run(debug=True) # most race KMs in the year, by distance # fastest race pace over the year (time / KMs) # individual KMs, and race results (race, position, time) by name # - and by race number and year # by race # - and by gender # tabs: # list of races (sorted by recent) # list of people (sorted by total kms for the year) # list of licences for the year (sorted by number of races) # list of podiums/rankings (people sorted by total_position/total_races) # click to expand by # person (races by recent) # person (races by pace)] # race (all AAC members by position) # SEARCH # /?sort={distance,pace}&sex={m,f} # /race/2018/HEWAT ETC?sort={position,pace}&sex={m,f} # /person/Timothy Allen?sort={pace,date} # /person/Timothy Allen/2018 # /license/2018/4356 # /license/2018/4356