Skip to content

Commit

Permalink
fix merge conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
mcdonc committed Feb 15, 2012
2 parents ea0da83 + 9e78f5e commit 5ad8e92
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 83 deletions.
18 changes: 10 additions & 8 deletions README.txt → README.rst
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
shootout
========

shootout is a demo app for the Pyramid web framework. The concepts
Shootout is a demo app for the Pyramid web framework. The concepts
demonstrated in the code include:

- Urldispatch mechanism (similar to routes).

- Built-in authentication and authorization mechanism.

- Beaker encrypted sessions using pyramid_beaker.

- Integration with pyramid_simpleform for form handling.

- SQLAlchemy based models.
Expand All @@ -22,17 +24,17 @@ On a Debian system, these imply: build-essentials, libsqlite3-dev.
Installing and Running
----------------------

#. virtualenv --no-site-packages env
- virtualenv --no-site-packages env

#. cd env
- cd env

#. . bin/activate
- . bin/activate

#. git clone git@github.com:Pylons/shootout.git
- git clone git@github.com:Pylons/shootout.git

#. cd shootout
- cd shootout

#. python setup.py develop
- python setup.py develop

#. paster serve development.ini
- paster serve development.ini

8 changes: 7 additions & 1 deletion development.ini
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
[app:main]
use = egg:shootout

reload_templates = true
debug_authorization = false
debug_notfound = false
debug_routematch = false
debug_templates = true
default_locale_name = en
sqlalchemy.url = sqlite:///%(here)s/shootout.db
session.type = cookie
session.key = shootout
session.encrypt_key = mysecretencryptionkey
session.validate_key = mysecretvalidationkey
session.cookie_on_exception = true
pyramid.includes = pyramid_debugtoolbar
pyramid_tm
sqlalchemy.url = sqlite:///%(here)s/shootout.db

[server:main]
use = egg:waitress#main
Expand Down
12 changes: 9 additions & 3 deletions production.ini
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
[app:main]
use = egg:shootout
reload_templates = true
reload_templates = false
debug_authorization = false
debug_notfound = false
debug_routematch = false
debug_templates = true
default_locale_name = en
pyramid.includes = pyramid_tm
pyramid_exclog

sqlalchemy.url = sqlite:///%(here)s/shootout.db
pyramid.includes = pyramid_exclog
pyramid_tm

[server:main]
use = egg:waitress#main
Expand All @@ -35,6 +36,11 @@ level = DEBUG
handlers =
qualname = shootout

[logger_exc_logger]
level = ERROR
handlers = exc_handler
qualname = exc_logger

[logger_sqlalchemy]
level = INFO
handlers =
Expand Down
14 changes: 8 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from setuptools import setup, find_packages

here = os.path.abspath(os.path.dirname(__file__))
README = open(os.path.join(here, 'README.txt')).read()
README = open(os.path.join(here, 'README.rst')).read()
CHANGES = open(os.path.join(here, 'CHANGES.txt')).read()

requires = [
Expand All @@ -19,15 +19,17 @@
'pyramid_simpleform',
'cryptacular',
'waitress',
'pyramid_beaker',
'pycrypto',
]

if sys.version_info[:3] < (2,5,0):
raise RuntimeError('This application requires Python 2.6+')

