Permalink
Browse files

Merge pull request #5 from virhilo/master

Some improvments
  • Loading branch information...
2 parents 77a92a6 + 2af0ae9 commit 07e8be090b63862d4774a5bf967ce2a16ba9ca3e @mcdonc mcdonc committed Aug 10, 2011
Showing with 104 additions and 47 deletions.
  1. +9 −7 README.txt
  2. +5 −0 development.ini
  3. +4 −2 setup.py
  4. +4 −2 shootout/__init__.py
  5. +31 −9 shootout/models.py
  6. +1 −0 shootout/templates/about.pt
  7. +1 −1 shootout/templates/idea.pt
  8. +35 −10 shootout/tests/test_views.py
  9. +14 −16 shootout/views.py
View
@@ -8,6 +8,8 @@ demonstrated in the code include:
- Built-in authentication and authorization mechanism.
+- Beaker encrypted sessions using pyramid_beaker.
+
- Integration with pyramid_simpleform for form handling.
- SQLAlchemy based models.
@@ -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
View
@@ -6,6 +6,11 @@ debug_notfound = false
debug_routematch = false
debug_templates = true
default_locale_name = en
+session.type = cookie
+session.key = shootout
+session.encrypt_key = mysecretencryptionkey
+session.validate_key = mysecretvalidationkey
+session.cookie_on_exception = true
sqlalchemy.url = sqlite:///%(here)s/shootout.db
[pipeline:main]
View
@@ -17,13 +17,15 @@
'WebError',
'pyramid_simpleform',
'cryptacular',
- ]
+ 'pyramid_beaker',
+ 'pycrypto',
+]
if sys.version_info[:3] < (2,5,0):
requires.append('pysqlite')
setup(name='shootout',
- version='0.2',
+ version='0.2.1',
description='A generic idea discussion and rating app (Pyramid sample)',
long_description=README + '\n\n' + CHANGES,
classifiers=[
View
@@ -3,18 +3,20 @@
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()
View
@@ -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
@@ -154,32 +155,53 @@ 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_tagname(cls, tag_name):
- return DBSession.query(Idea).filter(Idea.tags.any(name=tag_name))
+ 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 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 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, 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)
@@ -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>
@@ -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()}">
@@ -141,10 +141,10 @@ def test_idea_add_submit_schema_succeed(self):
self.assertEqual(idea.tags[1].name, u'bar')
self.assertEqual(idea.tags[2].name, u'def')
- def test_positive_idea_voting(self):
+ def test_vote_on_own_idea(self):
from shootout.views import idea_vote
from shootout.models import User
- _registerRoutes(self.config)
+ _registerRoutes(self.config)
idea = self._addIdea()
user = self.session.query(User).one()
self.assertEqual(idea.user_voted(u'username'), False)
@@ -155,24 +155,49 @@ def test_positive_idea_voting(self):
}
request = testing.DummyRequest(post=post_data)
idea_vote(request)
+ self.assertEqual(idea.hits, 0)
+ self.assertEqual(idea.misses, 0)
+ self.assertEqual(idea.hit_percentage, 0)
+ self.assertEqual(idea.total_votes, 0)
+ self.assertEqual(idea.vote_differential, 0)
+ self.assertEqual(idea.author.hits, 0)
+ self.assertEqual(len(idea.voted_users.all()), 0)
+ self.assertEqual(idea.user_voted(u'username'), False)
+
+ def test_positive_idea_voting(self):
+ from shootout.views import idea_vote
+ from shootout.models import User
+ _registerRoutes(self.config)
+ user = self._addUser()
+ idea = self._addIdea(user=user)
+ voter = self._addUser(u'votername')
+ self.assertEqual(idea.user_voted(u'votername'), False)
+ self.config.testing_securitypolicy(u'votername')
+ post_data = {
+ 'form.vote_hit': u'Hit',
+ 'target': 1,
+ }
+ request = testing.DummyRequest(post=post_data)
+ idea_vote(request)
self.assertEqual(idea.hits, 1)
self.assertEqual(idea.misses, 0)
self.assertEqual(idea.hit_percentage, 100)
self.assertEqual(idea.total_votes, 1)
self.assertEqual(idea.vote_differential, 1)
self.assertEqual(idea.author.hits, 1)
self.assertEqual(len(idea.voted_users.all()), 1)
- self.assertEqual(idea.voted_users.one(), user)
- self.assertTrue(idea.user_voted(u'username'))
+ self.assertEqual(idea.voted_users.one(), voter)
+ self.assertTrue(idea.user_voted(u'votername'))
def test_negative_idea_voting(self):
from shootout.views import idea_vote
from shootout.models import User
_registerRoutes(self.config)
- idea = self._addIdea()
- user = self.session.query(User).one()
- self.assertEqual(idea.user_voted(u'username'), False)
- self.config.testing_securitypolicy(u'username')
+ user = self._addUser()
+ idea = self._addIdea(user=user)
+ voter = self._addUser(u'votername')
+ self.assertEqual(idea.user_voted(u'votername'), False)
+ self.config.testing_securitypolicy(u'votername')
post_data = {
'form.vote_miss': u'Miss',
'target': 1,
@@ -186,8 +211,8 @@ def test_negative_idea_voting(self):
self.assertEqual(idea.vote_differential, -1)
self.assertEqual(idea.author.hits, 0)
self.assertEqual(len(idea.voted_users.all()), 1)
- self.assertEqual(idea.voted_users.one(), user)
- self.assertTrue(idea.user_voted(u'username'))
+ self.assertEqual(idea.voted_users.one(), voter)
+ self.assertTrue(idea.user_voted(u'votername'))
def test_registration_nosubmit(self):
from shootout.views import user_add
View
@@ -52,27 +52,24 @@ def idea_vote(request):
target = post_data.get('target')
session = DBSession()
- idea = Idea.get_by_id(target)
+ idea = Idea.get_by_id(target, with_joinedload=False)
voter_username = authenticated_userid(request)
voter = User.get_by_username(voter_username)
- if post_data.get('form.vote_hit'):
- idea.hits += 1
- idea.author.hits += 1
- voter.delivered_hits += 1
+ redirect_url = route_url('idea', request, idea_id=idea.idea_id)
+ response = HTTPMovedPermanently(location=redirect_url)
- elif post_data.get('form.vote_miss'):
- idea.misses += 1
- idea.author.misses += 1
- voter.delivered_misses += 1
+ if voter.user_id == idea.author_id:
+ request.session.flash(u'You cannot vote on your own ideas.')
+ return response
- idea.voted_users.append(voter)
+ if post_data.get('form.vote_hit'):
+ idea.vote(voter, True)
+ elif post_data.get('form.vote_miss'):
+ idea.vote(voter, False)
session.flush()
- redirect_url = route_url('idea', request, idea_id=idea.idea_id)
- response = HTTPMovedPermanently(location=redirect_url)
-
return response
@@ -136,7 +133,7 @@ def idea_add(request):
target = request.GET.get('target')
session = DBSession()
if target:
- target = Idea.get_by_id(target)
+ target = Idea.get_by_id(target, with_joinedload=False)
if not target:
return HTTPNotFound()
kind = 'comment'
@@ -188,7 +185,7 @@ def user_view(request):
'toolbar': toolbar_view(request),
'cloud': cloud_view(request),
'latest': latest_view(request),
- 'login_form' :login_form,
+ 'login_form': login_form,
}
@@ -283,9 +280,10 @@ def login_form_view(request):
def latest_view(request):
- latest = Idea.ideas_bunch(Idea.idea_id.desc())
+ latest = Idea.ideas_bunch(Idea.idea_id.desc(), with_joinedload=False)
return render('templates/latest.pt', {'latest': latest}, request)
+
def cloud_view(request):
totalcounts = []
for tag in Tag.tag_counts():

0 comments on commit 07e8be0

Please sign in to comment.