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
|
||||
|
||||
import websiteconfig as config
|
||||
|
||||
app = Flask(__name__)
|
||||
app.debug = config.DEBUG
|
||||
|
||||
@app.errorhandler(404)
|
||||
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 jinja2.utils import urlize
|
||||
from flask import Module, render_template, json, url_for, abort, Markup
|
||||
from flask_website import config
|
||||
|
||||
mailinglist = Module(__name__)
|
||||
THREADS_PER_PAGE = 15
|
||||
MAILINGLIST_PATH = os.path.join(os.path.dirname(__file__), '..', '..', '_mailinglist')
|
||||
mailinglist = Module(__name__, url_prefix='/mailinglist')
|
||||
|
||||
|
||||
class Mail(object):
|
||||
|
|
@ -54,14 +53,14 @@ class Thread(object):
|
|||
def get(year, month, day, slug):
|
||||
try:
|
||||
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))
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
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)]
|
||||
|
||||
@property
|
||||
|
|
@ -71,25 +70,25 @@ class Thread(object):
|
|||
slug=self.slug)
|
||||
|
||||
|
||||
@mailinglist.route('/mailinglist/')
|
||||
@mailinglist.route('/')
|
||||
def index():
|
||||
return render_template('mailinglist/index.html')
|
||||
|
||||
|
||||
@mailinglist.route('/mailinglist/archive/', defaults={'page': 1})
|
||||
@mailinglist.route('/mailinglist/archive/page/<int:page>/')
|
||||
@mailinglist.route('/archive/', defaults={'page': 1})
|
||||
@mailinglist.route('/archive/page/<int:page>/')
|
||||
def archive(page):
|
||||
all_threads = Thread.get_list()
|
||||
offset = (page - 1) * THREADS_PER_PAGE
|
||||
threads = all_threads[offset:offset + THREADS_PER_PAGE]
|
||||
offset = (page - 1) * config.THREADS_PER_PAGE
|
||||
threads = all_threads[offset:offset + config.THREADS_PER_PAGE]
|
||||
if page != 1 and not threads:
|
||||
abort(404)
|
||||
return render_template('mailinglist/archive.html',
|
||||
page_count=len(threads) // THREADS_PER_PAGE + 1,
|
||||
return render_template('mailinglist/archive.html', page_count=
|
||||
len(threads) // config.THREADS_PER_PAGE + 1,
|
||||
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):
|
||||
thread = Thread.get(year, month, day, slug)
|
||||
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