+ Hey! This is the first time you signed in on this website. In
+ order to proceed we need some extra information from you:
+
+
+ If you don't want to proceed, you can sign out again.
+{% endblock %}
diff --git a/refstack/templates/edit_profile.html b/refstack/templates/edit_profile.html
new file mode 100644
index 00000000..a9b6b877
--- /dev/null
+++ b/refstack/templates/edit_profile.html
@@ -0,0 +1,16 @@
+{% extends "layout.html" %}
+{% block title %}Edit Profile{% endblock %}
+{% block body %}
+
Edit Profile
+
+{% endblock %}
diff --git a/refstack/templates/index.html b/refstack/templates/index.html
index dc05e9df..2342de64 100644
--- a/refstack/templates/index.html
+++ b/refstack/templates/index.html
@@ -1,11 +1,6 @@
-
-
-
- RefStack: What is it?
-
-
-
-
+{% extends "layout.html" %}
+{% block title %}Welcome{% endblock %}
+{% block body %}
@@ -33,5 +28,4 @@
-
-
\ No newline at end of file
+{% endblock %}
\ No newline at end of file
diff --git a/refstack/templates/layout.html b/refstack/templates/layout.html
new file mode 100644
index 00000000..92a0ecb4
--- /dev/null
+++ b/refstack/templates/layout.html
@@ -0,0 +1,19 @@
+
+{% block title %}Welcome{% endblock %} | RefStack
+
+
+
{{ message }}
+{% endfor %}
+{% block body %}{% endblock %}
diff --git a/refstack/templates/login.html b/refstack/templates/login.html
new file mode 100644
index 00000000..f319b31e
--- /dev/null
+++ b/refstack/templates/login.html
@@ -0,0 +1,13 @@
+{% extends "layout.html" %}
+{% block title %}Sign in{% endblock %}
+{% block body %}
+
Sign in
+
+{% endblock %}
diff --git a/refstack/web.py b/refstack/web.py
index aa4cfcac..d508e00d 100644
--- a/refstack/web.py
+++ b/refstack/web.py
@@ -8,6 +8,7 @@ import random
import sqlite3
import sys
from flask import Flask, flash, request, redirect, url_for, render_template, g, session
+from flask_openid import OpenID
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.admin import Admin, BaseView, expose
from flask.ext.admin.contrib.sqlamodel import ModelView
@@ -44,6 +45,9 @@ app.config['MAIL_USERNAME'] = 'postmaster@hastwoparents.com'
app.config['MAIL_PASSWORD'] = '0sx00qlvqbo3'
mail = Mail(app)
+
+# setup flask-openid
+oid = OpenID(app)
db = SQLAlchemy(app)
@@ -77,8 +81,29 @@ class Cloud(db.Model):
return '' % self.endpoint
+class User(db.Model):
+ id = db.Column(db.Integer, primary_key=True)
+ name = db.Column(db.String(60))
+ email = db.Column(db.String(200))
+ openid = db.Column(db.String(200), unique=True)
+
+ def __init__(self, name, email, openid):
+ self.name = name
+ self.email = email
+ self.openid = openid
+
+
admin = Admin(app)
admin.add_view(ModelView(Vendor, db.session))
+admin.add_view(ModelView(Cloud, db.session))
+admin.add_view(ModelView(User, db.session))
+
+
+@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('/', methods=['POST','GET'])
@@ -87,6 +112,100 @@ def index():
return render_template('index.html', vendors = vendors)
+@app.route('/login', methods=['GET', 'POST'])
+@oid.loginhandler
+def login():
+ """Does the login via OpenID. Has to call into `oid.try_login`
+ to start the OpenID machinery.
+ """
+ # if we are already logged in, go back to were we came from
+ 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', 'fullname',
+ 'nickname'])
+ return render_template('login.html', next=oid.get_next_url(),
+ error=oid.fetch_error())
+
+
+@oid.after_login
+def create_or_login(resp):
+ """This is called when login with OpenID succeeded and it's not
+ necessary to figure out if this is the users's first login or not.
+ This function has to redirect otherwise the user will be presented
+ with a terrible URL which we certainly don't want.
+ """
+ session['openid'] = resp.identity_url
+ user = User.query.filter_by(openid=resp.identity_url).first()
+ if user is not None:
+ flash(u'Successfully signed in')
+ g.user = user
+ return redirect(oid.get_next_url())
+ return redirect(url_for('create_profile', next=oid.get_next_url(),
+ name=resp.fullname or resp.nickname,
+ email=resp.email))
+
+
+@app.route('/create-profile', methods=['GET', 'POST'])
+def create_profile():
+ """If this is the user's first login, the create_or_login function
+ will redirect here so that the user can set up his profile.
+ """
+ if g.user is not None or 'openid' not in session:
+ return redirect(url_for('index'))
+ if request.method == 'POST':
+ name = request.form['name']
+ email = request.form['email']
+ if not name:
+ flash(u'Error: you have to provide a name')
+ elif '@' not in email:
+ flash(u'Error: you have to enter a valid email address')
+ else:
+ flash(u'Profile successfully created')
+ db.session.add(User(name, email, session['openid']))
+ db.session.commit()
+ return redirect(oid.get_next_url())
+ return render_template('create_profile.html', next_url=oid.get_next_url())
+
+
+@app.route('/profile', methods=['GET', 'POST'])
+def edit_profile():
+ """Updates a profile"""
+ if g.user is None:
+ abort(401)
+ form = dict(name=g.user.name, email=g.user.email)
+ if request.method == 'POST':
+ if 'delete' in request.form:
+ db.session.delete(g.user)
+ db.session.commit()
+ session['openid'] = None
+ flash(u'Profile deleted')
+ return redirect(url_for('index'))
+ form['name'] = request.form['name']
+ form['email'] = request.form['email']
+ if not form['name']:
+ flash(u'Error: you have to provide a name')
+ elif '@' not in form['email']:
+ flash(u'Error: you have to enter a valid email address')
+ else:
+ flash(u'Profile successfully created')
+ g.user.name = form['name']
+ g.user.email = form['email']
+ db.session.commit()
+ return redirect(url_for('edit_profile'))
+ return render_template('edit_profile.html', form=form)
+
+
+@app.route('/logout')
+def logout():
+ session.pop('openid', None)
+ flash(u'You have been signed out')
+ return redirect(oid.get_next_url())
+
+
+
if __name__ == '__main__':
app.logger.setLevel('DEBUG')
port = int(os.environ.get('PORT', 5000))
diff --git a/requirements.txt b/requirements.txt
index 730b0132..569cf366 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,6 +3,7 @@ twisted
flask
Flask-SQLAlchemy
flask-admin
+flask-openid
werkzeug==0.8.3
flask==0.9
Flask-Login==0.1.3