mirror of https://github.com/pallets/flask.git
				
				
				
			Merge branch 'master' into module-support
This commit is contained in:
		
						commit
						de909b3bdf
					
				|  | @ -1,165 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| """ | ||||
|     OpenID Example | ||||
|     ~~~~~~~~~~~~~~ | ||||
| 
 | ||||
|     This simple application shows how OpenID can be used in an application. | ||||
| 
 | ||||
|     Dependencies: | ||||
| 
 | ||||
|     -   python-openid | ||||
|     -   SQLAlchemy | ||||
| 
 | ||||
|     :copyright: (c) 2010 by Armin Ronacher. | ||||
|     :license: BSD, see LICENSE for more details. | ||||
| """ | ||||
| from flask import Flask, render_template, request, g, session, flash, \ | ||||
|      redirect, url_for, abort | ||||
| from simpleopenid import SimpleOpenID | ||||
| 
 | ||||
| from sqlalchemy import create_engine, Column, Integer, String | ||||
| from sqlalchemy.orm import scoped_session, sessionmaker | ||||
| from sqlalchemy.ext.declarative import declarative_base | ||||
| 
 | ||||
| # configuration | ||||
| DATABASE_URI = 'sqlite:////tmp/openidexample.db' | ||||
| OPENID_FS_PATH = '/tmp/openidexample-store' | ||||
| SECRET_KEY = 'development key' | ||||
| DEBUG = True | ||||
| 
 | ||||
| # setup flask | ||||
| app = Flask(__name__) | ||||
| app.debug = DEBUG | ||||
| app.secret_key = SECRET_KEY | ||||
| 
 | ||||
| # setup simpleopenid | ||||
| oid = SimpleOpenID(OPENID_FS_PATH) | ||||
| 
 | ||||
| # setup sqlalchemy | ||||
| engine = create_engine(DATABASE_URI) | ||||
| db_session = scoped_session(sessionmaker(autocommit=False, | ||||
|                                          autoflush=False, | ||||
|                                          bind=engine)) | ||||
| Base = declarative_base() | ||||
| Base.query = db_session.query_property() | ||||
| 
 | ||||
| def init_db(): | ||||
|     Base.metadata.create_all(bind=engine) | ||||
| 
 | ||||
| 
 | ||||
| class User(Base): | ||||
|     __tablename__ = 'users' | ||||
|     id = Column(Integer, primary_key=True) | ||||
|     name = Column(String(60)) | ||||
|     email = Column(String(200)) | ||||
|     openid = Column(String(200)) | ||||
| 
 | ||||
|     def __init__(self, name, email, openid): | ||||
|         self.name = name | ||||
|         self.email = email | ||||
|         self.openid = openid | ||||
| 
 | ||||
| 
 | ||||
| @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('/') | ||||
| def index(): | ||||
|     return render_template('index.html') | ||||
| 
 | ||||
| 
 | ||||
| @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) | ||||
|     return render_template('login.html', next_url=oid.get_next_url()) | ||||
| 
 | ||||
| 
 | ||||
| @oid.after_login | ||||
| def create_or_login(identity_url): | ||||
|     """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'] = identity_url | ||||
|     user = User.query.filter_by(openid=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())) | ||||
| 
 | ||||
| 
 | ||||
| @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 were signed out') | ||||
|     return redirect(oid.get_next_url()) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     app.run() | ||||
|  | @ -1,108 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| """ | ||||
|     simpleopenid | ||||
|     ~~~~~~~~~~~~ | ||||
| 
 | ||||
|     Tiny wrapper around python-openid to make working with the basic | ||||
|     API in a flask application easier.  Adapt this code for your own | ||||
|     project if necessary. | ||||
| 
 | ||||
