Skip to content

Commit

Permalink
implement the authentication example code
Browse files Browse the repository at this point in the history
  • Loading branch information
mmerickel committed Feb 14, 2016
1 parent da5ebc2 commit 00b2c69
Show file tree
Hide file tree
Showing 29 changed files with 933 additions and 0 deletions.
4 changes: 4 additions & 0 deletions docs/tutorials/wiki2/src/authentication/CHANGES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
0.0
---

- Initial version
2 changes: 2 additions & 0 deletions docs/tutorials/wiki2/src/authentication/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include *.txt *.ini *.cfg *.rst
recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.jinja2 *.pt *.txt *.mak *.mako *.js *.html *.xml
14 changes: 14 additions & 0 deletions docs/tutorials/wiki2/src/authentication/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
tutorial README
==================

Getting Started
---------------

- cd <directory containing this file>

- $VENV/bin/python setup.py develop

- $VENV/bin/initialize_tutorial_db development.ini

- $VENV/bin/pserve development.ini

73 changes: 73 additions & 0 deletions docs/tutorials/wiki2/src/authentication/development.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
###
# app configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###

[app:main]
use = egg:tutorial

pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
pyramid_tm

sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite

auth.secret = seekrit

# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1

###
# wsgi server configuration
###

[server:main]
use = egg:waitress#main
host = 127.0.0.1
port = 6543

###
# logging configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###

[loggers]
keys = root, tutorial, sqlalchemy

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = INFO
handlers = console

[logger_tutorial]
level = DEBUG
handlers =
qualname = tutorial

[logger_sqlalchemy]
level = INFO
handlers =
qualname = sqlalchemy.engine
# "level = INFO" logs SQL queries.
# "level = DEBUG" logs SQL queries and results.
# "level = WARN" logs neither. (Recommended for production systems.)

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
62 changes: 62 additions & 0 deletions docs/tutorials/wiki2/src/authentication/production.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
###
# app configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###

[app:main]
use = egg:tutorial

pyramid.reload_templates = false
pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en

sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite

auth.secret = real-seekrit

[server:main]
use = egg:waitress#main
host = 0.0.0.0
port = 6543

###
# logging configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###

[loggers]
keys = root, tutorial, sqlalchemy

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console

[logger_tutorial]
level = WARN
handlers =
qualname = tutorial

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
# "level = INFO" logs SQL queries.
# "level = DEBUG" logs SQL queries and results.
# "level = WARN" logs neither. (Recommended for production systems.)

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
49 changes: 49 additions & 0 deletions docs/tutorials/wiki2/src/authentication/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import os

from setuptools import setup, find_packages

here = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(here, 'README.txt')) as f:
README = f.read()
with open(os.path.join(here, 'CHANGES.txt')) as f:
CHANGES = f.read()

requires = [
'bcrypt',
'docutils',
'pyramid',
'pyramid_jinja2',
'pyramid_debugtoolbar',
'pyramid_tm',
'SQLAlchemy',
'transaction',
'zope.sqlalchemy',
'waitress',
]

setup(name='tutorial',
version='0.0',
description='tutorial',
long_description=README + '\n\n' + CHANGES,
classifiers=[
"Programming Language :: Python",
"Framework :: Pyramid",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
],
author='',
author_email='',
url='',
keywords='web wsgi bfg pylons pyramid',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
test_suite='tutorial',
install_requires=requires,
entry_points="""\
[paste.app_factory]
main = tutorial:main
[console_scripts]
initialize_tutorial_db = tutorial.scripts.initializedb:main
""",
)
13 changes: 13 additions & 0 deletions docs/tutorials/wiki2/src/authentication/tutorial/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from pyramid.config import Configurator


def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
config = Configurator(settings=settings)
config.include('pyramid_jinja2')
config.include('.models')
config.include('.routes')
config.include('.security')
config.scan()
return config.make_wsgi_app()
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from sqlalchemy import engine_from_config
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import configure_mappers
import zope.sqlalchemy

# import or define all models here to ensure they are attached to the
# Base.metadata prior to any initialization routines
from .page import Page # flake8: noqa
from .user import User # flake8: noqa

