aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPriit Laes <plaes@plaes.org>2010-07-17 23:30:46 +0300
committerPriit Laes <plaes@plaes.org>2010-07-17 23:30:46 +0300
commitca08281c1dedd5dfe026048a32641a29d1f013cb (patch)
tree5920e3c83c0a4f78cdbebd1156807bf488b96825
parentImprove wording for developer check QA issue info (diff)
downloadgsoc2010-grumpy-ca08281c1dedd5dfe026048a32641a29d1f013cb.tar.gz
gsoc2010-grumpy-ca08281c1dedd5dfe026048a32641a29d1f013cb.tar.bz2
gsoc2010-grumpy-ca08281c1dedd5dfe026048a32641a29d1f013cb.zip
Added OpenID login support
-rw-r--r--grumpy/models.py14
-rw-r--r--grumpy/templates/create_profile.html20
-rw-r--r--grumpy/templates/layout.html9
-rw-r--r--grumpy/templates/login.html13
-rw-r--r--grumpy/webapp.py63
5 files changed, 116 insertions, 3 deletions
diff --git a/grumpy/models.py b/grumpy/models.py
index 807557f..55019f0 100644
--- a/grumpy/models.py
+++ b/grumpy/models.py
@@ -187,3 +187,17 @@ class PkgIssue(db.Model):
def __repr__(self):
return '<%s> - %s : %s' % \
(self.__class__.__name__, self.plugin, self.type)
+
+class User(db.Model):
+ """User model"""
+ __tablename__ = 'users'
+
+ id = db.Column('id', db.Integer, primary_key=True)
+ regtoken = db.Column('token', db.String)
+ openid = db.Column('openid', db.String)
+ email = db.Column('user', db.String, unique=True)
+
+ def __init__(self, email, openid):
+ self.email = email
+ self.openid = openid
+ # TODO, generate token
diff --git a/grumpy/templates/create_profile.html b/grumpy/templates/create_profile.html
new file mode 100644
index 0000000..37f562d
--- /dev/null
+++ b/grumpy/templates/create_profile.html
@@ -0,0 +1,20 @@
+{% extends "layout.html" %}
+{% block title %}Create profile{% endblock %}
+{% block body %}
+ <h2>Create profile</h2>
+ <p>
+ Hey! This is a first time you signed in on this website. In order to proceed
+ we need some extra information from you:
+ <form action="" method=post>
+ <dl>
+ <dt>Gentoo developer email:
+ <dd><input type=text name=email size=30 value="{{ request.values.email }}">
+ </dl>
+ <p>
+ <input type=submit value="Create profile">
+ <input type=hidden name=next value="{{ next }}">
+ </form>
+ <p>
+ If you don't want to proceed, you can
+ <a href="{{ url_for('logout') }}">sign out</a> again.
+{% endblock %}
diff --git a/grumpy/templates/layout.html b/grumpy/templates/layout.html
index abd3001..e3d8ff2 100644
--- a/grumpy/templates/layout.html
+++ b/grumpy/templates/layout.html
@@ -2,6 +2,15 @@
<head>
<title>{% block title %}Welcome{% endblock %} | Grumpy</title>
</head>
+<div class=menu>
+ <ul>
+ {% if g.user %}
+ <li><a href="{{ url_for('logout') }}">Log out</a></li>
+ {% else %}
+ <li><a href="{{ url_for('login') }}">Login</a></li>
+ {% endif %}
+ </ul>
+</div>
<div class=page>
{% with flashes = get_flashed_messages() %}
{% if flashes %}
diff --git a/grumpy/templates/login.html b/grumpy/templates/login.html
new file mode 100644
index 0000000..cca3842
--- /dev/null
+++ b/grumpy/templates/login.html
@@ -0,0 +1,13 @@
+{% extends "layout.html" %}
+{% block title %}Sign in{% endblock %}
+{% block body %}
+ <h2>Sign in</h2>
+ <form action="" method=post>
+ {% if error %}<p class=error><strong>Error:</strong> {{ error }}</p>{% endif %}
+ <p>
+ OpenID:
+ <input type=text name=openid size=30>
+ <input type=submit value="Sign in">
+ <input type=hidden name=next value="{{ next }}">
+ </form>
+{% endblock %}
diff --git a/grumpy/webapp.py b/grumpy/webapp.py
index b33156b..b426cc8 100644
--- a/grumpy/webapp.py
+++ b/grumpy/webapp.py
@@ -9,10 +9,21 @@
:license: BSD, see LICENSE for details.
"""
from . import app
-from .models import Category, Package
+from .models import db, Category, Package, User
from .utils import requires_auth_basic
-from flask import flash, jsonify, redirect, render_template, url_for
+from flask import (flash, g, jsonify, redirect, render_template, request, \
+ session, url_for)
+from flaskext.openid import OpenID
+
+# OpenID support
+oid = OpenID(app)
+
+@app.before_request
+def before_request():
+ g.user = None
+ if 'openid' in session:
+ g.user = User.query.filter_by(openid=session['openid']).first()
@app.route('/')
@app.route('/browse/')
@@ -20,7 +31,6 @@ def index():
cats = Category.query.order_by(Category.cat.asc()).all()
return render_template('index.html', cats=cats)
-
@app.route('/browse/<cat>/')
def browse_cat(cat):
if cat:
@@ -42,6 +52,53 @@ def browse_pkg(cat, pkg):
flash('Package "%s/%s" does not exist' % (cat, pkg))
return redirect(url_for('browse_cat', cat=cat))
+@app.route('/login', methods=['GET', 'POST'])
+@oid.loginhandler
+def login():
+ if g.user is not None:
+ return redirect(oid.get_next_url())
+ if request.method == 'POST':
+ openid = request.form.get('openid')
+ if openid:
+ return oid.try_login(openid, ask_for=['email'])
+ return render_template('login.html', next=oid.get_next_url(),
+ error=oid.fetch_error())
+
+@app.route('/logout')
+def logout():
+ session.pop('openid', None)
+ flash(u'You have been signed out')
+ return redirect(oid.get_next_url())
+
+@oid.after_login
+def create_or_login(resp):
+ session['openid'] = resp.identity_url
+ user = User.query.filter_by(openid=resp.identity_url).first()
+ if user is not None:
+ flash(u'Successfully logged in')
+ g.user = user
+ return redirect(oid.get_next_url())
+ return redirect(url_for('create_profile', next=oid.get_next_url(),
+ email=resp.email))
+
+@app.route('/create-profile', methods=['GET', 'POST'])
+def create_profile():
+ if g.user is not None or 'openid' not in session:
+ return redirect(url_for('index'))
+ if request.method == 'POST':
+ email = request.form['email'].strip()
+ if not email:
+ flash(u'Error: you need to provide @gentoo.org email')
+ # XXX: remove plaes.org, that's for testing purposes ;)
+ elif not email.endswith(('@gentoo.org', '@plaes.org')):
+ flash(u'You need to be a valid Gentoo developer to sign up')
+ else:
+ flash(u'Profile successfully created')
+ db.session.add(User(email, session['openid']))
+ # TODO: send confirmation token with email
+ db.session.commit()
+ return render_template('create_profile.html', next=oid.get_next_url())
+
@app.route('/_api/1.0/tinderbox/')
@requires_auth_basic
def tinderbox_api():