|     :copyright: (c) 2010 by Armin Ronacher. | ||||
|     :license: BSD, see LICENSE for more details. | ||||
| """ | ||||
| from functools import wraps | ||||
| 
 | ||||
| from flask import request, session, flash, redirect | ||||
| from werkzeug import url_quote | ||||
| 
 | ||||
| from openid.association import Association | ||||
| from openid.store.interface import OpenIDStore | ||||
| from openid.store.filestore import FileOpenIDStore | ||||
| from openid.consumer.consumer import Consumer, SUCCESS, CANCEL | ||||
| from openid.consumer import discover | ||||
| from openid.store import nonce | ||||
| 
 | ||||
| # python-openid is a really stupid library in that regard, we have | ||||
| # to disable logging by monkey patching | ||||
| from openid import oidutil | ||||
| oidutil.log = lambda *a, **kw: None | ||||
| 
 | ||||
| 
 | ||||
| class SimpleOpenID(object): | ||||
|     """Simple helper class for OpenID auth.""" | ||||
| 
 | ||||
|     def __init__(self, store_path): | ||||
|         self.store_path = store_path | ||||
|         self.after_login_func = None | ||||
| 
 | ||||
|     def create_store(self): | ||||
|         """Creates the filesystem store""" | ||||
|         return FileOpenIDStore(self.store_path) | ||||
| 
 | ||||
|     def signal_error(self, msg): | ||||
|         """Signals an error.  It does this by flashing a message""" | ||||
|         flash(u'Error: ' + msg) | ||||
| 
 | ||||
|     def get_next_url(self): | ||||
|         """Return the URL where we want to redirect to.""" | ||||
|         return request.values.get('next') or \ | ||||
|                request.referrer or \ | ||||
|                request.url_root | ||||
| 
 | ||||
|     def get_current_url(self): | ||||
|         """the current URL + next""" | ||||
|         return request.base_url + '?next=' + url_quote(self.get_next_url()) | ||||
| 
 | ||||
|     def get_success_url(self): | ||||
|         """Return the success URL""" | ||||
|         return self.get_current_url() + '&openid_complete=yes' | ||||
| 
 | ||||
|     def errorhandler(f): | ||||
|         """Called if an error occours with the message.  By default | ||||
|         ``'Error: message'`` is flashed. | ||||
|         """ | ||||
|         self.signal_error = f | ||||
|         return f | ||||
| 
 | ||||
|     def after_login(self, f): | ||||
|         """This function will be called after login.  It must redirect to | ||||
|         a different place and remember the user somewhere.  The session | ||||
|         is not modified by SimpleOpenID. | ||||
|         """ | ||||
|         self.after_login_func = f | ||||
|         return f | ||||
| 
 | ||||
|     def loginhandler(self, f): | ||||
|         """Marks a function as login handler.  This decorator injects some | ||||
|         more OpenID required logic. | ||||
|         """ | ||||
|         self.login_endpoint = f.__name__ | ||||
|         @wraps(f) | ||||
|         def decorated(*args, **kwargs): | ||||
|             if request.args.get('openid_complete') != u'yes': | ||||
|                 return f(*args, **kwargs) | ||||
|             consumer = Consumer(session, self.create_store()) | ||||
|             openid_response = consumer.complete(request.args.to_dict(), | ||||
|                                                 self.get_current_url()) | ||||
|             if openid_response.status == SUCCESS: | ||||
|                 return self.after_login_func(openid_response.identity_url) | ||||
|             elif openid_response.status == CANCEL: | ||||
|                 self.signal_error(u'The request was cancelled') | ||||
|                 return redirect(self.get_current_url()) | ||||
|             self.signal_error(u'OpenID authentication error') | ||||
|             return redirect(self.get_current_url()) | ||||
|         return decorated | ||||
| 
 | ||||
|     def try_login(self, identity_url): | ||||
|         """This tries to login with the given identity URL.  This function | ||||
|         must be called from the login_handler. | ||||
|         """ | ||||
|         try: | ||||
|             consumer = Consumer(session, self.create_store()) | ||||
|             auth_request = consumer.begin(identity_url) | ||||
|         except discover.DiscoveryFailure: | ||||
|             self.signal_error(u'The OpenID was invalid') | ||||
|             return redirect(self.get_current_url()) | ||||
|         trust_root = request.host_url | ||||
|         return redirect(auth_request.redirectURL(request.host_url, | ||||
|                                                  self.get_success_url())) | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 433 B | 
|  | @ -1,39 +0,0 @@ | |||
| body { | ||||
|     font-family: 'Georgia', serif; | ||||
|     font-size: 16px; | ||||
|     margin: 30px; | ||||
|     padding: 0; | ||||
| } | ||||
| 
 | ||||
| a { | ||||
|     color: #335E79; | ||||
| } | ||||
| 
 | ||||
| p.message { | ||||
|     color: #335E79; | ||||
|     padding: 10px; | ||||
|     background: #CADEEB; | ||||
| } | ||||
| 
 | ||||
| input { | ||||
|     font-family: 'Georgia', serif; | ||||
|     font-size: 16px; | ||||
|     border: 1px solid black; | ||||
|     color: #335E79; | ||||
|     padding: 2px; | ||||
| } | ||||
| 
 | ||||
| input[type="submit"] { | ||||
|     background: #CADEEB; | ||||
|     color: #335E79; | ||||
|     border-color: #335E79; | ||||
| } | ||||
| 
 | ||||
| input[name="openid"] { | ||||
|     background: url(openid.png) 4px no-repeat; | ||||
|     padding-left: 24px; | ||||
| } | ||||
| 
 | ||||
| h1, h2 { | ||||
|     font-weight: normal; | ||||
| } | ||||
|  | @ -1,22 +0,0 @@ | |||
| {% extends "layout.html" %} | ||||
| {% block title %}Create Profile{% endblock %} | ||||
| {% block body %} | ||||
|   <h2>Create Profile</h2> | ||||
|   <p> | ||||
|     Hey!  This is the first time you signed in on this website.  In | ||||
|     order to proceed we need a couple of more information from you: | ||||
|   <form action="" method=post> | ||||
|     <dl> | ||||
|       <dt>Name: | ||||
|       <dd><input type=text name=name size=30 value="{{ request.form.name }}"> | ||||
|       <dt>E-Mail | ||||
|       <dd><input type=text name=email size=30 value="{{ request.form.email }}"> | ||||
|     </dl> | ||||
|     <p> | ||||
|       <input type=submit value="Create profile"> | ||||
|       <input type=hidden name=next value="{{ next_url }}"> | ||||
|   </form> | ||||
|   <p> | ||||
|     If you don't want to proceed, you can <a href="{{ url_for('logout') | ||||
|     }}">sign out</a> again. | ||||
| {% endblock %} | ||||
|  | @ -1,16 +0,0 @@ | |||
| {% extends "layout.html" %} | ||||
| {% block title %}Edit Profile{% endblock %} | ||||
| {% block body %} | ||||
|   <h2>Edit Profile</h2> | ||||
|   <form action="" method=post> | ||||
|     <dl> | ||||
|       <dt>Name: | ||||
|       <dd><input type=text name=name size=30 value="{{ form.name }}"> | ||||
|       <dt>E-Mail | ||||
|       <dd><input type=text name=email size=30 value="{{ form.email }}"> | ||||
|     </dl> | ||||
|     <p> | ||||
|       <input type=submit value="Update profile"> | ||||
|       <input type=submit name=delete value="Delete"> | ||||
|   </form> | ||||
| {% endblock %} | ||||
|  | @ -1,10 +0,0 @@ | |||
| {% extends "layout.html" %} | ||||
| {% block body %} | ||||
|   <h2>Overview</h2> | ||||
|   {% if g.user %} | ||||
|   <p> | ||||
|     Hello {{ g.user.name }}! | ||||
|   {% endif %} | ||||
|   <p> | ||||
|     This is just an example page so that something is here. | ||||
| {% endblock %} | ||||
|  | @ -1,18 +0,0 @@ | |||
| <!doctype html> | ||||
| <title>{% block title %}Welcome{% endblock %} | Flask OpenID Example</title> | ||||
| <link rel=stylesheet type=text/css href="{{ url_for('static', | ||||
|   filename='style.css') }}"> | ||||
| <h1>Flask OpenID Example</h1> | ||||
| <ul class=navigation> | ||||
|   <li><a href="{{ url_for('index') }}">overview</a> | ||||
|   {% if g.user %} | ||||
|   <li><a href="{{ url_for('edit_profile') }}">profile</a> | ||||
|   <li><a href="{{ url_for('logout') }}">sign out [{{ g.user.name }}]</a> | ||||
|   {% else %} | ||||
|   <li><a href="{{ url_for('login') }}">sign in</a> | ||||
|   {% endif %} | ||||
| </ul> | ||||
| {% for message in get_flashed_messages() %} | ||||
|   <p class=message>{{ message }} | ||||
| {% endfor %} | ||||
| {% block body %}{% endblock %} | ||||
|  | @ -1,12 +0,0 @@ | |||
| {% extends "layout.html" %} | ||||
| {% block title %}Sign in{% endblock %} | ||||
| {% block body %} | ||||
|   <h2>Sign in</h2> | ||||
|   <form action="" method=post> | ||||
|     <p> | ||||
|       OpenID: | ||||
|       <input type=text name=openid size=30> | ||||
|       <input type=submit value="Sign in"> | ||||
|       <input type=hidden name=next value="{{ next_url }}"> | ||||
|   </form> | ||||
| {% endblock %} | ||||
		Loading…
	
		Reference in New Issue