Mercurial > farol
changeset 12:4219d6fb4c38
Implement three kind of caches
author | Benoît Allard <benoit.allard@greenbone.net> |
---|---|
date | Tue, 30 Sep 2014 12:18:52 +0200 |
parents | a32f9b86edb4 |
children | d5265a0da13a |
files | CHANGES farol/cache.py farol/config.py farol/main.py farol/session.py farol/templates/about.j2 farol/templates/base.j2 farol/templates/cache/load.j2 farol/templates/cache/save.j2 farol/templates/document/edit_tracking.j2 farol/templates/load.j2 farol/templates/new.j2 farol/templates/producttree/edit_product.j2 farol/templates/save.j2 |
diffstat | 14 files changed, 238 insertions(+), 136 deletions(-) [+] |
line wrap: on
line diff
--- a/CHANGES Mon Sep 29 14:19:07 2014 +0200 +++ b/CHANGES Tue Sep 30 12:18:52 2014 +0200 @@ -1,10 +1,20 @@ Farol 0.1.1 (2014-??-??) ======================== +This is the first patch release of Farol 0.1, it fixes various issues, and +improve usability. + + +Thanks to all the contributors: +Michael Wiegand and Benoît Allard. + Main changes since 0.1: ----------------------- -* Ease the import of documents +* Ease the import of documents, with various shortcuts * Add a Welcome page +* Add loging of the exceptions to a farol.log file (in the instance dir) +* Implement three different kind of 'caching': disableds, global or + session-based. Farol 0.1 (2014-09-24)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/farol/cache.py Tue Sep 30 12:18:52 2014 +0200 @@ -0,0 +1,117 @@ +# -*- encoding: utf-8 -*- +# Description: +# Web stuff related to the cache. +# +# Authors: +# Benoît Allard <benoit.allard@greenbone.net> +# +# Copyright: +# Copyright (C) 2014 Greenbone Networks GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + +"""\ +The caching stuff ... +""" + +import os + +from flask import (Blueprint, current_app, session, flash, redirect, url_for, + render_template, request) +from werkzeug import secure_filename + +from farolluz.parsers.cvrf import parse +from farolluz.renderer import render + +from .session import get_current, set_current, del_current, has_current, document_required + +mod = Blueprint('cache', __name__) + +def caching_type(): + """\ + Returns the type of caching we are using: + None, 'session' or 'global' + """ + c_type = current_app.config.get('CACHING', 'global') + return {'disabled': None}.get(c_type, c_type) + +def _caching_dir(): + """\ + Returns the current caching directory + """ + c_type = caching_type() + if c_type is None: return None + root_dir = current_app.config.get('CACHE_DIRECTORY', + os.path.join(current_app.instance_path, '_cache')) + if c_type == 'global': return root_dir + uid = session.get('id') + # No uid yet, so no cache ... + if uid is None: return None + return os.path.join(root_dir, uid.hex) + +def cache_content(): + """\ + The content of the cache + """ + dirname = _caching_dir() + if dirname is None: return [] + if not os.path.exists(dirname): + os.makedirs(dirname) + l = [] + for path in os.listdir(dirname): + name, ext = os.path.splitext(path) + if ext == '.xml': + l.append(name) + return l + +def cleanup_cache(): + """\ + Remove old documents ... maybe ... from time to time ... + """ + pass + +@mod.route('/save', methods=['GET', 'POST']) +@document_required +def save(): + if request.method != 'POST': + return render_template('cache/save.j2', + id_=get_current()._tracking._identification._id) + # Get some kind of filename, and save the cvrf on cache (disk) + path = secure_filename(request.form['fname']) + path, _ = os.path.splitext(path) + dirname = _caching_dir() + with open(os.path.join(dirname, path + '.xml'), 'wt') as f: + f.write(render(get_current(), 'cvrf.j2').encode('utf-8')) + flash('File saved as %s' % path) + del_current() + return redirect(url_for('new')) + +@mod.route('/load/<element>', methods=['GET', 'POST']) +def load(element): + if request.method != 'POST': + if has_current(): + # Suggest to save first + return render_template('cache/load.j2', element=element) + + # Ouch, GET request changing state of the server ... + + dirname = _caching_dir() + fpath = os.path.join(dirname, element+'.xml') + with open(fpath, 'rt') as f: + set_current(parse(f)) + os.remove(fpath) + flash('"%s" has been removed from cache' % element) + # Get some kind of id, and load the file. + return redirect(url_for('document.view'))
--- a/farol/config.py Mon Sep 29 14:19:07 2014 +0200 +++ b/farol/config.py Tue Sep 30 12:18:52 2014 +0200 @@ -29,4 +29,5 @@ """ the default configuration """ DEBUG=True SECRET_KEY=os.urandom(24) +# CACHING='disabled'
--- a/farol/main.py Mon Sep 29 14:19:07 2014 +0200 +++ b/farol/main.py Tue Sep 30 12:18:52 2014 +0200 @@ -33,8 +33,9 @@ from flask import Flask, request, render_template, redirect, url_for, flash from werkzeug import secure_filename +from . import cache from .document import document -from .session import get_current, set_current, has_current, del_current, document_required +from .session import get_current, set_current, has_current, document_required from .vulnerability import vulnerability from .producttree import producttree @@ -42,6 +43,7 @@ app.config.from_object('farol.config.Config') app.config.from_pyfile('farol.cfg', silent=True) +app.register_blueprint(cache.mod, url_prefix='/cache') app.register_blueprint(document, url_prefix='/document') app.register_blueprint(vulnerability, url_prefix='/vulnerability') app.register_blueprint(producttree, url_prefix='/producttree') @@ -56,16 +58,8 @@ @app.context_processor def cache_content(): """ List the documents in cache """ - dirname = app.config.get('CACHE_DIRECTORY', - os.path.join(app.instance_path, '_cache')) - if not os.path.exists(dirname): - os.makedirs(dirname) - l = [] - for path in os.listdir(dirname): - name, ext = os.path.splitext(path) - if ext == '.xml': - l.append(name) - return dict(cache=l) + return dict(caching=cache.caching_type(), + cache=cache.cache_content()) @app.context_processor def doc_properties(): @@ -98,7 +92,7 @@ def new(): if request.method != 'POST': return render_template('new.j2', has_document=has_current(), now=utcnow()) - url = None + if 'rhsa' in request.form: year, index = request.form['id'].split(':') parse_url("https://www.redhat.com/security/data/cvrf/%(year)s/cvrf-rhsa-%(year)s-%(index)s.xml" % {'year': year, 'index': index}) @@ -136,39 +130,6 @@ doc = render_cvrf(cvrf, format_ + '.j2') return render_template('render.j2', format_=format_, title=cvrf._title, type_=cvrf._type, doc=doc ) -@app.route('/save', methods=['GET', 'POST']) -@document_required -def save(): - if request.method != 'POST': - return render_template('save.j2', id_=get_current()._tracking._identification._id) - # Get some kind of filename, and save the cvrf on cache (disk) - path = secure_filename(request.form['fname']) - path, _ = os.path.splitext(path) - dirname = app.config.get('CACHE_DIRECTORY', - os.path.join(app.instance_path, '_cache')) - with open(os.path.join(dirname, path + '.xml'), 'wt') as f: - f.write(render_cvrf(get_current(), 'cvrf.j2').encode('utf-8')) - flash('File saved as %s' % path) - del_current() - return redirect(url_for('new')) - -@app.route('/load/<element>', methods=['GET', 'POST']) -def load(element): - if request.method != 'POST': - if has_current(): - # Suggest to save first - return render_template('load.j2', element=element) - - dirname = app.config.get('CACHE_DIRECTORY', - os.path.join(app.instance_path, '_cache')) - fpath = os.path.join(dirname, element+'.xml') - with open(fpath, 'rt') as f: - set_current(parse(f)) - os.remove(fpath) - flash('"%s" has been removed from cache' % element) - # Get some kind of id, and load the file. - return redirect(url_for('document.view')) - @app.route('/about') def about(): return render_template('about.j2', instance_dir=app.instance_path)
--- a/farol/session.py Mon Sep 29 14:19:07 2014 +0200 +++ b/farol/session.py Tue Sep 30 12:18:52 2014 +0200 @@ -34,7 +34,9 @@ CVRFs = {} def set_current(cvrf): - session['id'] = uuid.uuid4() + if 'id' not in session: + # New user. + session['id'] = uuid.uuid4() CVRFs[session['id']] = cvrf def get_current(): @@ -52,8 +54,6 @@ if 'id' in session: if session['id'] in CVRFs: del CVRFs[session['id']] - del session['id'] - def document_required(f): @wraps(f)
--- a/farol/templates/about.j2 Mon Sep 29 14:19:07 2014 +0200 +++ b/farol/templates/about.j2 Tue Sep 30 12:18:52 2014 +0200 @@ -38,11 +38,20 @@ <p>This platform is meant as a way to review / create / edit / publish Security Advisories in an accessible way</p> <p>In the current version, Advisories not currently saved are kept in memory of the running process. If the process terminates, and they are not saved, documents are lost.</p> {% if config.DEBUG and not config.DEBUG_SURE %} + <hr> + <h3 id="debug">Debug Mode</h3> + <p>Your application is Running in Debug mode. While this might be a choice you made, this is not suitable for Production deployment. The <a href="/console">console</a> is an example of unsafe debug facilities.</p> + <p>You can turn the Debug mode off by setting <code>DEBUG=False</code> in the configuration file located at the following path: <code>{{ instance_dir }}/farol.cfg</code>.</p> + <p>If you want to remove this message and the DEBUG Footer alert, but still want to keep the Debug mode on, just set <code>DEBUG_SURE=True</code> in your configuration file.</p> + {% endif %} <hr> - <h3 id="debug">Debug Mode</h3> - <p>Your application is Running in Debug mode. While this might be a choice you made, this is not suitable for Production deployment. The <a href="/console">console</a> is an example of unsafe debug facilities.</p> - <p>You can turn the Debug mode off by setting <code>DEBUG=False</code> in the configuration file located at the following path: <code>{{ instance_dir }}/farol.cfg</code>.</p> - <p>If you want to remove this message and the DEBUG Footer alert, but still want to keep the Debug mode on, just set <code>DEBUG_SURE=True</code> in your configuration file.</p> + <h3 id="caching">Document cache</h3> + {% if not caching %} + <p class="text-muted">Document cache is <strong>disabled</strong> by configuration.</p> + {% elif caching == 'global' %} + <p>All user share a <strong>global cache</strong>.</p> + {% else %} + <p>Each session have a <strong>private cache</strong>, sessions are bound to a browser <em>session</em>. They are usually reset when the browser is restarted.</p> {% endif %} <hr> <p><strong>Farol</strong> is published under GPLv2+, and is Copyright © Greenbone Networks GmbH.</p>
--- a/farol/templates/base.j2 Mon Sep 29 14:19:07 2014 +0200 +++ b/farol/templates/base.j2 Tue Sep 30 12:18:52 2014 +0200 @@ -90,17 +90,19 @@ {% for format in ('cvrf', 'nasl', 'oval') %}<li><a href="{{ url_for('render', format_=format)}}">as {{ format | upper }}</a></li>{% endfor %} </ul> </li> + {% if caching %} <li> - <form action="{{ url_for('save') }}"> + <form action="{{ url_for('cache.save') }}"> <button class="btn btn-success navbar-btn"{% if not has_current %} disabled="disabled"{% endif %}>Save</button> </form> </li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">Cache <span class="caret"></span></a> <ul class="dropdown-menu" role="menu"> - {% for element in cache | sort %}<li><a href="{{ url_for('load', element=element)}}">{{ element }}</a></li>{% endfor %} + {% for element in cache | sort %}<li><a href="{{ url_for('cache.load', element=element)}}">{{ element }}</a></li>{% endfor %} </ul> </li> + {% endif %} </ul> </div>{# /.navbar-collapse #} </div>{# /.container-fluid #}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/farol/templates/cache/load.j2 Tue Sep 30 12:18:52 2014 +0200 @@ -0,0 +1,36 @@ +{# +# Description: +# Web Template used in Farol Design +# +# Authors: +# Benoît Allard <benoit.allard@greenbone.net> +# +# Copyright: +# Copyright (C) 2014 Greenbone Networks GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +-#} + +{% extends "base.j2" %} +{% from "macros.j2" import textinput %} +{% block title %}Edit the title{% endblock %} + +{% block content %} +<p>You asked to load {{ element }}, but you still have an unsaved document loaded. Do you want to <a href="{{ url_for('.save') }}">save</a> it first ?</p> +<form role="form" method="POST"> +<button class="btn btn-primary" type="submit">Load "{{ element }}"</button> +<a class="btn btn-danger" href="{{ url_for('welcome') }}">Cancel</a> +</form> +{% endblock %}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/farol/templates/cache/save.j2 Tue Sep 30 12:18:52 2014 +0200 @@ -0,0 +1,36 @@ +{# +# Description: +# Web Template used in Farol Design +# +# Authors: +# Benoît Allard <benoit.allard@greenbone.net> +# +# Copyright: +# Copyright (C) 2014 Greenbone Networks GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +-#} + +{% extends "base.j2" %} +{% from "macros.j2" import textinput %} +{% block title %}Save{% endblock %} + +{% block content %} +<form role="form" method="POST"> +{{ textinput("fname", "File name", "doc1", id_, required=True) }} +<button class="btn btn-primary" type="submit">Save</button> +<a class="btn btn-danger" href="{{ url_for('document.view') }}">Cancel</a> +</form> +{% endblock %}
--- a/farol/templates/document/edit_tracking.j2 Mon Sep 29 14:19:07 2014 +0200 +++ b/farol/templates/document/edit_tracking.j2 Tue Sep 30 12:18:52 2014 +0200 @@ -31,7 +31,8 @@ <form role="form" method="POST"> {{ textinput("id", "ID", value=tracking._identification._id, required=True) }} -{{ textinput("id_aliases", "Aliases", value=', '.join(tracking._identification._aliases)) }} +{{ textinput("id_aliases", "Aliases", value=', '.join(tracking._identification._aliases), + help="Multiple aliases should be separated by commas.") }} {{ selectinput("status", "Status", statuses, tracking._status) }} {{ textinput("version", "Version", value=version, required=True) }} {{ textinput("initial", "Initial Release Date", value=tracking._initialDate.isoformat(), required=True, type="datetime") }}
--- a/farol/templates/load.j2 Mon Sep 29 14:19:07 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -{# -# Description: -# Web Template used in Farol Design -# -# Authors: -# Benoît Allard <benoit.allard@greenbone.net> -# -# Copyright: -# Copyright (C) 2014 Greenbone Networks GmbH -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. --#} - -{% extends "base.j2" %} -{% from "macros.j2" import textinput %} -{% block title %}Edit the title{% endblock %} - -{% block content %} -<p>You asked to load {{ element }}, but you still have an unsaved document loaded. Do you want to <a href="{{ url_for('save') }}">save</a> it first ?</p> -<form role="form" method="POST"> -<button class="btn btn-primary" type="submit">Load "{{ element }}"</button> -<a class="btn btn-danger" href="{{ url_for('welcome') }}">Cancel</a> -</form> -{% endblock %}
--- a/farol/templates/new.j2 Mon Sep 29 14:19:07 2014 +0200 +++ b/farol/templates/new.j2 Tue Sep 30 12:18:52 2014 +0200 @@ -31,8 +31,8 @@ {% block title %}New{% endblock %} {% block content %} -{% if has_document %} -<p class="text-danger">You have an unsaved document, maybe you want to <a href={{ url_for('save') }}>save</a> it first ?</p> +{% if has_document and caching %} +<p class="text-danger">You have an unsaved document, maybe you want to <a href={{ url_for('cache.save') }}>save</a> it first ?</p> {% endif %} <h3>New Document</h3> @@ -156,10 +156,12 @@ </div> -{% call panel(heading="Load a document from the cache", title=4, collapsible=False) %} -<ul> -{% for element in cache | sort %}<li><a href="{{ url_for('load', element=element)}}">{{ element }}</a></li>{% endfor %} -</ul> -{% endcall %} +{% if caching %} + {% call panel(heading="Load a document from the cache", title=4, collapsible=False) %} + <ul> + {% for element in cache | sort %}<li><a href="{{ url_for('cache.load', element=element)}}">{{ element }}</a></li>{% endfor %} + </ul> + {% endcall %} +{% endif %} {% endblock %}
--- a/farol/templates/producttree/edit_product.j2 Mon Sep 29 14:19:07 2014 +0200 +++ b/farol/templates/producttree/edit_product.j2 Tue Sep 30 12:18:52 2014 +0200 @@ -37,7 +37,6 @@ {{ textinput('cpe', "CPE", placeholder="cpe:/a:...", value=product._cpe) }} <hr> {{ selectinput2('parent_branch', "Parent Branch", orphaned_leaves , product.getParentPath()) }} -<!-- {{ current_rel }} --> {{ selectinput2('parent_relationship', "Parent relationship", orphaned_relationships, current_rel) }} <button class="btn btn-primary" type="submit">{{ action }}</button>
--- a/farol/templates/save.j2 Mon Sep 29 14:19:07 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -{# -# Description: -# Web Template used in Farol Design -# -# Authors: -# Benoît Allard <benoit.allard@greenbone.net> -# -# Copyright: -# Copyright (C) 2014 Greenbone Networks GmbH -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. --#} - -{% extends "base.j2" %} -{% from "macros.j2" import textinput %} -{% block title %}Save{% endblock %} - -{% block content %} -<form role="form" method="POST"> -{{ textinput("fname", "File name", "doc1", id_, required=True) }} -<button class="btn btn-primary" type="submit">Save</button> -<a class="btn btn-danger" href="{{ url_for('document.view') }}">Cancel</a> -</form> -{% endblock %}