Changeset - e7297d65fa3b
[Not reviewed]
default
0 1 5
Dennis Fink - 11 years ago 2014-07-13 16:37:46
dennis.fink@c3l.lu
Implement worldmap stats
6 files changed with 186 insertions and 1 deletions:
0 comments (0 inline, 0 general)
ennstatus/stats/forms.py
Show inline comments
 
new file 100644
 
from flask_wtf import Form
 
from wtforms import SelectField
 
from wtforms.validators import DataRequired
 

	
 
STYLES = [
 
    ('default', 'Default'),
 
    ('light', 'Light'),
 
    ('neon', 'Neon'),
 
    ('light_red_blue', 'Red Blue'),
 
    ('dark_solarized', 'Dark Solarized'),
 
    ('light_solarized', 'Light Solarized'),
 
    ('dark_colorized', 'Dark Colorized'),
 
    ('light_colorized', 'Light Colorized'),
 
    ('turquoise', 'Turquoise'),
 
    ('green', 'Light green'),
 
    ('dark_green', 'Dark green'),
 
    ('dark_green_blue', 'Dark green blue'),
 
    ('blue', 'Blue'),
 
    ('solid_color', 'Solid Color'),
 
]
 

	
 
SERVER_TYPES = [
 
    ('all', 'All'),
 
    ('exit', 'Exit'),
 
    ('relay', 'Relay'),
 
    ('bridge', 'Bridge'),
 
]
 

	
 

	
 
class WorldmapStyleForm(Form):
 
    style = SelectField('Style',
 
                        validators=[DataRequired()],
 
                        choices=STYLES)
 
    server_type = SelectField('Server type',
 
                              validators=[DataRequired()],
 
                              choices=SERVER_TYPES)
ennstatus/stats/functions.py
Show inline comments
 
new file 100644
 
from collections import Counter, defaultdict
 

	
 
from flask import current_app
 

	
 
import pygal
 

	
 

	
 
from ennstatus.status.functions import split_all_servers_to_types
 

	
 
COUNTRIES_TO_ISO = dict(
 
    zip(pygal.i18n.COUNTRIES.values(), pygal.i18n.COUNTRIES.keys()))
 
COUNTRIES_TO_ISO['Isle of Man'] = 'gb'
 

	
 
def _make_country_list():
 

	
 
    servers = split_all_servers_to_types()
 
    countries = defaultdict(list)
 

	
 
    for key, value in servers.items():
 
        for server in value:
 
            country = COUNTRIES_TO_ISO[server['country']]
 
            countries[key].append(country)
 

	
 
    return countries
 

	
 

	
 
def make_worldmap(server_type, style):
 

	
 
    arguments = {
 
        'title': '%s nodes' % server_type.capitalize(),
 
        'style': pygal.style.styles[style],
 
        'legend_at_bottom': True,
 
        'disable_xml_declaration': True,
 
        'pretty_print': True,
 
    }
 

	
 
    countries = _make_country_list()
 

	
 
    exits_count = Counter(countries['Exit'])
 
    relays_count = Counter(countries['Relay'])
 
    bridges_count = Counter(countries['Bridge'])
 

	
 
    plot = pygal.Worldmap(**arguments)
 

	
 
    if server_type in ('all', 'exit'):
 
        plot.add('Exits', exits_count)
 

	
 
    if server_type in ('all', 'relay'):
 
        plot.add('Relays', relays_count)
 

	
 
    if server_type in ('all', 'bridge'):
 
        plot.add('Bridges', bridges_count)
 

	
 
    return plot
ennstatus/stats/views.py
Show inline comments
 
new file 100644
 
from flask import (Blueprint, render_template, request, current_app,
 
                   redirect, url_for)
 

	
 
from ennstatus.stats.functions import (make_worldmap, make_total_pie,
 
                                       make_type_pie)
 
from ennstatus.stats.forms import (WorldmapStyleForm)
 

	
 
stats_page = Blueprint('stats', __name__)
 

	
 

	
 
@stats_page.route('/')
 
def index():
 
    return render_template('stats/index.html')
 

	
 

	
 
@stats_page.route('/worldmap', methods=('GET', 'POST'))
 
def worldmap():
 

	
 
    current_app.logger.info('Handling worldmap')
 
    form = WorldmapStyleForm()
 
    style_choices = [choice[0] for choice in form.style.choices]
 
    server_choices = [choice[0] for choice in form.server_type.choices]
 

	
 
    if request.method == 'POST':
 
        current_app.logger.debug('Validating form')
 
        if form.validate_on_submit():
 
            style = form.style.data
 
            server_type = form.server_type.data
 
            return redirect(url_for('stats.worldmap', server_type=server_type,
 
                                    style=style))
 
    else:
 
        if 'style' in request.args:
 
            style = request.args['style']
 
            if style in style_choices:
 
                current_app.logger.info('Using style %s' % style)
 
            else:
 
                current_app.logger.warn('Style %s not found' % style)
 
                style = 'default'
 
        else:
 
            current_app.logger.info('Using default style')
 
            style = 'default'
 

	
 
        if 'server_type' in request.args:
 
            server_type = request.args['server_type']
 
            if server_type in server_choices:
 
                current_app.logger.info('Showing %s nodes' % server_type)
 
            else:
 
                current_app.logger.warn('Server type %s not found' % style)
 
                server_type = 'all'
 
        else:
 
            current_app.logger.info('Showing all servers')
 
            server_type = 'all'
 
            
 

	
 
    form.style.data = style
 
    form.server_type.data = server_type
 

	
 
    plot = make_worldmap(server_type, style)
 

	
 
    return render_template('stats/worldmap.html', plot=plot, form=form)
 

	
 

	
ennstatus/templates/stats/base.html
Show inline comments
 
new file 100644
 
{% extends "base.html" %}
 

	
 
{% block scripts %}
 
  {{ super() }}
 
  <script type="text/javascript" src="http://kozea.github.com/pygal.js/javascripts/svg.jquery.js"></script>
 
  <script type="text/javascript" src="http://kozea.github.com/pygal.js/javascripts/pygal-tooltips.js"></script>
 
{% endblock %}
ennstatus/templates/stats/worldmap.html
Show inline comments
 
new file 100644
 
{% extends "stats/base.html" %}
 

	
 
{% set title = "Worldmap" %}
 

	
 
{% block content %}
 
<div class="col-md-12">
 
  <div class="pull-right">
 
    <form class="form-inline" role="form" method="POST" action="/stats/worldmap">
 
      {{ form.hidden_tag() }}
 
      <div class="form-group">
 
        {{ form.style.label}}
 
        {{ form.style(_class="form-control") }}
 
        {{ form.server_type.label }}
 
        {{ form.server_type(_class="form-control") }}
 
      </div>
 
      <input type="submit" class="btn btn-primary btn-sm" value="Submit">
 
    </form>
 
  </div>
 
  <div class="clearfix"></div>
 
</div>
 
<div class="col-md-12">
 
  <figure>
 
    {{ plot.render()|safe }} 
 
  </figure>
 
</div>
 
{% endblock %}
requirements.in
Show inline comments
 
@@ -5,5 +5,5 @@ Flask-Mail==0.9.0
 
#Flask-SSLify==0.1.4
 
Flask==0.10.1
 
pygeoip==0.3.0
 
#pygal==1.2.1
 
pygal==1.2.1
 
#humanize==0.5
0 comments (0 inline, 0 general)