Add initial Flask implementation

このコミットが含まれているのは:
Jan Dittberner 2015-11-10 22:31:14 +01:00
コミット f63939cb03
8個のファイルの変更312行の追加1行の削除

12
config.py ノーマルファイル
ファイルの表示

@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
WTF_CSRF_ENABLED = False
# available languages
LANGUAGES = {
'en': 'English',
'de': 'Deutsch',
'fr': 'Français',
'id': 'Bahasa Indonesia',
'pt_BR': 'Portuguese (Brazil)'
}

ファイルの表示

@ -3,7 +3,7 @@
#
# Debian Member Portfolio Service package
#
# Copyright © 2009-2014 Jan Dittberner <jan@dittberner.info>
# Copyright © 2009-2015 Jan Dittberner <jan@dittberner.info>
#
# This file is part of the Debian Member Portfolio Service.
#
@ -20,3 +20,12 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
from flask import Flask
from flask.ext.babel import Babel
app = Flask(__name__)
babel = Babel(app)
app.config.from_object('config')
from debianmemberportfolio import views

35
debianmemberportfolio/forms.py ノーマルファイル
ファイルの表示

@ -0,0 +1,35 @@
from __future__ import unicode_literals
from flask.ext.wtf import Form
from wtforms import IntegerField, StringField
from wtforms.validators import (
AnyOf, DataRequired, Email, Length, Optional, Regexp
)
class FingerPrint(Regexp):
def __init__(self, **kwargs):
super(FingerPrint, self).__init__(r'^[a-fA-F0-9]*$', **kwargs)
class PlainText(Regexp):
def __init__(self, **kwargs):
super(PlainText, self).__init__(r'^[a-zA-Z\-0-9]*$')
class DeveloperData(Form):
email = StringField('email', validators=[DataRequired(), Email()])
name = StringField('name', validators=[DataRequired()])
gpgfp = StringField('gpgfp', validators=[
FingerPrint(),
Length(min=32, max=40)
])
username = StringField('username', validators=[PlainText()])
nonddemail = StringField('nonddemail', validators=[Email()])
aliothusername = StringField('aliothusername', validators=[PlainText()])
mode = StringField(
'mode', default='html',validators=[AnyOf(['json', 'html'])]
)
forumsid = IntegerField('forumsid', default=None, validators=[Optional()])
wikihomepage = StringField('wikihomepage', default=None, validators=[
Optional()])

48
debianmemberportfolio/templates/base.html ノーマルファイル
ファイルの表示

@ -0,0 +1,48 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
{# vim: ft=jinja
Base template for XHTML templates.
Copyright © 2009-2015 Jan Dittberner <jan@dittberner.info>
This file is part of the Debian Member Portfolio service.
Debian Member Portfolio service is free software: you can redistribute it
and/or modify it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Debian Member Portfolio service 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 Affero
General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>.
#}
<html>
<head>
<title>{% block title %}{{ _('Debian Member Portfolio Service') }}{% endblock %}</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='stylesheets/style.css') }}" />
{% block extrahead %}{% endblock %}
</head>
<body>
<div id="header">
<img alt="{{ _('Debian Logo') }}" id="debianlogo" src="{{ url_for('static', filename='images/openlogo-100.jpg') }}" height="100" width="100" />
<h1>{{ _('Debian Member Portfolio Service') }}</h1>
<p>{% trans %}This service has been inspired by Stefano Zacchiroli's <a href="https://wiki.debian.org/DDPortfolio">DDPortfolio page in the Debian Wiki</a>. You can create a set of customized links leading to a Debian Member's or package maintainer's information regarding Debian.{% endtrans %}</p>
<p><a class="FlattrButton" style="display:none" title="Debian Member Portfolio Service" href="{{ request.scheme }}://portfolio.debian.net/">Debian Member Portfolio Service</a></p>
</div>
<div id="content">
{% block body %}{% endblock %}
</div>
<div id="footer">
<img alt="{{ _('AGPL - Free Software') }}" id="agpllogo" src="{{ url_for('static', filename='images/agplv3-88x31.png') }}" width="88" height="31" />
<p>{% trans browseurl='http://debianstuff.dittberner.info/gitweb/?p=debianmemberportfolio.git;a=summary', cloneurl='http://debianstuff.dittberner.info/git/debianmemberportfolio.git', transifexurl='https://www.transifex.com/projects/p/debportfolioservice/' %}The service is available under the terms of the <a href="https://www.gnu.org/licenses/agpl.html">GNU Affero General Public License</a> as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. You can <a href="{{ browseurl }}" title="Gitweb repository browser URL">browse the source code</a> or clone it from <a href="{{ cloneurl }}" title="git clone URL">{{ cloneurl }}</a> using <a href="http://git-scm.com/">git</a>. If you want to translate this service to your language you can contribute at <a href="{{ transifexurl }}" title="Debian Member Portfolio Service at Transifex">Transifex</a>.{% endtrans %}</p>
<p>{{ _('Copyright © 2009-2015 Jan Dittberner') }}</p>
</div>
<script type="text/javascript">
var flattr_url = '{{ request.scheme }}://portfolio.debian.net/';
</script>
<script src="{{ request.scheme }}://api.flattr.com/js/0.6/load.js?mode=auto&amp;button=compact" type="text/javascript"></script>
</body>
</html>

