Mercurial > piecrust2
changeset 601:effbc78b5528
admin: Better error reporting, general clean-up.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 24 Jan 2016 10:42:33 -0800 |
parents | c37307a72f79 |
children | c6bc0ef03f82 |
files | foodtruck/config.py foodtruck/configuration.py foodtruck/sites.py foodtruck/templates/error.html foodtruck/templates/install.html foodtruck/views/dashboard.py foodtruck/views/main.py foodtruck/web.py piecrust/commands/builtin/admin.py |
diffstat | 9 files changed, 258 insertions(+), 228 deletions(-) [+] |
line wrap: on
line diff
--- a/foodtruck/config.py Sun Jan 24 10:41:36 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -import os.path -import copy -import logging -import yaml -from piecrust.configuration import ( - Configuration, ConfigurationError, ConfigurationLoader, - merge_dicts) - - -logger = logging.getLogger(__name__) - - -def get_foodtruck_config(dirname=None): - dirname = dirname or os.getcwd() - cfg_path = os.path.join(dirname, 'foodtruck.yml') - return FoodTruckConfiguration(cfg_path) - - -class FoodTruckConfigNotFoundError(Exception): - pass - - -class FoodTruckConfiguration(Configuration): - def __init__(self, cfg_path): - super(FoodTruckConfiguration, self).__init__() - self.cfg_path = cfg_path - - def _load(self): - try: - with open(self.cfg_path, 'r', encoding='utf-8') as fp: - values = yaml.load( - fp.read(), - Loader=ConfigurationLoader) - - self._values = self._validateAll(values) - except OSError: - raise FoodTruckConfigNotFoundError() - except Exception as ex: - raise ConfigurationError( - "Error loading configuration from: %s" % - self.cfg_path) from ex - - def _validateAll(self, values): - if values is None: - values = {} - - values = merge_dicts(copy.deepcopy(default_configuration), values) - - return values - - def save(self): - with open(self.cfg_path, 'w', encoding='utf8') as fp: - self.cfg.write(fp) - - -default_configuration = { - 'triggers': { - 'bake': 'chef bake' - }, - 'scm': { - 'type': 'hg' - }, - 'security': { - 'username': '', - 'password': '' - } - } -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foodtruck/configuration.py Sun Jan 24 10:42:33 2016 -0800 @@ -0,0 +1,68 @@ +import os.path +import copy +import logging +import yaml +from piecrust.configuration import ( + Configuration, ConfigurationError, ConfigurationLoader, + merge_dicts) + + +logger = logging.getLogger(__name__) + + +def get_foodtruck_config(dirname=None): + dirname = dirname or os.getcwd() + cfg_path = os.path.join(dirname, 'foodtruck.yml') + return FoodTruckConfiguration(cfg_path) + + +class FoodTruckConfigNotFoundError(Exception): + pass + + +class FoodTruckConfiguration(Configuration): + def __init__(self, cfg_path): + super(FoodTruckConfiguration, self).__init__() + self.cfg_path = cfg_path + + def _load(self): + try: + with open(self.cfg_path, 'r', encoding='utf-8') as fp: + values = yaml.load( + fp.read(), + Loader=ConfigurationLoader) + + self._values = self._validateAll(values) + except OSError: + raise FoodTruckConfigNotFoundError() + except Exception as ex: + raise ConfigurationError( + "Error loading configuration from: %s" % + self.cfg_path) from ex + + def _validateAll(self, values): + if values is None: + values = {} + + values = merge_dicts(copy.deepcopy(default_configuration), values) + + return values + + def save(self): + with open(self.cfg_path, 'w', encoding='utf8') as fp: + self.cfg.write(fp) + + +default_configuration = { + 'triggers': { + 'bake': 'chef bake' + }, + 'scm': { + 'type': 'hg' + }, + 'security': { + 'username': '', + 'password': '' + } + } +
--- a/foodtruck/sites.py Sun Jan 24 10:41:36 2016 -0800 +++ b/foodtruck/sites.py Sun Jan 24 10:42:33 2016 -0800 @@ -6,6 +6,7 @@ import threading import subprocess from piecrust.app import PieCrust +from piecrust.configuration import merge_dicts logger = logging.getLogger(__name__) @@ -15,6 +16,10 @@ pass +class InvalidSiteError(Exception): + pass + + class Site(object): def __init__(self, name, root_dir, config): self.name = name @@ -48,7 +53,7 @@ elif global_scm_cfg: cfg = copy.deepcopy(global_scm_cfg) - if not cfg or not 'type' in cfg: + if not cfg or 'type' not in cfg: raise Exception("No SCM available for site: %s" % self.name) if cfg['type'] == 'hg': @@ -134,12 +139,12 @@ scfg = self.config.get('sites/%s' % name) if scfg is None: - raise Exception("No such site: %s" % name) + raise InvalidSiteError("No such site: %s" % name) root_dir = scfg.get('path') if root_dir is None: - raise Exception("Site '%s' has no path defined." % name) + raise InvalidSiteError("Site '%s' has no path defined." % name) if not os.path.isdir(root_dir): - raise Exception("Site '%s' has an invalid path." % name) + raise InvalidSiteError("Site '%s' has an invalid path." % name) self._site_dirs[name] = root_dir return root_dir
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foodtruck/templates/error.html Sun Jan 24 10:42:33 2016 -0800 @@ -0,0 +1,13 @@ +{% set title = 'An Error Occured' %} + +{% extends 'layouts/master.html' %} + +{% block content %} +<div class="container"> + {% if error == 'invalid_site' %} + <p>There was an error with your configuration file: {{exception}}</p> + {% endif %} +</div> +{% endblock %} + +
--- a/foodtruck/templates/install.html Sun Jan 24 10:41:36 2016 -0800 +++ b/foodtruck/templates/install.html Sun Jan 24 10:42:33 2016 -0800 @@ -1,8 +1,10 @@ -{% extends 'layouts/default.html' %} +{% set title = 'Configuration File Missing' %} + +{% extends 'layouts/master.html' %} {% block content %} <div class="container"> -Please install this shit. + No FoodTruck configuration file was found. Did you run <code>chef admin init</code>? </div> {% endblock %}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foodtruck/views/dashboard.py Sun Jan 24 10:42:33 2016 -0800 @@ -0,0 +1,146 @@ +import os +import os.path +import logging +from flask import ( + g, request, + render_template, url_for, redirect) +from flask.ext.login import login_user, logout_user, login_required +from piecrust.configuration import parse_config_header +from piecrust.rendering import QualifiedPage +from piecrust.uriutil import split_uri +from ..textutil import text_preview +from ..views import with_menu_context +from ..web import app, load_user, after_this_request + + +logger = logging.getLogger(__name__) + + +@app.route('/') +@login_required +def index(): + data = {} + site_name = request.cookies.get('foodtruck_site_name') + site = g.sites.get(site_name) + assert site is not None + + fs_endpoints = {} + data['sources'] = [] + for source in site.piecrust_app.sources: + if source.is_theme_source: + continue + facs = source.getPageFactories() + src_data = { + 'name': source.name, + 'list_url': url_for('list_source', source_name=source.name), + 'page_count': len(facs)} + data['sources'].append(src_data) + + fe = getattr(source, 'fs_endpoint', None) + if fe: + fs_endpoints[fe] = source + + st = site.scm.getStatus() + data['new_pages'] = [] + for p in st.new_files: + pd = _getWipData(p, site, fs_endpoints) + if pd: + data['new_pages'].append(pd) + data['edited_pages'] = [] + for p in st.edited_files: + pd = _getWipData(p, site, fs_endpoints) + if pd: + data['edited_pages'].append(pd) + + data['site_name'] = site.name + data['site_title'] = site.piecrust_app.config.get('site/title', site.name) + data['url_bake'] = url_for('bake_site') + data['url_preview'] = url_for('preview_site_root', sitename=site.name) + + data['sites'] = [] + for k, v in g.config.get('sites').items(): + data['sites'].append({ + 'name': k, + 'display_name': v.get('name', k), + 'url': url_for('index', site_name=site_name) + }) + data['needs_switch'] = len(g.config.get('sites')) > 1 + data['url_switch'] = url_for('switch_site') + + with_menu_context(data) + return render_template('dashboard.html', **data) + + +def _getWipData(path, site, fs_endpoints): + source = None + for endpoint, s in fs_endpoints.items(): + if path.startswith(endpoint): + source = s + break + if source is None: + return None + + fac = source.buildPageFactory(os.path.join(site.root_dir, path)) + route = site.piecrust_app.getRoute( + source.name, fac.metadata, skip_taxonomies=True) + if not route: + return None + + qp = QualifiedPage(fac.buildPage(), route, fac.metadata) + uri = qp.getUri() + _, slug = split_uri(site.piecrust_app, uri) + + with open(fac.path, 'r', encoding='utf8') as fp: + raw_text = fp.read() + + header, offset = parse_config_header(raw_text) + extract = text_preview(raw_text, offset=offset) + return { + 'title': qp.config.get('title'), + 'slug': slug, + 'url': url_for('edit_page', slug=slug), + 'text': extract + } + + +@login_required +@app.route('/switch_site', methods=['POST']) +def switch_site(): + site_name = request.form.get('site_name') + if not site_name: + return redirect(url_for('index')) + + @after_this_request + def _save_site(resp): + resp.set_cookie('foodtruck_site_name', site_name) + + return redirect(url_for('index')) + + +@app.route('/login', methods=['GET', 'POST']) +def login(): + data = {} + + if request.method == 'POST': + username = request.form.get('username') + password = request.form.get('password') + remember = request.form.get('remember') + + user = load_user(username) + if user is not None and app.bcrypt: + if app.bcrypt.check_password_hash(user.password, password): + login_user(user, remember=bool(remember)) + return redirect(url_for('index')) + data['message'] = ( + "User '%s' doesn't exist or password is incorrect." % + username) + + return render_template('login.html', **data) + + +@app.route('/logout') +@login_required +def logout(): + logout_user() + return redirect(url_for('index')) +
--- a/foodtruck/views/main.py Sun Jan 24 10:41:36 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,146 +0,0 @@ -import os -import os.path -import logging -from flask import ( - g, request, - render_template, url_for, redirect) -from flask.ext.login import login_user, logout_user, login_required -from piecrust.configuration import parse_config_header -from piecrust.rendering import QualifiedPage -from piecrust.uriutil import split_uri -from ..textutil import text_preview -from ..views import with_menu_context -from ..web import app, load_user, after_this_request - - -logger = logging.getLogger(__name__) - - -@app.route('/') -@login_required -def index(): - data = {} - site_name = request.cookies.get('foodtruck_site_name') - site = g.sites.get(site_name) - assert site is not None - - fs_endpoints = {} - data['sources'] = [] - for source in site.piecrust_app.sources: - if source.is_theme_source: - continue - facs = source.getPageFactories() - src_data = { - 'name': source.name, - 'list_url': url_for('list_source', source_name=source.name), - 'page_count': len(facs)} - data['sources'].append(src_data) - - fe = getattr(source, 'fs_endpoint', None) - if fe: - fs_endpoints[fe] = source - - st = site.scm.getStatus() - data['new_pages'] = [] - for p in st.new_files: - pd = _getWipData(p, site, fs_endpoints) - if pd: - data['new_pages'].append(pd) - data['edited_pages'] = [] - for p in st.edited_files: - pd = _getWipData(p, site, fs_endpoints) - if pd: - data['edited_pages'].append(pd) - - data['site_name'] = site.name - data['site_title'] = site.piecrust_app.config.get('site/title', site.name) - data['url_bake'] = url_for('bake_site') - data['url_preview'] = url_for('preview_site_root', sitename=site.name) - - data['sites'] = [] - for k, v in g.config.get('sites').items(): - data['sites'].append({ - 'name': k, - 'display_name': v.get('name', k), - 'url': url_for('index', site_name=site_name) - }) - data['needs_switch'] = len(g.config.get('sites')) > 1 - data['url_switch'] = url_for('switch_site') - - with_menu_context(data) - return render_template('dashboard.html', **data) - - -def _getWipData(path, site, fs_endpoints): - source = None - for endpoint, s in fs_endpoints.items(): - if path.startswith(endpoint): - source = s - break - if source is None: - return None - - fac = source.buildPageFactory(os.path.join(site.root_dir, path)) - route = site.piecrust_app.getRoute( - source.name, fac.metadata, skip_taxonomies=True) - if not route: - return None - - qp = QualifiedPage(fac.buildPage(), route, fac.metadata) - uri = qp.getUri() - _, slug = split_uri(site.piecrust_app, uri) - - with open(fac.path, 'r', encoding='utf8') as fp: - raw_text = fp.read() - - header, offset = parse_config_header(raw_text) - extract = text_preview(raw_text, offset=offset) - return { - 'title': qp.config.get('title'), - 'slug': slug, - 'url': url_for('edit_page', slug=slug), - 'text': extract - } - - -@login_required -@app.route('/switch_site', methods=['POST']) -def switch_site(): - site_name = request.form.get('site_name') - if not site_name: - return redirect(url_for('index')) - - @after_this_request - def _save_site(resp): - resp.set_cookie('foodtruck_site_name', site_name) - - return redirect(url_for('index')) - - -@app.route('/login', methods=['GET', 'POST']) -def login(): - data = {} - - if request.method == 'POST': - username = request.form.get('username') - password = request.form.get('password') - remember = request.form.get('remember') - - user = load_user(username) - if user is not None and app.bcrypt: - if app.bcrypt.check_password_hash(user.password, password): - login_user(user, remember=bool(remember)) - return redirect(url_for('index')) - data['message'] = ( - "User '%s' doesn't exist or password is incorrect." % - username) - - return render_template('login.html', **data) - - -@app.route('/logout') -@login_required -def logout(): - logout_user() - return redirect(url_for('index')) -
--- a/foodtruck/web.py Sun Jan 24 10:41:36 2016 -0800 +++ b/foodtruck/web.py Sun Jan 24 10:42:33 2016 -0800 @@ -2,9 +2,9 @@ import os.path import logging from flask import Flask, g, request, render_template -from .config import ( +from .configuration import ( FoodTruckConfigNotFoundError, get_foodtruck_config) -from .sites import FoodTruckSites +from .sites import FoodTruckSites, InvalidSiteError logger = logging.getLogger(__name__) @@ -55,7 +55,8 @@ if current is None: names = g.config.get('sites') if not names or not isinstance(names, dict): - raise FoodTruckConfigNotFoundError() + raise InvalidSiteError( + "No sites are defined in the configuration file.") current = next(iter(names.keys())) s = FoodTruckSites(g.config, current) return s @@ -71,9 +72,17 @@ return response -@app.errorhandler(FoodTruckConfigNotFoundError) -def _on_config_missing(ex): - return render_template('install.html') +if not app.config['DEBUG']: + app.logger.debug("Registering exception handlers.") + + @app.errorhandler(FoodTruckConfigNotFoundError) + def _on_config_missing(ex): + return render_template('install.html') + + @app.errorhandler(InvalidSiteError) + def _on_invalid_site(ex): + data = {'error': 'invalid_site', 'exception': str(ex)} + return render_template('error.html', **data) @app.errorhandler @@ -132,8 +141,8 @@ import foodtruck.views.baking # NOQA import foodtruck.views.create # NOQA +import foodtruck.views.dashboard # NOQA import foodtruck.views.edit # NOQA -import foodtruck.views.main # NOQA import foodtruck.views.menu # NOQA import foodtruck.views.preview # NOQA import foodtruck.views.settings # NOQA
--- a/piecrust/commands/builtin/admin.py Sun Jan 24 10:41:36 2016 -0800 +++ b/piecrust/commands/builtin/admin.py Sun Jan 24 10:42:33 2016 -0800 @@ -41,6 +41,7 @@ def _runFoodTruck(self, ctx): from foodtruck import settings settings.FOODTRUCK_CMDLINE_MODE = True + settings.FOODTRUCK_ROOT = os.getcwd() from foodtruck.main import run_foodtruck run_foodtruck(debug=ctx.args.debug) @@ -76,7 +77,7 @@ fp.write(ft_config) flask_config = """ -secret_key = '%(secret_key)s' +SECRET_KEY = %(secret_key)s """ flask_config = flask_config % {'secret_key': secret_key} with open('app.cfg', 'w', encoding='utf8') as fp: