# HG changeset patch # User Daniele Nicolodi # Date 1321456179 -3600 # Node ID ac0a27a72b9e0e18b4ce976baa1f0a621048460f # Parent 6bcf931c0e5962246149edf7a06c923f3c12b7e9 Reorganize Flask application setup code. diff -r 6bcf931c0e59 -r ac0a27a72b9e src/ltpdarepo/__init__.py --- a/src/ltpdarepo/__init__.py Tue Nov 15 19:15:58 2011 +0100 +++ b/src/ltpdarepo/__init__.py Wed Nov 16 16:09:39 2011 +0100 @@ -3,27 +3,30 @@ # This software may be used and distributed according to the terms of # the GNU Affero General Public License version 3 or any later version. -from urlparse import urlparse, urljoin + from datetime import datetime +from pkg_resources import get_distribution +from urlparse import urlparse, urljoin -from flask import Flask, g, request, session, render_template, Markup, redirect, flash, url_for +from flask import Flask, g, request, session, render_template, Markup, redirect, flash, url_for, current_app from werkzeug.exceptions import default_exceptions, InternalServerError, HTTPException -from pkg_resources import get_distribution import MySQLdb as mysql -import MySQLdb.converters +import MySQLdb.converters as converters import dateutil.tz -from ltpdarepo.security import secure, require, authenticate +from .security import secure, require, authenticate +from .views.browse import module as browse +from .views.databases import module as databases +from .views.feed import url_for_atom_feed, module as feed +from .views.profile import module as profile +from .views.queries import module as queries +from .views.users import module as users SCHEMA = 29 -app = Flask(__name__) -secure(app) - - class datetimeutc(datetime): # subclass of `datetime.datetime` with default string # representation including the timezone name @@ -34,17 +37,16 @@ # customize mysql types conversion for datetime fields to return # timezone aware objects in the UTC timezone def datetime_or_none_utc(s): - value = mysql.converters.DateTime_or_None(s) + value = converters.DateTime_or_None(s) if value is not None: value = datetimeutc(value.year, value.month, value.day, value.hour, value.minute, value.second, value.microsecond, tzinfo=dateutil.tz.tzutc()) return value -conversions = mysql.converters.conversions.copy() +conversions = converters.conversions.copy() conversions[mysql.constants.FIELD_TYPE.DATETIME] = datetime_or_none_utc -@app.before_request def before_request(): # get version information from package g.version = get_distribution('ltpdarepo').version @@ -54,8 +56,9 @@ return # open database connection - g.db = mysql.connect(host=app.config['HOSTNAME'], db=app.config['DATABASE'], - user=app.config['USERNAME'], passwd=app.config['PASSWORD'], + config = current_app.config + g.db = mysql.connect(host=config['HOSTNAME'], db=config['DATABASE'], + user=config['USERNAME'], passwd=config['PASSWORD'], charset='utf8', conv=conversions) # validate schema revision @@ -69,7 +72,6 @@ 'Required version: %s.