40
debianmemberportfolio/templates/showform.html ノーマルファイル
ファイルの表示

@ -0,0 +1,40 @@
{% extends "base.html" %}
{#
Template for the data input form.
Copyright © 2009-2015 Jan Dittberner <jan@dittberner.info>
This file is part of the Debian Member Portfolio service.
Debian Member Portfolio service is free software: you can redistribute it
and/or modify it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Debian Member Portfolio service 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 Affero
General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>.
#}
{% block title %}{{ super()}} - {{ _('Enter your personal information') }}{% endblock %}
{% block extrahead %}{{ super() }}<script type="text/javascript" src="{{ url_for('static', filename='javascript/jquery/jquery.js') }}"></script>
<script type="text/javascript" src="{{ url_for('formhelper_js') }}"></script>
{% endblock %}
{% block body %}{{ super() }}
<form action="{{ url_for('urllist') }}" method="get">
<fieldset id="portfolio">
<legend>{{ _('Debian Member Portfolio') }}</legend>
<div id="emailfield"{% if form.email.errors %} class="witherrors"{% endif %}>
<label for="email">{{ _('Email address:') }}
{% if form.email.errors %}<br />
<span class="errormsg">{{ form.email.errors|join(', ') }}</span>
{% endif %}
</label><br />
{{ form.email }}<br />
</div>
</fieldset>
</form>
{% endblock %}

ファイルの表示

@ -0,0 +1,119 @@
{# vim: ft=jinja
Helper JavaScript for the data input form.
Copyright © 2009, 2010, 2015 Jan Dittberner <jan@dittberner.info>
This file is part of the Debian Member Portfolio service.
Debian Member Portfolio service is free software: you can redistribute it
and/or modify it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Debian Member Portfolio service 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 Affero
General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>.
#}
var defaulthiddendivs = new Array(
'#namefield', '#gpgfpfield', '#usernamefield', '#nonddemailfield',
'#aliothusernamefield', '#wikihomepagefield', '#forumsidfield');
var maskedfielddivs = new Array(
'#namefield', '#gpgfpfield', '#usernamefield', '#nonddemailfield',
'#aliothusernamefield', '#wikihomepagefield', '#forumsidfield');
var allfielddivs = new Array(
'#namefield', '#gpgfpfield', '#usernamefield', '#nonddemailfield',
'#aliothusernamefield', '#wikihomepagefield', '#forumsidfield');
function updateFields(data, textStatus) {
if (data.type == 2) { // DD
$('#name').attr('value', data.name).attr('readonly', 'readonly');
$('#gpgfp').attr('value', data.gpgfp);
$('#username').attr('value', data.username).attr(
'readonly', 'readonly');
$('#nonddemail').attr('value', data.email).focus();
$('#aliothusername').attr('value', data.username);
$('#wikihomepage').attr('value', data.wikihomepage);
$('#namefield').show();
$('#gpgfpfield').show();
$('#usernamefield').show();
$('#nonddemailfield').show();
$('#aliothusernamefield').show();
$('#wikihomepagefield').show();
$('#forumsidfield').show();
$('#nonddemail').focus().select();
} else if (data.type == 1) { // DM
$('#name').attr('value', data.name).attr('readonly', 'readonly');
$('#gpgfp').attr('value', data.gpgfp);
$('#username').attr('value', '');
$('#nonddemail').attr('value', data.email).focus();
$('#wikihomepage').attr('value', data.wikihomepage);
$('#namefield').show();
$('#gpgfpfield').show();
$('#usernamefield').hide();
$('#nonddemailfield').hide();
$('#aliothusernamefield').show();
$('#wikihomepagefield').show();
$('#forumsidfield').show();
$('#aliothusername').focus().select();
} else {
$('#nonddemail').attr('value', data.email);
$('#name').removeAttr('readonly');
$('#username').removeAttr('readonly').attr('value', '');
$('#gpgfp').attr('value', '');
$('#usernamefield').hide();
$('#gpgfpfield').hide();
$('#nonddemailfield').hide();
$('#namefield').show();
$('#aliothusernamefield').show();
$('#wikihomepagefield').show();
$('#forumsidfield').show();
$('#name').focus().select();
}
}
function onChangeShowAll(event) {
if ($('#showall').attr('checked')) {
for (var fielddiv in allfielddivs) {
$(allfielddivs[fielddiv]).show();
}
} else {
for (var fielddiv in maskedfielddivs) {
$(maskedfielddivs[fielddiv]).hide();
}
}
}
function onBlurEmail() {
if ($.trim($('#email').attr('value')).length > 0) {
$.ajax({
'url' : '{{ url_for("fetchdddata") }}',
'data' : {'email' : $('#email').attr('value')},
'dataType' : 'json',
'success' : updateFields,
'error' : function(request, textStatus, errorThrown) {
$('#email').focus();
}
});
}
}
$(document).ready(function() {
for (var index in defaulthiddendivs) {
if (!$(defaulthiddendivs[index]).hasClass('witherrors')) {
$(defaulthiddendivs[index]).hide();
}
}
$('#showall').attr('checked', false).change(onChangeShowAll);
$('#showallfield').show();
$('#email').blur(onBlurEmail).focus();
});

42
debianmemberportfolio/views.py ノーマルファイル
ファイルの表示

@ -0,0 +1,42 @@
from debianmemberportfolio import app, babel
from flask import g, make_response, request, render_template
from config import LANGUAGES
from .forms import DeveloperData
@babel.localeselector
def get_locale():
return request.accept_languages.best_match(LANGUAGES.keys())
@app.before_request
def before_request():
g.locale = get_locale()
@app.route('/')
def index():
form = DeveloperData()
# TODO: replicate behavior of
# debianmemberportfolio.controllers.portfolio.PortfolioController.index
return render_template('showform.html', form=form)
@app.route('/result')
def urllist():
form = DeveloperData(request.values)
if form.validate():
return render_template('showurls.html')
return render_template('showform.html', form=form)
@app.route('/htmlformhelper.js')
def formhelper_js():
response = make_response(render_template('showformscript.js'))
response.headers['Content-Type'] = 'text/javascript; charset=utf-8'
return response
@app.route('/showformscripts/fetchdddata/')
def fetchdddata():
return 'dddata'

6
run.py 実行可能ファイル
ファイルの表示

@ -0,0 +1,6 @@
#!/usr/bin/env python2
from debianmemberportfolio import app
if __name__ == '__main__':
app.debug = True
app.run()