Added some openid code.
This commit is contained in:
parent
904fe68d51
commit
a81cf3a67c
5 changed files with 196 additions and 13 deletions
|
|
@ -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):
|
||||||
|
|
|
||||||
83
flask_website/_openid_auth.py
Normal file
83
flask_website/_openid_auth.py
Normal 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
87
flask_website/database.py
Normal 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))
|
||||||
|
|
@ -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
11
websiteconfig.py
Normal 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
|
||||||
Loading…
Add table
Add a link
Reference in a new issue