setup(name='shootout',
version='0.2',
version='0.2.2',
description='A generic idea discussion and rating app (Pyramid sample)',
long_description=README + '\n\n' + CHANGES,
long_description=README + '\n\n' + CHANGES,
classifiers=[
"Framework :: Pylons",
"Framework :: BFG",
Expand All @@ -42,13 +44,13 @@
author_email="cguardia@yahoo.com, virhilo@gmail.com",
url='http://pylons-devel@googlegroups.com',
license="BSD-derived (http://www.repoze.org/LICENSE.txt)",
keywords='web wsgi pyramid pylons example',
keywords='web wsgi bfg pyramid pylons example',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
test_suite='shootout.tests',
install_requires = requires,
entry_points = """\
install_requires=requires,
entry_points="""\
[paste.app_factory]
main = shootout:main
""",
Expand Down
7 changes: 4 additions & 3 deletions shootout/__init__.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
from pyramid.config import Configurator
from pyramid.authentication import AuthTktAuthenticationPolicy
from pyramid.authorization import ACLAuthorizationPolicy
from pyramid.session import UnencryptedCookieSessionFactoryConfig

from pyramid_beaker import session_factory_from_settings

from sqlalchemy import engine_from_config

from shootout.models import initialize_sql


def main(global_config, **settings):
def main(global_config, **settings): # pragma: no cover
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
initialize_sql(engine)

session_factory = UnencryptedCookieSessionFactoryConfig('secret')
session_factory = session_factory_from_settings(settings)

authn_policy = AuthTktAuthenticationPolicy('s0secret')
authz_policy = ACLAuthorizationPolicy()
Expand Down
49 changes: 37 additions & 12 deletions shootout/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from sqlalchemy.orm import backref
from sqlalchemy.orm import column_property
from sqlalchemy.orm import synonym
from sqlalchemy.orm import joinedload
from sqlalchemy.types import Integer
from sqlalchemy.types import Unicode
from sqlalchemy.types import UnicodeText
Expand All @@ -27,9 +28,11 @@

crypt = cryptacular.bcrypt.BCRYPTPasswordManager()


def hash_password(password):
return unicode(crypt.encode(password))


class User(Base):
"""
Application's user model.
Expand Down Expand Up @@ -63,7 +66,7 @@ def __init__(self, username, password, name, email):

@classmethod
def get_by_username(cls, username):
return DBSession.query(cls).filter(cls.username==username).first()
return DBSession.query(cls).filter(cls.username == username).first()

@classmethod
def check_password(cls, username, password):
Expand Down Expand Up @@ -100,7 +103,7 @@ def extract_tags(tags_string):

@classmethod
def get_by_name(cls, tag_name):
tag = DBSession.query(cls).filter(cls.name==tag_name)
tag = DBSession.query(cls).filter(cls.name == tag_name)
return tag.first()

@classmethod
Expand All @@ -116,7 +119,7 @@ def create_tags(cls, tags_string):
tags.append(tag)

return tags

@classmethod
def tag_counts(cls):
query = DBSession.query(Tag.name, func.count('*'))
Expand Down Expand Up @@ -154,32 +157,54 @@ class Idea(Base):
)

@classmethod
def get_by_id(cls, idea_id):
return DBSession.query(cls).filter(cls.idea_id==idea_id).first()
def get_query(cls, with_joinedload=True):
query = DBSession.query(cls)
if with_joinedload:
query = query.options(joinedload('tags'), joinedload('author'))
return query

@classmethod
def get_by_id(cls, idea_id, with_joinedload=True):
query = cls.get_query(with_joinedload)
return query.filter(cls.idea_id == idea_id).first()

@classmethod
def get_by_tagname(cls, tag_name):
return DBSession.query(Idea).filter(Idea.tags.any(name=tag_name))
def get_by_tagname(cls, tag_name, with_joinedload=True):
query = cls.get_query(with_joinedload)
return query.filter(Idea.tags.any(name=tag_name))

@classmethod
def ideas_bunch(cls, order_by, how_many=10):
q = DBSession.query(cls).join('author').filter(cls.target==None)
return q.order_by(order_by)[:how_many]
def ideas_bunch(cls, order_by, how_many=10, with_joinedload=True):
query = cls.get_query(with_joinedload).join('author')
return query.filter(cls.target == None).order_by(order_by)[:how_many]

def user_voted(self, username):
return bool(self.voted_users.filter_by(username=username).first())

def vote(self, user, positive):
if positive:
self.hits += 1
self.author.hits += 1
user.delivered_hits += 1
else:
self.misses += 1
self.author.misses += 1
user.delivered_misses += 1

self.voted_users.append(user)


class RootFactory(object):
__acl__ = [
(Allow, Everyone, 'view'),
(Allow, Authenticated, 'post')
]

def __init__(self, request):
pass
pass # pragma: no cover


def initialize_sql(engine):
def initialize_sql(engine): # pragma: no cover
DBSession.configure(bind=engine)
Base.metadata.bind = engine
Base.metadata.create_all(engine)
Expand Down
1 change: 1 addition & 0 deletions shootout/templates/about.pt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<li>Urldispatch mechanism (similar to routes).</li>
<li>Built-in authentication and authorization mechanism.</li>
<li>Integration with pyramid_simpleform for form handling.</li>
<li>Beaker encrypted sessions using pyramid_beaker.</li>
<li>SQLAlchemy based models.</li>
</ul>
<p>The code can be checked out from the version control repository at:</p>
Expand Down
4 changes: 3 additions & 1 deletion shootout/templates/base.pt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link href="${request.static_url('shootout:static/default.css')}" rel="stylesheet" type="text/css" />
Expand Down
2 changes: 1 addition & 1 deletion shootout/templates/idea.pt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<div tal:condition="voted">
<p>You already voted for this idea.</p>
</div>
<div tal:condition="not voted and viewer_username">
<div tal:condition="not voted and viewer_username and idea.author.username != viewer_username">
<form action="${request.route_url('idea_vote')}" method="post">
<input name="_csrf" type="hidden"
value="${request.session.get_csrf_token()}">
Expand Down
10 changes: 4 additions & 6 deletions shootout/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ def test_doesnt_exitst(self):
self.assertRaises(NoResultFound, query.one)

def test_arleady_exist(self):
from shootout.models import User
from sqlalchemy.exc import IntegrityError
self._addUser()
self.assertRaises(IntegrityError, self._addUser)
Expand All @@ -80,7 +79,7 @@ def test_password_hashing(self):

def test_password_checking(self):
from shootout.models import User
user = self._addUser()
self._addUser()
self.assertTrue(User.check_password(u'username', u'password'))
self.assertFalse(User.check_password(u'username', u'wrong'))
self.assertFalse(User.check_password(u'nobody', u'password'))
Expand All @@ -89,7 +88,7 @@ def test_getting_by_username(self):
from shootout.models import User
user = self._addUser()
self.assertEqual(user, User.get_by_username(u'username'))


class TestTag(ModelsTestCase):
def test_extracting_tags(self):
Expand All @@ -110,7 +109,7 @@ def test_creating_tags(self):
self.assertEqual(tags[2].name, tags_names.pop())

def test_tags_counts(self):
from shootout.models import Tag, Idea
from shootout.models import Tag

user = self._addUser()

Expand Down Expand Up @@ -233,11 +232,10 @@ def test_ideas_bunch(self):
[idea1, idea4, idea2, idea3])

def test_user_voted(self):
from shootout.models import Idea
idea = self._addIdea()
voting_user = self._addUser(u'voter')
idea.voted_users.append(voting_user)
self.session.flush()
self.assertTrue(idea.user_voted(u'voter'))
self.assertFalse(idea.user_voted(u'xxx'))

Loading

0 comments on commit 5ad8e92

Please sign in to comment.