' % (g.schema, SCHEMA)) -@app.teardown_request def teardown_request(exception): # close database connection db = getattr(g, 'db', None) @@ -77,8 +79,7 @@ db.close() -# register error handlers -def _error_handler(error): +def error_handler(error): if not isinstance(error, HTTPException): # nicely report tracebacks import traceback @@ -86,15 +87,11 @@ error.description += '
' + traceback.format_exc() + '
' return render_template('error.html', error=error), error.code -for exc in default_exceptions: - app.error_handler_spec[None][exc] = _error_handler - -@app.template_filter('breadcrumbs') -def breadcrumbs(path): +def breadcrumbs(): url = [] parts = [] - for item in path.split('/')[1:-1]: + for item in request.path.split('/')[1:-1]: url.append(item) if item: parts.append((item, urljoin(url_for('index'), '/'.join(url)))) @@ -111,7 +108,6 @@ args.update(request.args) args.update(p=page) return url_for(request.endpoint, **args) -app.jinja_env.globals['url_for_other_page'] = url_for_other_page def url_for_other_order(field): @@ -123,7 +119,6 @@ args.update(request.args) args.update(o=field, r=int(reverse)) return url_for(request.endpoint, **args) -app.jinja_env.globals['url_for_other_order'] = url_for_other_order def url_for_other_size(size): @@ -131,7 +126,6 @@ args.update(request.args) args.update(n=size) return url_for(request.endpoint, **args) -app.jinja_env.globals['url_for_other_size'] = url_for_other_size def is_safe_url(target): @@ -140,57 +134,69 @@ return test.scheme in ('http', 'https') and test.netloc == ref.netloc -@app.route('/login', methods=['GET', 'POST']) -def login(): - if request.method == 'POST': - if authenticate(request.form['username'], request.form['password']): - session['username'] = request.form['username'] - target = request.args.get('next') - if not target or not is_safe_url(target): - target = url_for('index') - return redirect(target) - flash('Login failed.', category='error') +class Application(Flask): + def __init__(self, conf=None, **kwargs): + super(Application, self).__init__(__name__) + secure(self) - return render_template('login.html') - + # configuration + self.config.from_pyfile('config.py') + if conf is not None: + self.config.from_pyfile(conf) + self.config.update(kwargs) -@app.route('/logout') -def logout(): - session.pop('username', None) - return redirect(url_for('index')) - + @self.route('/') + @require('user') + def index(): + curs = g.db.cursor() + curs.execute("""SELECT DISTINCT Db FROM mysql.db, available_dbs + WHERE Select_priv='Y' AND User=%s AND Db=db_name + ORDER BY Db""", session['username']) + dbs = [row[0] for row in curs.fetchall()] + return render_template('index.html', databases=dbs) -@app.route('/') -@require('user') -def index(): - curs = g.db.cursor() - curs.execute("""SELECT DISTINCT Db FROM mysql.db, available_dbs - WHERE Select_priv='Y' AND User=%s AND Db=db_name - ORDER BY Db""", session['username']) - dbs = [row[0] for row in curs.fetchall()] - return render_template('index.html', databases=dbs) + @self.route('/login', methods=['GET', 'POST']) + def login(): + if request.method == 'POST': + if authenticate(request.form['username'], request.form['password']): + session['username'] = request.form['username'] + target = request.args.get('next') + if not target or not is_safe_url(target): + target = url_for('index') + return redirect(target) + flash('Login failed.', category='error') + return render_template('login.html') -from .views.browse import module -app.register_blueprint(module, url_prefix='/browse') + @self.route('/logout') + def logout(): + session.pop('username', None) + return redirect(url_for('index')) -from .views.feed import module, url_for_atom_feed -app.register_blueprint(module, url_prefix='/browse') -app.jinja_env.globals['url_for_atom_feed'] = url_for_atom_feed + # database connection + self.before_request(before_request) + self.teardown_request(teardown_request) -from .views.profile import module -app.register_blueprint(module, url_prefix='/user') + # template globals + self.jinja_env.globals['breadcrumbs'] = breadcrumbs + self.jinja_env.globals['url_for_other_page'] = url_for_other_page + self.jinja_env.globals['url_for_other_order'] = url_for_other_order + self.jinja_env.globals['url_for_other_size'] = url_for_other_size + self.jinja_env.globals['url_for_atom_feed'] = url_for_atom_feed -from .views.databases import module -app.register_blueprint(module, url_prefix='/manage/databases') + # error handlers + for exc in default_exceptions: + self.error_handler_spec[None][exc] = error_handler -from .views.queries import module -app.register_blueprint(module, url_prefix='/manage/queries') - -from .views.users import module -app.register_blueprint(module, url_prefix='/manage/users') + # blueprints + self.register_blueprint(browse, url_prefix='/browse') + self.register_blueprint(feed, url_prefix='/browse') + self.register_blueprint(profile, url_prefix='/user') + self.register_blueprint(databases, url_prefix='/manage/databases') + self.register_blueprint(queries, url_prefix='/manage/queries') + self.register_blueprint(users, url_prefix='/manage/users') def main(): - app.config.from_pyfile('config.py') + app = Application() app.run() diff -r 6bcf931c0e59 -r ac0a27a72b9e src/ltpdarepo/admin.py --- a/src/ltpdarepo/admin.py Tue Nov 15 19:15:58 2011 +0100 +++ b/src/ltpdarepo/admin.py Wed Nov 16 16:09:39 2011 +0100 @@ -19,14 +19,16 @@ except ImportError: HAS_SQL_ALCHEMY = False -from . import app -app.config.from_pyfile('config.py') from .user import User from .database import Database from .config import HOSTNAME, DATABASE, USERNAME, PASSWORD +from . import Application +app = Application() + + @contextmanager def interact(app): # fake request diff -r 6bcf931c0e59 -r ac0a27a72b9e src/ltpdarepo/templates/layout.html --- a/src/ltpdarepo/templates/layout.html Tue Nov 15 19:15:58 2011 +0100 +++ b/src/ltpdarepo/templates/layout.html Wed Nov 16 16:09:39 2011 +0100 @@ -22,7 +22,7 @@ {% block page %}
- +
{% if session.username is defined %} {{ session.username }}