Added some openid code.

This commit is contained in:
Armin Ronacher 2010-05-02 19:07:42 +02:00
parent 904fe68d51
commit a81cf3a67c
5 changed files with 196 additions and 13 deletions

View file

@ -1,6 +1,9 @@
from flask import Flask, render_template from flask import Flask, render_template
import websiteconfig as config
app = Flask(__name__) app = Flask(__name__)
app.debug = config.DEBUG
@app.errorhandler(404) @app.errorhandler(404)
def not_found(error): def not_found(error):

View file

@ -0,0 +1,83 @@
from __future__ import with_statement
from time import time
from hashlib import sha1
from contextlib import closing
from openid.association import Association
from openid.store.interface import OpenIDStore
from openid.consumer.consumer import Consumer, SUCCESS, CANCEL
from openid.consumer import discover
from openid.store import nonce
from sqlalchemy.orm import scoped_session
from sqlalchemy.exceptions import SQLError
from flask import request, redirect, abort, url_for, flash
from flask_website.database import User, db_session
class WebsiteOpenIDStore(OpenIDStore):
"""Implements the open store for the website using the database."""
def storeAssociation(self, server_url, association):
assoc = OpenIDAssociation(
server_url=server_url,
handle=association.handle,
secret=association.secret.encode('base64'),
issued=association.issued,
lifetime=association.lifetime,
assoc_type=association.assoc_type
)
db_session.add(assoc)
def getAssociation(self, server_url, handle=None):
q = OpenIDAssociation.query.filter_by(server_url=server_url)
if handle is not None:
q = q.filter_by(handle=handle)
result_assoc = None
for item in q.all():
assoc = Association(item.handle, item.secret.decode('base64'),
item.issued, item.lifetime, item.assoc_type)
if assoc.getExpiresIn() <= 0:
self.removeAssociation(server_url, assoc.handle)
else:
result_assoc = assoc
return result_assoc
def removeAssociation(self, server_url, handle):
return OpenIDAssociation.filter(
(OpenIDAssociation.server_url == server_url) &
(OpenIDAssociation.handle == handle)
).delete()
def useNonce(self, server_url, timestamp, salt):
if abs(timestamp - time()) > nonce.SKEW:
return False
rv = OpenIDUserNonces.query.filter(
(OpenIDUserNonces.server_url == server_url) &
(OpenIDUserNonces.timestamp == timestamp) &
(OpenIDUserNonces.salt == salt)
).first()
if rv is not None:
return False
rv = OpenIDUserNonces(server_url=server_url, timestamp=timestamp,
salt=salt)
session.add(rv)
return True
def cleanupNonces(self):
return OpenIDUserNonces.filter(
OpenIDUserNonces.timestamp <= int(time() - nonce.SKEW)
).delete()
def cleanupAssociations(self):
return OpenIDAssociation.filter(
OpenIDAssociation.lifetime < int(time())
).delete()
def getAuthKey(self):
return sha1(config.SECRET_KEY).hexdigest()[:self.AUTH_KEY_LEN]
def isDump(self):
return False

87
flask_website/database.py Normal file
View file

@ -0,0 +1,87 @@
from datetime import datetime
from sqlalchemy import create_engine, MetaData, Table, Column, Integer, \
String, DateTime, ForeignKey
from sqlalchemy.orm import scoped_session, sessionmaker, backref
from sqlalchemy.ext.declarative import declarative_base
from flask_website import config
engine = create_engine(config.DATABASE_URI)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
def init_db():
Model.metadata.create_all(bind=engine)
class Model(declarative_base()):
query = db_session.query_property()
class User(Model):
__tablename__ = 'users'
id = Column('user_id', Integer, primary_key=True)
openid = Column('openid', String(200))
username = Column(String(40), unique=True)
password = Column(String(80))
def __init__(self, username, password):
self.username = username
self.password = password
class Category(Model):
__tablename__ = 'categories'
id = Column('category_id', Integer, primary_key=True)
name = Column(String(50))
slug = Column(String(50))
class Snippet(Model):
__tablename__ = 'snippets'
id = Column('snippet_id', Integer, primary_key=True)
author = ForeignKey(User, backref=backref('snippets', lazy='dynamic'))
category = ForeignKey(Category, backref=backref('snippets', lazy='dynamic'))
title = Column(String(200))
body = Column(String)
pub_date = DateTime()
def __init__(self, author, title, body):
self.author = author
self.title = title
self.body = body
self.pub_date = datetime.utcnow()
class Comment(Model):
__tablename__ = 'comments'
id = Column('comment_id', Integer, primary_key=True)
snippet = ForeignKey(Snippet, backref='lazy')
author = ForeignKey(User, backref=backref('comments', lazy='dynamic'))
title = Column(String(200))
text = Column(String)
pub_date = DateTime()
def __init__(self, author, title, text):
self.author = author
self.title = title
self.text = text
self.pub_date = datetime.utcnow()
class OpenIDAssociation(Model):
id = Column('association_id', Integer, primary_key=True)
server_url = Column(String(1024))
handle = Column(String(255))
secret = Column(String(255))
issued = Column(Integer)
lifetime = Column(Integer)
assoc_type = Column(String(64))
class OpenIDUserNonces(Model):
id = Column('user_nonce_id', Integer, primary_key=True)
server_url = Column(String(1024))
timestamp = Column(Integer)
salt = Column(String(40))