# run configure_mappers after defining all of the models to ensure
# all relationships can be setup
configure_mappers()


def get_engine(settings, prefix='sqlalchemy.'):
return engine_from_config(settings, prefix)


def get_session_factory(engine):
factory = sessionmaker()
factory.configure(bind=engine)
return factory


def get_tm_session(session_factory, transaction_manager):
"""
Get a ``sqlalchemy.orm.Session`` instance backed by a transaction.
This function will hook the session to the transaction manager which
will take care of committing any changes.
- When using pyramid_tm it will automatically be committed or aborted
depending on whether an exception is raised.
- When using scripts you should wrap the session in a manager yourself.
For example::
import transaction
engine = get_engine(settings)
session_factory = get_session_factory(engine)
with transaction.manager:
dbsession = get_tm_session(session_factory, transaction.manager)
"""
dbsession = session_factory()
zope.sqlalchemy.register(
dbsession, transaction_manager=transaction_manager)
return dbsession


def includeme(config):
"""
Initialize the model for a Pyramid app.
Activate this setup using ``config.include('tutorial.models')``.
"""
settings = config.get_settings()

# use pyramid_tm to hook the transaction lifecycle to the request
config.include('pyramid_tm')

session_factory = get_session_factory(get_engine(settings))
config.registry['dbsession_factory'] = session_factory

# make request.dbsession available for use in Pyramid
config.add_request_method(
# r.tm is the transaction manager used by pyramid_tm
lambda r: get_tm_session(session_factory, r.tm),
'dbsession',
reify=True
)
16 changes: 16 additions & 0 deletions docs/tutorials/wiki2/src/authentication/tutorial/models/meta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.schema import MetaData

# Recommended naming convention used by Alembic, as various different database
# providers will autogenerate vastly different names making migrations more
# difficult. See: http://alembic.readthedocs.org/en/latest/naming.html
NAMING_CONVENTION = {
"ix": 'ix_%(column_0_label)s',
"uq": "uq_%(table_name)s_%(column_0_name)s",
"ck": "ck_%(table_name)s_%(constraint_name)s",
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
"pk": "pk_%(table_name)s"
}

metadata = MetaData(naming_convention=NAMING_CONVENTION)
Base = declarative_base(metadata=metadata)
20 changes: 20 additions & 0 deletions docs/tutorials/wiki2/src/authentication/tutorial/models/page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from sqlalchemy import (
Column,
ForeignKey,
Integer,
Text,
)
from sqlalchemy.orm import relationship

from .meta import Base


class Page(Base):
""" The SQLAlchemy declarative model class for a Page object. """
__tablename__ = 'pages'
id = Column(Integer, primary_key=True)
name = Column(Text, nullable=False, unique=True)
data = Column(Integer, nullable=False)

creator_id = Column(ForeignKey('users.id'), nullable=False)
creator = relationship('User', backref='created_pages')
29 changes: 29 additions & 0 deletions docs/tutorials/wiki2/src/authentication/tutorial/models/user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import bcrypt
from sqlalchemy import (
Column,
Integer,
Text,
)

from .meta import Base


class User(Base):
""" The SQLAlchemy declarative model class for a User object. """
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(Text, nullable=False, unique=True)
role = Column(Text, nullable=False)

password_hash = Column(Text)

def set_password(self, pw):
pwhash = bcrypt.hashpw(pw.encode('utf8'), bcrypt.gensalt())
self.password_hash = pwhash

def check_password(self, pw):
if self.password_hash is not None:
expected_hash = self.password_hash.encode('utf8')
actual_hash = bcrypt.hashpw(pw.encode('utf8'), expected_hash)
return expected_hash == actual_hash
return False
8 changes: 8 additions & 0 deletions docs/tutorials/wiki2/src/authentication/tutorial/routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
def includeme(config):
config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('view_wiki', '/')
config.add_route('login', '/login')
config.add_route('logout', '/logout')
config.add_route('view_page', '/{pagename}')
config.add_route('add_page', '/add_page/{pagename}')
config.add_route('edit_page', '/{pagename}/edit_page')
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# package
Loading

0 comments on commit 00b2c69

Please sign in to comment.