View file

@ -4,10 +4,9 @@ from hashlib import md5
from werkzeug import parse_date from werkzeug import parse_date
from jinja2.utils import urlize from jinja2.utils import urlize
from flask import Module, render_template, json, url_for, abort, Markup from flask import Module, render_template, json, url_for, abort, Markup
from flask_website import config
mailinglist = Module(__name__) mailinglist = Module(__name__, url_prefix='/mailinglist')
THREADS_PER_PAGE = 15
MAILINGLIST_PATH = os.path.join(os.path.dirname(__file__), '..', '..', '_mailinglist')
class Mail(object): class Mail(object):
@ -54,14 +53,14 @@ class Thread(object):
def get(year, month, day, slug): def get(year, month, day, slug):
try: try:
with open('%s/threads/%s-%02d-%02d/%s' % with open('%s/threads/%s-%02d-%02d/%s' %
(MAILINGLIST_PATH, year, month, day, slug)) as f: (config.MAILINGLIST_PATH, year, month, day, slug)) as f:
return Thread(json.load(f)) return Thread(json.load(f))
except IOError: except IOError:
pass pass
@staticmethod @staticmethod
def get_list(): def get_list():
with open('%s/threads/threadlist' % MAILINGLIST_PATH) as f: with open('%s/threads/threadlist' % config.MAILINGLIST_PATH) as f:
return [Thread(x) for x in json.load(f)] return [Thread(x) for x in json.load(f)]
@property @property
@ -71,25 +70,25 @@ class Thread(object):
slug=self.slug) slug=self.slug)
@mailinglist.route('/mailinglist/') @mailinglist.route('/')
def index(): def index():
return render_template('mailinglist/index.html') return render_template('mailinglist/index.html')
@mailinglist.route('/mailinglist/archive/', defaults={'page': 1}) @mailinglist.route('/archive/', defaults={'page': 1})
@mailinglist.route('/mailinglist/archive/page/<int:page>/') @mailinglist.route('/archive/page/<int:page>/')
def archive(page): def archive(page):
all_threads = Thread.get_list() all_threads = Thread.get_list()
offset = (page - 1) * THREADS_PER_PAGE offset = (page - 1) * config.THREADS_PER_PAGE
threads = all_threads[offset:offset + THREADS_PER_PAGE] threads = all_threads[offset:offset + config.THREADS_PER_PAGE]
if page != 1 and not threads: if page != 1 and not threads:
abort(404) abort(404)
return render_template('mailinglist/archive.html', return render_template('mailinglist/archive.html', page_count=
page_count=len(threads) // THREADS_PER_PAGE + 1, len(threads) // config.THREADS_PER_PAGE + 1,
page=page, threads=threads) page=page, threads=threads)
@mailinglist.route('/mailinglist/archive/<int:year>/<int:month>/<int:day>/<slug>/') @mailinglist.route('/archive/<int:year>/<int:month>/<int:day>/<slug>/')
def show_thread(year, month, day, slug): def show_thread(year, month, day, slug):
thread = Thread.get(year, month, day, slug) thread = Thread.get(year, month, day, slug)
if thread is None: if thread is None:

11
websiteconfig.py Normal file
View file

@ -0,0 +1,11 @@
import os
_basedir = os.path.abspath(os.path.dirname(__file__))
DEBUG = False
SECRET_KEY = 'testkey'
DATABASE_URI = 'sqlite:///' + os.path.join(_basedir, 'flask-website.db')
MAILINGLIST_PATH = os.path.join(_basedir, '_mailinglist')
THREADS_PER_PAGE = 15
del os