Skip to content
Browse files

refactorized models and partialy views and templates

  • Loading branch information...
1 parent ee6f06e commit 4390c189389ca82fa27c0339ccb0e1b7dba5709f @virhilo virhilo committed Mar 12, 2011
View
6 CHANGES.txt
@@ -1,4 +1,4 @@
-Next release
-============
+0.0
+---
-- Forked from repoze.shootout 0.6dev
+- Initial version
View
2 MANIFEST.in
@@ -0,0 +1,2 @@
+include *.txt *.ini *.cfg *.rst
+recursive-include shootout *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml
View
35 README.txt
@@ -1,37 +1,4 @@
-shootout
-========
+shootout README
-shootout is a demo app for the Pyramid web framework. The concepts
-demonstrated in the code include:
-- Urldispatch mechanism (similar to routes).
-
-- Integration with the repoze.who authentication endware.
-
-- Integration with the deliverance filter for theming.
-
-- SQLAlchemy based models.
-
-Library Requirements
---------------------
-
-shootout requires a C compiler, SQLite3, and libxml2 and libxslt bindings.
-
-On a Debian system, these imply: build-essentials, libsqlite3-dev,
-libxml2-dev, libxslt-dev.
-
-Installing and Running
-----------------------
-
-#. virtualenv --no-site-packages env
-
-#. cd env
-
-#. git clone git@github.com:Pylons/shootout.git
-
-#. cd shootout
-
-#. ../bin/python setup.py develop
-
-#. ../bin/paster serve development.ini
View
74 development.ini
@@ -1,31 +1,63 @@
-[DEFAULT]
-debug = true
-theme = thewildwest
-theme_host = http://localhost:5430
-
[app:shootout]
use = egg:shootout
-db = sqlite:///ideadb
-debug_templates = true
reload_templates = true
-
-[filter:who]
-use = egg:repoze.who#config
-config_file = %(here)s/who.ini
-
-[filter:deliverance]
-paste.filter_app_factory = deliverance.wsgimiddleware:make_filter
-theme_uri = %(theme_host)s/resources/%(theme)s/index.html?notheme
-rule_uri = file:///%(here)s/shootout/deliverance/rules/%(theme)s.xml
+debug_authorization = false
+debug_notfound = false
+debug_routematch = false
+debug_templates = true
+default_locale_name = en
+sqlalchemy.url = sqlite:///%(here)s/shootout.db
[pipeline:main]
pipeline =
- deliverance
- egg:repoze.tm2#tm
- who
- shootout
+ egg:WebError#evalerror
+ tm
+ shootout
+
+[filter:tm]
+use = egg:repoze.tm2#tm
+commit_veto = repoze.tm:default_commit_veto
[server:main]
use = egg:Paste#http
host = 0.0.0.0
-port = 5430
+port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root, shootout, sqlalchemy
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_shootout]
+level = DEBUG
+handlers =
+qualname = shootout
+
+[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][%(threadName)s] %(message)s
+
+# End logging configuration
View
77 production.ini
@@ -0,0 +1,77 @@
+[app:shootout]
+use = egg:shootout
+reload_templates = false
+debug_authorization = false
+debug_notfound = false
+debug_routematch = false
+debug_templates = false
+default_locale_name = en
+sqlalchemy.url = sqlite:///%(here)s/shootout.db
+
+[filter:weberror]
+use = egg:WebError#error_catcher
+debug = false
+;error_log =
+;show_exceptions_in_wsgi_errors = true
+;smtp_server = localhost
+;error_email = janitor@example.com
+;smtp_username = janitor
+;smtp_password = "janitor's password"
+;from_address = paste@localhost
+;error_subject_prefix = "Pyramid Error"
+;smtp_use_tls =
+;error_message =
+
+[filter:tm]
+use = egg:repoze.tm2#tm
+commit_veto = repoze.tm:default_commit_veto
+
+[pipeline:main]
+pipeline =
+ weberror
+ tm
+ shootout
+
+[server:main]
+use = egg:Paste#http
+host = 0.0.0.0
+port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root, shootout, sqlalchemy
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = WARN
+handlers = console
+
+[logger_shootout]
+level = WARN
+handlers =
+qualname = shootout
+
+[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][%(threadName)s] %(message)s
+
+# End logging configuration
View
26 setup.cfg
@@ -1,9 +1,27 @@
-[easy_install]
-zip_ok = false
-
[nosetests]
match=^test
-where=shootout
nocapture=1
cover-package=shootout
+with-coverage=1
cover-erase=1
+
+[compile_catalog]
+directory = shootout/locale
+domain = shootout
+statistics = true
+
+[extract_messages]
+add_comments = TRANSLATORS:
+output_file = shootout/locale/shootout.pot
+width = 80
+
+[init_catalog]
+domain = shootout
+input_file = shootout/locale/shootout.pot
+output_dir = shootout/locale
+
+[update_catalog]
+domain = shootout
+input_file = shootout/locale/shootout.pot
+output_dir = shootout/locale
+previous = true
View
38 setup.py
@@ -1,4 +1,5 @@
import os
+import sys
from setuptools import setup, find_packages
@@ -7,49 +8,48 @@
CHANGES = open(os.path.join(here, 'CHANGES.txt')).read()
requires = [
- 'setuptools',
- 'pyramid>=1.0a10',
- 'pyramid_zcml',
- 'repoze.who',
- 'repoze.who.deprecatedplugins',
- 'Deliverance <= 0.2',
- 'SQLAlchemy < 0.6a',
+ 'setuptools'
+ 'pyramid',
+ 'SQLAlchemy',
+ 'transaction',
+ 'repoze.tm2>=1.0b1', # default_commit_veto
'zope.sqlalchemy',
- 'repoze.tm2',
- 'FormEncode',
+ 'WebError',
+ 'pyramid_who',
+ 'formencode',
]
-import sys
if sys.version_info[:3] < (2,5,0):
requires.append('pysqlite')
setup(name='shootout',
- version='0.0',
+ version='0.2',
description='A generic idea discussion and rating app (Pyramid sample)',
long_description=README + '\n\n' + CHANGES,
classifiers=[
"Framework :: Pylons",
+ "Framework :: BFG",
"Intended Audience :: Developers",
"Programming Language :: Python",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
"Topic :: Internet :: WWW/HTTP :: WSGI",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
],
- author='Carlos de la Guardia',
- author_email='cguardia@yahoo.com',
+ author="Carlos de la Guardia, Lukasz Fidosz",
+ 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',
+ license="BSD-derived (http://www.repoze.org/LICENSE.txt)
+ keywords='web wsgi pyramid pylons example',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
- install_requires=requires,
- tests_require=requires,
- test_suite="shootout.tests",
+ test_suite='shootout.tests',
+ install_requires = requires,
entry_points = """\
[paste.app_factory]
main = shootout:main
- """
+ """,
+ paster_plugins=['pyramid'],
)
View
65 shootout/__init__.py
@@ -1,16 +1,59 @@
-from shootout.models import get_root
+from pyramid.config import Configurator
+from pyramid.authentication import AuthTktAuthenticationPolicy
+from pyramid.authorization import ACLAuthorizationPolicy
+from pyramid.session import UnencryptedCookieSessionFactoryConfig
+
+from sqlalchemy import engine_from_config
+
from shootout.models import initialize_sql
+
def main(global_config, **settings):
- # paster app config callback
- db = settings.get('db')
- if not db:
- raise ValueError('shootout requires a db section '
- '(the SQLAlchemy db URI)')
- initialize_sql(db)
- from pyramid.config import Configurator
- config = Configurator(root_factory=get_root)
- config.include('pyramid_zcml')
- config.load_zcml('shootout:configure.zcml')
+ """ This function returns a Pyramid WSGI application.
+ """
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ initialize_sql(engine)
+
+ session_factory = UnencryptedCookieSessionFactoryConfig('secret')
+
+ authn_policy = AuthTktAuthenticationPolicy('s0secret')
+ authz_policy = ACLAuthorizationPolicy()
+
+ config = Configurator(
+ settings=settings,
+ root_factory='shootout.models.RootFactory',
+ authentication_policy=authn_policy,
+ authorization_policy=authz_policy,
+ session_factory=session_factory
+ )
+ config.add_static_view('static', 'shootout:static')
+ config.add_route('idea', '/ideas/{idea_id}',
+ view='shootout.views.idea_view',
+ view_renderer='templages/idea.pt')
+ config.add_route('user', '/users/{user}',
+ view='shootout.views.user_view',
+ view_renderer='templates/user.pt')
+ config.add_route('tag', '/tags/{tag_name}',
+ view='shootout.views.tag_view',
+ view_renderer='templates/tag.pt')
+ config.add_route('idea_add', '/idea_add',
+ view='shootout.views.idea_add',
+ view_permission='post',
+ view_renderer='templates/idea_add.pt')
+ config.add_route('idea_vote', '/idea_vote/{idea_id}',
+ view_permission = 'post',
+ view='shootout.views.idea_vote')
+ config.add_route('register', '/register',
+ view='shootout.views.user_add',
+ view_renderer='templates/user_add.pt')
+ config.add_route('login', '/login',
+ view='shootout.views.login_view')
+ config.add_route('about', '/about',
+ view='shootout.views.about_view',
+ view_renderer='templates/about.pt')
+ config.add_route('main', '/',
+ view='shootout.views.main_view',
+ view_renderer='templates/main.pt')
return config.make_wsgi_app()
+
View
119 shootout/configure.zcml
@@ -1,119 +0,0 @@
-<configure xmlns="http://pylonshq.com/pyramid"
- i18n_domain="repoze.bfg">
-
- <include package="pyramid_zcml" />
-
- <route
- name="idea"
- path="ideas/:idea"
- view=".views.idea_view"
- factory=".models.URLDispatchRootFactory"
- />
-
- <route
- name="user"
- path="users/:user"
- view=".views.user_view"
- factory=".models.URLDispatchRootFactory"
- />
-
- <route
- name="tag"
- path="tags/:tag"
- view=".views.tag_view"
- />
-
- <view
- for=".models.IRange"
- view=".views.user_view"
- name="user_view"
- permission="view"
- />
-
- <view
- for=".models.IRange"
- view=".views.main_view"
- permission="view"
- />
-
- <view
- for=".models.IRange"
- view=".views.user_add"
- name="register"
- permission="view"
- />
-
- <view
- for=".models.IRange"
- view=".views.idea_add"
- name="idea_add"
- permission="post"
- />
-
- <view
- for=".models.IRange"
- view=".views.idea_vote"
- name="idea_vote"
- permission="post"
- />
-
- <view
- for=".models.IRange"
- view=".views.logout_view"
- name="logout"
- permission="post"
- />
-
- <view
- for=".models.IRange"
- view=".views.login_view"
- name="login"
- permission="post"
- />
-
- <view
- for=".models.IRange"
- view=".views.cloud_view"
- name="cloud"
- permission="view"
- />
-
- <view
- for=".models.IRange"
- view=".views.latest_view"
- name="latest"
- permission="view"
- />
-
- <view
- for=".models.IRange"
- view=".views.login_form_view"
- name="login_form"
- permission="view"
- />
-
- <view
- for=".models.IRange"
- view=".views.toolbar_view"
- name="toolbar"
- permission="view"
- />
-
- <view
- for=".models.IRange"
- view=".views.static_view"
- name="resources"
- />
-
- <view
- for=".models.IRange"
- view=".views.about_view"
- name="about"
- />
-
- <remoteuserauthenticationpolicy
- environ_key="REMOTE_USER"/>
-
- <aclauthorizationpolicy/>
-
-</configure>
View
9 shootout/deliverance/rules/standardrules.xml
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<rules xmlns:xi="http://www.w3.org/2001/XInclude" xmlns="http://www.plone.org/deliverance">
- <prepend theme="//head" content="//head/link" nocontent="ignore" />
- <prepend theme="//head" content="//head/style" nocontent="ignore" />
- <append theme="//head" content="//head/script" nocontent="ignore" />
- <append theme="//head" content="//head/meta" nocontent="ignore" />
- <append-or-replace theme="//head" content="//head/title"
- nocontent="ignore" />
-</rules>
View
13 shootout/deliverance/rules/thewildwest.xml
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<rules xmlns:xi="http://www.w3.org/2001/XInclude" xmlns="http://www.plone.org/deliverance" >
- <xi:include href="standardrules.xml" />
-
- <copy theme="//div[@id='menu']" content="//div[@id='menu']/*" nocontent="ignore"/>
- <append theme="//div[@id='cloud']" content="//div[@id='cloud']/*" nocontent="ignore" />
- <append theme="//div[@id='login_form']" content="//div[@id='login_form']/*" nocontent="ignore" />
- <append theme="//div[@id='latest']" content="//div[@id='latest']/*" nocontent="ignore" />
- <copy theme="//div[@id='toolbar']" content="//div[@id='toolbar']/*" nocontent="ignore" />
- <prepend theme="//div[@id='message']" content="//div[@id='message']/*" nocontent="ignore" />
- <prepend theme="//div[@id='sections']" content="//div[@id='sections']/*" nocontent="ignore" />
- <copy theme="//div[@id='footer']" content="//div[@id='footer']/*" nocontent="ignore" />
-</rules>
View
302 shootout/models.py
@@ -1,177 +1,169 @@
-from zope.interface import implements
-from zope.interface import Interface
+try:
+ import hashlib
+ sha1 = hashlib.sha1
+except ImportError:
+ import sha
+ sha1 = sha.new
-from zope.sqlalchemy import ZopeTransactionExtension
+from random import sample
+from string import letters
-from pyramid.security import Allow
-from pyramid.security import Everyone
-from pyramid.security import Authenticated
+import transaction
+
+from sqlalchemy import Table, Column, ForeignKey
+from sqlalchemy.orm import relation, backref, column_property
+from sqlalchemy.types import Integer, Unicode, UnicodeText
+
+from sqlalchemy.exc import IntegrityError
+from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
-from sqlalchemy.orm import mapper
-from sqlalchemy.orm import column_property
-from sqlalchemy.orm import relation
-
-from sqlalchemy import Table
-from sqlalchemy import ForeignKey
-from sqlalchemy import Integer
-from sqlalchemy import String
-from sqlalchemy import Column
-from sqlalchemy import Text
-from sqlalchemy import MetaData
-from sqlalchemy import create_engine
-
-from repoze.who.plugins.sql import SQLAuthenticatorPlugin
-from repoze.who.plugins.sql import default_password_compare
-DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
+from zope.sqlalchemy import ZopeTransactionExtension
-def connection_factory():
- session = DBSession()
- return session.connection().connection.connection
-
-def make_authenticator_plugin():
- query = "SELECT username,password FROM users where username = :login;"
- conn_factory = connection_factory
- compare_fn = default_password_compare
- return SQLAuthenticatorPlugin(query, conn_factory, compare_fn)
-
-metadata = MetaData()
-
-users_table = Table(
- 'users',
- metadata,
- Column('user_id', Integer, primary_key=True),
- Column('username', String(20), unique=True),
- Column('password', String(20)),
- Column('name', String(50)),
- Column('email', String(50)),
- Column('hits', Integer),
- Column('misses', Integer),
- Column('delivered_hits', Integer),
- Column('delivered_misses', Integer),
-)
+from pyramid.security import Everyone
+from pyramid.security import Authenticated
+from pyramid.security import Allow
-class IUser(Interface):
- pass
-
-class User(object):
- implements(IUser)
- def __init__(self,username,password,name,email):
- self.username=username
- self.password=password
- self.name=name
- self.email=email
- self.hits=0
- self.misses=0
- self.delivered_hits=0
- self.delivered_misses=0
-
-user_mapper = mapper(User, users_table)
-
-tags_table = Table(
- 'tags',
- metadata,
- Column('tag_id', Integer, primary_key=True),
- Column('name', String(50), unique=True, nullable=False, index=True)
-)
-ideas_tags_table = Table(
- 'ideas_tags',
- metadata,
- Column('idea_id', Integer, ForeignKey('ideas.idea_id'), primary_key=True),
- Column('tag_id', Integer, ForeignKey('tags.tag_id'), primary_key=True),
+DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
+Base = declarative_base()
+
+
+def hash_password(salt, password):
+ return sha1(salt + password).hexdigest()
+
+class User(Base):
+ """
+ Application's user model.
+ """
+ __tablename__ = 'users'
+ user_id = Column(Integer, primary_key=True)
+ username = Column(Unicode(20), unique=True)
+ password = Column(Unicode(53))
+ name = Column(Unicode(50))
+ email = Column(Unicode(50))
+ hits = Column(Integer, default=0)
+ misses = Column(Integer, default=0)
+ delivered_hits = Column(Integer, default=0)
+ delivered_missed = Column(Integer, default=0)
+
+ def __init__(self, username, password, name, email):
+ self.username = username
+ self.name = name
+ self.email = email
+
+ salt = ''.join(sample(letters, 8))
+ self.password = 'SHA|%s|%s' % (salt, hash_password(salt, password))
+
+ @classmethod
+ def get_by_username(cls, username):
+ return DBSession.query(cls).filter(cls.username==username).first()
+
+ @classmethod
+ def check_password(cls, username, password):
+ user = cls.get_by_username(username)
+ if not user:
+ return False
+ (salt, user_password) = user.password.split('|')[1:]
+ return user_password == hash_password(salt, password)
+
+
+ideas_tags = Table('ideas_tags', Base.metadata,
+ Column('idea_id', Integer, ForeignKey('ideas.idea_id')),
+ Column('tag_id', Integer, ForeignKey('tags.tag_id'))
)
-class ITag(Interface):
- pass
-class Tag(object):
- implements(ITag)
+class Tag(Base):
+ """
+ Idea's tag model.
+ """
+ __tablename__ = 'tags'
+ tag_id = Column(Integer, primary_key=True)
+ name = Column(Unicode(50), unique=True, index=True)
+
def __init__(self, name):
self.name = name
-class IIdeaTag(Interface):
- pass
-
-class IdeaTag(object):
- implements(IIdeaTag)
-
-tag_mapper = mapper(Tag, tags_table)
-
-ideas_table = Table(
- 'ideas',
- metadata,
- Column('idea_id', Integer, primary_key=True),
- Column('target', Integer),
- Column('author', Integer, ForeignKey('users.user_id')),
- Column('title', Text),
- Column('text', Text),
- Column('hits', Integer),
- Column('misses', Integer),
-)
-
-class IIdea(Interface):
- pass
-
-class Idea(object):
- implements(IIdea)
- __acl__ = [ (Allow, Everyone, 'view'), ]
- def __init__(self, target, author, title, text):
- self.target = target
- self.author = author
- self.title = title
- self.text = text
- self.hits = 0
- self.misses = 0
-
-hit_percentage = (
- (ideas_table.c.hits > 0 or ideas_table.c.misses > 0) and
- (ideas_table.c.hits /
- (ideas_table.c.hits+ideas_table.c.misses)*100) or 0
+ @staticmethod
+ def extract_tags(tags_string):
+ tags = tags_string.replace(';',' ').replace(',',' ')
+ tags = [tag.lower() for tag in tags.split()]
+ tags = set(tags)
+
+ if '' in tags:
+ tags.remove('')
+ return tags
+
+ @classmethod
+ def get_by_name(cls, tag_name):
+ tag = DBSession.query(cls).filter(cls.name==tag_name)
+ return tag.first()
+
+ @classmethod
+ def create_tags(cls, tags_string):
+ tags_list = cls.extract_tags(tags_string)
+ tags = []
+
+ for tag_name in tags_list:
+ tag = cls.get_by_name(tag_name)
+ if not tag:
+ tag = Tag(name=tag_name)
+ DBSession.add(tag)
+ tags.append(tag)
+
+ return tags
+
+
+class Idea(Base):
+ __tablename__ = 'ideas'
+ idea_id = Column(Integer, primary_key=True)
+ target = Column(Integer)
+ author_id = Column(Integer, ForeignKey('users.user_id'))
+ author = relation(User, cascade="delete",
+ backref=backref('ideas', order_by=User.username))
+ title = Column(UnicodeText)
+ text = Column(UnicodeText)
+ hits = Column(Integer, default=0)
+ misses = Column(Integer, default=0)
+ tags = relation(Tag, secondary=ideas_tags, backref='ideas')
+
+ hit_percentage = (hits / (hits + misses) * 100)
+ hit_percentage = column_property(
+ hit_percentage.label('hit_percentage')
)
-hit_percentage = column_property(hit_percentage.label('hit_percentage'))
-
-total_votes = column_property(
- (ideas_table.c.hits + ideas_table.c.misses).label('total_votes')
- )
+ total_votes = column_property((hits + misses).label('total_votes'))
-vote_differential = column_property(
- (ideas_table.c.hits-ideas_table.c.misses).label('vote_differential')
+ vote_differential = column_property(
+ (hits - misses).label('vote_differential')
)
-idea_mapper = mapper(Idea, ideas_table, properties={
- 'total_votes':total_votes,
- 'vote_differential':vote_differential,
- 'hit_percentage':hit_percentage,
- 'users':relation(User, order_by=users_table.c.user_id),
- 'tags':relation(Tag, secondary=ideas_tags_table, backref='ideas'),
-})
-
-idea_tag_mapper = mapper(IdeaTag, ideas_tags_table)
-
-class IRange(Interface):
- pass
-
-class Range(object):
- implements(IRange)
- __acl__ = [ (Allow, Everyone, 'view'), (Allow, Authenticated, 'post')]
-
-class URLDispatchRootFactory:
- def __init__(self, environ):
- self.__dict__.update(environ['bfg.routes.matchdict'])
-
-firing_range = Range()
-
-def get_root(environ):
- return firing_range
-
-def initialize_sql(db_string, echo=False):
- engine = create_engine(db_string, echo=echo)
+ @classmethod
+ def get_by_id(cls, idea_id):
+ return DBSession.query(cls).filter(cls.idea_id==idea_id).one()
+
+ @classmethod
+ def get_by_tagname(cls, tag_name):
+ return DBSession.query(Idea).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]
+
+class RootFactory(object):
+ __acl__ = [
+ (Allow, Everyone, 'view'),
+ (Allow, Authenticated, 'post')
+ ]
+ def __init__(self, request):
+ pass
+
+def initialize_sql(engine):
DBSession.configure(bind=engine)
- metadata.bind = engine
- metadata.create_all(engine)
- return engine
+ Base.metadata.bind = engine
+ Base.metadata.create_all(engine)
View
42 shootout/resources/thewildwest/index.html
@@ -1,42 +0,0 @@
-<!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">
-<head>
-<title>The Wild West</title>
-<meta http-equiv="content-type" content="text/html; charset=utf-8" />
-<link href="default.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="wrapper">
- <div id="header">
- <h1>Shootout</h1>
- <h2>repoze.bfg demo app</h2>
- </div>
- <div id="menu">
- <ul>
- <li><a href="/" class="active">Home</a></li>
- <li><a href="/about">About this demo</a></li>
- </ul>
- </div>
- <div id="content">
- <div id="sidebar">
- <div id="login_form">
- </div>
- <div id="cloud">
- </div>
- <div id="latest">
- </div>
- </div>
- <div id="main">
- <div id="toolbar"></div>
- <div id="message"></div>
- <div id="sections">
- </div>
- </div>
- <div style="clear: both; height: 1px;"></div>
- </div>
- <div id="footer">
- <p>Copyright &copy; 2010 <a href="http://www.delaguardia.com.mx">Carlos de la Guardia</a>. Powered by <a href="http://docs.pylonshq.com">Pyramid</a>. Design by <a href="http://www.sumanasa.com/">Sumanasa.com</a>.</p>
- </div>
-</div>
-</body>
-</html>
View
0 shootout/resources/thewildwest/default.css → shootout/static/default.css
File renamed without changes.
View
BIN shootout/static/favicon.ico
Binary file not shown.
View
0 shootout/resources/thewildwest/images/bg.gif → shootout/static/images/bg.gif
File renamed without changes
View
0 ...t/resources/thewildwest/images/bullet.gif → shootout/static/images/bullet.gif
File renamed without changes
View
0 ...tout/resources/thewildwest/images/cbg.gif → shootout/static/images/cbg.gif
File renamed without changes
View
0 ...tout/resources/thewildwest/images/fbg.gif → shootout/static/images/fbg.gif
File renamed without changes
View
0 ...tout/resources/thewildwest/images/gun.jpg → shootout/static/images/gun.jpg
File renamed without changes
View
0 .../resources/thewildwest/images/listoff.gif → shootout/static/images/listoff.gif
File renamed without changes
View
0 ...t/resources/thewildwest/images/liston.gif → shootout/static/images/liston.gif
File renamed without changes
View
0 ...tout/resources/thewildwest/images/sbg.gif → shootout/static/images/sbg.gif
File renamed without changes
View
75 shootout/templates/about.pt
@@ -1,30 +1,53 @@
+<!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"
xmlns:tal="http://xml.zope.org/namespaces/tal">
- <head>
- <title>Shootout</title>
- </head>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <link href="${request.static_url('shootout:static/shootout.css')}" rel="stylesheet" type="text/css" />
+ <title>Shootout</title>
+ </head>
<body>
- <div id="menu">
- <ul>
- <li><a href="${app_url}">Home</a></li>
- </ul>
- </div>
- <div tal:replace="structure toolbar" />
- <div tal:replace="structure cloud" />
- <div tal:replace="structure latest" />
- <div tal:replace="structure login_form" />
- <div id="sections">
- <h1>shootout</h1>
- <p>This is a demo application for the <a href="http://docs.pylonshq.com">Pyramid</a> Python web framework.</p>
- <p>The concepts demonstrated in the code include:</p>
- <ul>
- <li>Urldispatch mechanism (similar to routes).</li>
- <li>Integration with the repoze.who authentication endware.</li>
- <li>Integration with the deliverance filter for theming.</li>
- <li>SQLAlchemy based models.</li>
- </ul>
- <p>The code can be checked out from the version control repository at:</p>
- <p><a href="https://github.com/Pylons/shootout">https://github.com/Pylons/shootout</a></p>
- </div>
-</body>
+ <div id="wrapper">
+ <div id="header">
+ <h1>Shootout</h1>
+ <h2>Pyramid web framework demo app</h2>
+ </div>
+ <div id="menu">
+ <ul>
+ <li><a href="${request.route_url('main')}">Home</a></li>
+ </ul>
+ </div>
+ <div id="content">
+ <div id="sidebar">
+ <div tal:replace="structure login_form" />
+ <div tal:replace="structure cloud" />
+ <div tal:replace="structure latest" />
+ </div>
+ <div id="main">
+ <div tal:replace="structure toolbar" />
+ <div id="message"></div>
+ <div id="sections">
+ <h1>shootout</h1>
+ <p>This is a demo application for the <a href="http://docs.pylonshq.com">Pyramid</a> Python web framework.</p>
+ <p>The concepts demonstrated in the code include:</p>
+ <ul>
+ <li>Urldispatch mechanism (similar to routes).</li>
+ <li>Built-in authorization and authentication mechanism.</li>
+ <li>Integration with the pyramid_simpleform.</li>
+ <li>SQLAlchemy based models.</li>
+ </ul>
+ <p>The code can be checked out from the version control repository at:</p>
+ <p><a href="https://github.com/Pylons/shootout">https://github.com/Pylons/shootout</a></p>
+ </div>
+ </div>
+ </div>
+ <div id="footer">
+ <p>
+ Copyright &copy; 2010 <a href="http://www.delaguardia.com.mx">Carlos de la Guardia</a> and Łukasz Fidosz.
+ Powered by <a href="http://docs.pylonshq.com">Pyramid</a>.
+ Design by <a href="http://www.sumanasa.com/">Sumanasa.com</a>.
+ </p>
+ </div>
+ </div>
+ </body>
</html>
View
2 shootout/templates/cloud.pt
@@ -1,5 +1,5 @@
<div id="cloud" xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal">
<h2>Tag Cloud</h2>
- <a tal:repeat="tag cloud" href="${app_url}/tags/${tag[0]}" style="font-size: ${tag[2]}px">${tag[0]} </a>
+ <a tal:repeat="tag cloud" href="${request.route_url('tag', tag_name=tag[0])}" style="font-size: ${tag[2]}px">${tag[0]} </a>
</div>
View
4 shootout/templates/latest.pt
@@ -2,7 +2,9 @@
xmlns:tal="http://xml.zope.org/namespaces/tal">
<h2>Latest shots</h2>
<ul>
- <li tal:repeat="idea latest"><a class="idea" href="${app_url}/ideas/${idea.idea_id}">${idea.title}</a>.</li>
+ <li tal:repeat="idea latest">
+ <a class="idea" href="${request.route_url('idea', idea_id=idea.idea_id)}">${idea.title}</a>.
+ </li>
</ul>
</div>
View
2 shootout/templates/login.pt
@@ -1,6 +1,6 @@
<div id="login_form" xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal">
- <form id="login_form" action="?__do_login=true" method="post" tal:condition="not loggedin">
+ <form id="login_form" action="/login" method="post" tal:condition="not loggedin">
<h2>Log In</h2>
<fieldset>
<label for="login">Username:</label>
View
7 shootout/templates/tag.pt
@@ -1,3 +1,4 @@
+<!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"
xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
@@ -17,7 +18,11 @@
<div id="sections">
<h1>${tag}</h1>
<ul>
- <li tal:repeat="idea ideas"><span class="tags"><a tal:repeat="tag idea.tags" href="${app_url}/tags/${tag.name}">${tag.name}</a></span> <a href="${app_url}/ideas/${idea.idea_id}">${idea.title}</a>, by <a class="byline" href="${app_url}/users/${idea.users.username}">${idea.users.name}</a> <span class="hits">${idea.hits}</span> hits, <span class="misses">${idea.misses}</span> misses.</li>
+ <li tal:repeat="idea ideas">
+ <span class="tags"><a tal:repeat="tag idea.tags" href="${app_url}/tags/${tag.name}">${tag.name}</a></span>
+ <a href="${app_url}/ideas/${idea.idea_id}">${idea.title}</a>, by <a class="byline" href="${app_url}/users/${idea.users.username}">${idea.users.name}</a>
+ <span class="hits">${idea.hits}</span> hits, <span class="misses">${idea.misses}</span> misses.
+ </li>
</ul>
</div>
</body>
View
9 shootout/templates/toolbar.pt
@@ -1,5 +1,10 @@
<div xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal" id="toolbar">
- <span tal:condition="viewer_username" class="username"><a href="${app_url}/idea_add">Post an idea</a>. You are logged in as <b>${viewer_username}</b>. <a href="${app_url}/logout">Logout</a>.</span>
- <span tal:condition="not viewer_username"><b>You need to log in to post or vote.</b> Not a member? <b><a href="${app_url}/register">Register</a></b>.</span>
+ <span tal:condition="viewer_username" class="username">
+ <a href="${request.route_url('idea_add')}">Post an idea</a>. You are logged in as <b>${viewer_username}</b>.
+ <a href="${request.route_url('logout')}">Logout</a>.</span>
+ <span tal:condition="not viewer_username">
+ <b>You need to log in to post or vote.</b> Not a member? <b>
+ <a href="${request.route_url('register')}">Register</a></b>.
+ </span>
</div>
View
10 shootout/templates/user_add.pt
@@ -6,16 +6,18 @@
<body>
<div id="menu">
<ul>
- <li><a href="${app_url}">Home</a></li>
- <li><a href="${app_url}/about">About this demo</a></li>
+ <li><a href="${request.route_url('main')}">Home</a></li>
+ <li><a href="${request.route_url('about')}">About this demo</a></li>
</ul>
</div>
<div tal:replace="structure toolbar" />
<div tal:replace="structure cloud" />
<div tal:replace="structure latest" />
<div tal:replace="structure login_form" />
- <div id="message" tal:condition="message">
- <p>${message}</p>
+ <div id="message" tal:condition="request.session.peek_flash()">-->
+ <p tal:repeat="message request.session.pop_flash()">
+ ${message}
+ </p>
</div>
<div id="sections">
<h1>Register</h1>
View
146 shootout/tests.py
@@ -1,140 +1,24 @@
import unittest
-
+from pyramid.config import Configurator
from pyramid import testing
-class ViewTests(unittest.TestCase):
+def _initTestingDB():
+ from sqlalchemy import create_engine
+ from shootout.models import initialize_sql
+ session = initialize_sql(create_engine('sqlite://'))
+ return session
+
+class TestMyView(unittest.TestCase):
def setUp(self):
- DB_STRING = 'sqlite:///:memory:'
- from shootout.models import initialize_sql
- self.engine = initialize_sql(DB_STRING, echo=False)
self.config = testing.setUp()
+ _initTestingDB()
def tearDown(self):
- import transaction
- transaction.abort()
testing.tearDown()
- def _registerCommonTemplates(self):
- self.config.testing_add_renderer('templates/login.pt')
- self.config.testing_add_renderer('templates/toolbar.pt')
- self.config.testing_add_renderer('templates/cloud.pt')
- self.config.testing_add_renderer('templates/latest.pt')
-
- def _addUser(self, username='username'):
- from shootout.models import User
- from shootout.models import DBSession
- session = DBSession()
- user = User(username=username, password='password', name='name',
- email='email')
- session.add(user)
- session.flush()
- return user
-
- def _addIdea(self, target=None):
- from shootout.models import Idea
- from shootout.models import DBSession
- session = DBSession()
- user = self._addUser()
- idea = Idea(target=target, author=user.user_id, title='title',
- text='text')
- session.add(idea)
- session.flush()
- return idea
-
- def test_main_view(self):
- from shootout.views import main_view
- self.config.testing_securitypolicy('username')
- self._registerCommonTemplates()
- renderer = self.config.testing_add_renderer('templates/main.pt')
- request = testing.DummyRequest(params={'message':'abc'})
- context = testing.DummyModel()
- main_view(context, request)
- self.assertEqual(renderer.username, 'username')
- self.assertEqual(renderer.app_url, 'http://example.com')
- self.assertEqual(renderer.message, 'abc')
- self.assertEqual(len(renderer.toplists), 4)
-
- def test_idea_add_nosubmit(self):
- from shootout.views import idea_add
- self.config.testing_securitypolicy('username')
- self._registerCommonTemplates()
- renderer = self.config.testing_add_renderer('templates/idea_add.pt')
- request = testing.DummyRequest(params={'message':'abc'})
- context = testing.DummyModel()
- idea_add(context, request)
- self.assertEqual(renderer.app_url, 'http://example.com')
- self.assertEqual(renderer.message, 'abc')
- self.assertEqual(renderer.target, None)
- self.assertEqual(renderer.kind, 'idea')
-
- def test_idea_add_nosubmit_comment(self):
- from shootout.views import idea_add
- self.config.testing_securitypolicy('username')
- self._registerCommonTemplates()
- renderer = self.config.testing_add_renderer('templates/idea_add.pt')
- idea = self._addIdea()
- request = testing.DummyRequest(
- params={'message':'abc', 'target':idea.idea_id})
- context = testing.DummyModel()
- idea_add(context, request)
- self.assertEqual(renderer.app_url, 'http://example.com')
- self.assertEqual(renderer.message, 'abc')
- self.assertEqual(renderer.target, idea)
- self.assertEqual(renderer.kind, 'comment')
-
- def test_idea_add_nosubmit_idea(self):
- from shootout.views import idea_add
- self.config.testing_securitypolicy('username')
- self._registerCommonTemplates()
- renderer = self.config.testing_add_renderer('templates/idea_add.pt')
- request = testing.DummyRequest(
- params={'message':'abc', 'target':None})
- context = testing.DummyModel()
- idea_add(context, request)
- self.assertEqual(renderer.app_url, 'http://example.com')
- self.assertEqual(renderer.message, 'abc')
- self.assertEqual(renderer.target, None)
- self.assertEqual(renderer.kind, 'idea')
-
- def test_idea_add_submit_schema_fail_empty_params(self):
- from shootout.views import idea_add
- self.config.testing_securitypolicy('username')
- idea = self._addIdea()
- request = testing.DummyRequest(
- params={'target':idea.idea_id, 'form.submitted':True}
- )
- context = testing.DummyModel()
- response = idea_add(context, request)
- self.assertEqual(response.status, '302 Found')
- self.assertEqual(response.location, 'http://example.com/idea_add?message=tags%3A%20Missing%20value%0Atext%3A%20Missing%20value%0Atitle%3A%20Missing%20value')
-
- def test_idea_add_submit_schema_succeed(self):
- from shootout.views import idea_add
- from shootout.models import DBSession
- from shootout.models import Idea
- self.config.testing_securitypolicy('username')
- request = testing.DummyRequest(
- params={
- 'form.submitted':True,
- 'tags':'abc def',
- 'text':'My idea is cool',
- 'title':'My idea'
- }
- )
- context = testing.DummyModel()
- user = self._addUser('username')
- response = idea_add(context, request)
- self.assertEqual(response.status, '302 Found')
- self.assertEqual(response.location, 'http://example.com/ideas/1')
- session = DBSession()
- result = list(session.query(Idea))
- self.assertEqual(len(result), 1)
- idea = result[0]
- self.assertEqual(idea.idea_id, 1)
- self.assertEqual(idea.text, 'My idea is cool')
- self.assertEqual(idea.title, 'My idea')
- self.assertEqual(idea.author, user.user_id)
- self.assertEqual(len(idea.tags), 2)
- self.assertEqual(idea.tags[0].name, 'abc')
- self.assertEqual(idea.tags[1].name, 'def')
-
+ def test_it(self):
+ from shootout.views import my_view
+ request = testing.DummyRequest()
+ info = my_view(request)
+ self.assertEqual(info['root'].name, 'root')
+ self.assertEqual(info['project'], 'shootout')
View
496 shootout/views.py
@@ -1,157 +1,179 @@
-try:
- import hashlib
- sha1 = hashlib.sha1
-except ImportError:
- import sha
- sha1 = sha.new
-import os
import math
import urllib
-import webob
import formencode
-from webob.exc import HTTPFound
-from webob.exc import HTTPUnauthorized
-from sqlalchemy.sql import func
-
-from pyramid.renderers import render_to_response
-from pyramid.renderers import render
-from pyramid.security import authenticated_userid
-from pyramid.view import static
+from pyramid.renderers import render_to_response, render
+from pyramid.httpexceptions import HTTPMovedPermanently, HTTPFound
+from pyramid.security import authenticated_userid, remember, forget
from shootout.models import DBSession
-from shootout.models import User
-from shootout.models import Idea
-from shootout.models import Tag
-from shootout.models import IdeaTag
+from shootout.models import User, Idea, Tag
-resources = os.path.join(
- os.path.abspath(os.path.dirname(__file__)), 'resources')
-static_view = static(resources)
COOKIE_VOTED = 'shootout.voted'
-def idea_bunch(order_by, how_many=10):
- session = DBSession()
- return session.query(Idea).join('users').filter(
- Idea.target==None).order_by(order_by).all()[:how_many]
-def main_view(context, request):
- params = request.params
- message = params.get('message','')
- hitpct = idea_bunch(Idea.hit_percentage.desc(), 10)
- top = idea_bunch(Idea.hits.desc(), 10)
- bottom = idea_bunch(Idea.misses.desc(), 10)
- last10 = idea_bunch(Idea.idea_id.desc(), 10)
- toplists=[
- {'title':'Latest shots','items':last10},
- {'title':'Most hits','items':top},
- {'title':'Most misses','items':bottom},
- {'title':'Best performance','items':hitpct},
- ]
- login_form = login_form_view(context,request)
- return render_to_response(
- 'templates/main.pt',
- dict(
- username = authenticated_userid(request),
- app_url=request.application_url,
- message=message,
- toolbar=toolbar_view(context,request),
- cloud=cloud_view(context,request),
- latest=latest_view(context,request),
- login_form=login_form,
- toplists=toplists
- ),
- request,
- )
+def main_view(request):
+ import pdb;pdb.set_trace()
+ hitpct = Idea.ideas_bunch(Idea.hit_percentage.desc())
+ top = Idea.ideas_bunch(Idea.hits.desc())
+ bottom = Idea.ideas_bunch(Idea.misses.desc())
+ last10 = Idea.ideas_bunch(Idea.idea_id.desc())
+
+ toplists = [
+ {'title': 'Latest shots', 'items': last10},
+ {'title': 'Most hits', 'items': top},
+ {'title': 'Most misses', 'items': bottom},
+ {'title': 'Best performance', 'items': hitpct},
+ ]
+
+ login_form = login_form_view(request)
+
+ return {
+ 'username': authenticated_userid(request),
+ 'toolbar': toolbar_view(request),
+ 'cloud': cloud_view(request),
+ 'latest': latest_view(request),
+ 'login_form': login_form,
+ 'toplists': toplists,
+ }
-def idea_vote(context, request):
- app_url = request.application_url
- response = webob.Response()
+
+def idea_vote(request):
params = request.params
target = params.get('target')
- session = DBSession()
- idea = session.query(Idea).filter(Idea.idea_id==target).one()
+
+ idea = Idea.get_by_id(target)
voter_username = authenticated_userid(request)
- voter = session.query(User).filter(User.username==voter_username).one()
- poster = session.query(User).filter(User.user_id==idea.author).one()
+ voter = User.get_by_username(voter_username)
+
if params.get('form.vote_hit'):
- vote='hit'
- idea.hits=idea.hits+1
- poster.hits=poster.hits+1
- voter.delivered_hits=voter.delivered_hits+1
- if params.get('form.vote_miss'):
- vote='miss'
- idea.misses=idea.misses+1
- poster.misses=poster.misses+1
- voter.delivered_misses=voter.delivered_misses+1
- cookie = "%s.%s.%s" % (COOKIE_VOTED,idea.idea_id,voter_username)
- response.set_cookie(cookie.encode('utf-8'), vote)
+ vote = 'hit'
+ idea.hits += 1
+ idea.author.hits += 1
+ voter.delivered_hits += 1
+
+ elif params.get('form.vote_miss'):
+ vote = 'miss'
+ idea.misses += 1
+ idea.author.misses += 1
+ voter.delivered_misses += 1
+
session.flush()
- url = "%s/ideas/%s" % (app_url,idea.idea_id)
- response.status = '301 Moved Permanently'
- response.headers['Location'] = url
+
+ #:request.session.
+
+ redirect_url = request.route_url('idea', idea_id=idea.id)
+ response = HTTPMovedPermanently(location=redirect_url)
+
+ cookie = '.'.join((COOKIE_VOTED, idea.idea_id, voter_username))
+ response.set_cookie(cookie.encode('utf-8'), vote)
+
return response
+
+class Registration(formencode.Schema):
+ allow_extra_fields = True
+ username = formencode.validators.PlainText(not_empty=True)
+ password = formencode.validators.PlainText(not_empty=True)
+ email = formencode.validators.Email(resolve_domain=False)
+ name = formencode.validators.String(not_empty=True)
+ password = formencode.validators.String(not_empty=True)
+ confirm_password = formencode.validators.String(not_empty=True)
+ chained_validators = [
+ formencode.validators.FieldsMatch('password','confirm_password')
+ ]
+
+
+def user_add(request):
+ post_data = request.POST
+ if 'form.submitted' in post_data:
+ headers = []
+ username = post_data.get('username', None)
+ password = post_data.get('password', None)
+ name = post_data.get('name', None)
+ email = post_data.get('email', None)
+
+ schema = Registration()
+ try:
+ schema.to_python(post_data)
+ except formencode.validators.Invalid, why:
+ why = str(why).splitlines()
+ for i in why:
+ request.session.flash(i)
+ url = request.route_url('register')
+ else:
+ session = DBSession()
+ user = User(username=username, password=password, name=name,
+ email=email)
+ session.add(user)
+ headers = remember(request, username)
+ url = request.route_url('main')
+ return HTTPFound(location=url, headers=headers)
+
+ login_form = login_form_view(request)
+
+ return {
+ 'toolbar': toolbar_view(request),
+ 'cloud': cloud_view(request),
+ 'latest': latest_view(request),
+ 'login_form': login_form,
+ }
+
class AddIdea(formencode.Schema):
allow_extra_fields = True
title = formencode.validators.String(not_empty=True)
text = formencode.validators.String(not_empty=True)
tags = formencode.validators.String(not_empty=True)
-def idea_add(context, request):
- app_url = request.application_url
- params = request.params
- message = params.get('message','')
+
+def idea_add(request):
+ post = request.POST
+ message = post.get('message','')
session = DBSession()
- if params.get('form.submitted'):
- target = params.get('target', None)
- title = params.get('title')
- text = params.get('text')
- tags = params.get('tags')
+
+ if post.get('form.submitted'):
+ target = post.get('target', None)
+ title = post.get('title')
+ text = post.get('text')
+ tags_string = post.get('tags')
schema = AddIdea()
try:
- schema.to_python(params)
+ schema.to_python(post)
except formencode.validators.Invalid, why:
- message=urllib.quote(str(why))
- url = "%s/idea_add?message=%s" % (app_url,message)
+ request.session.flash(message)
else:
- author_id = authenticated_userid(request)
- author = session.query(User).filter(
- User.username==author_id).one().user_id
+ author_username = authenticated_userid(request)
+ author = User.get_by_username(author_username)
idea = Idea(target=target, author=author, title=title, text=text)
session.add(idea)
- tags = tags.replace(';',' ').replace(',',' ')
- tags = [tag.lower() for tag in tags.split()]
- tags = set(tags)
- if '' in tags:
- tags.remove('')
- for tagname in tags:
- existent = session.query(Tag).filter(Tag.name==tagname).all()
- if not existent:
- tag = Tag(name=tagname)
- session.add(tag)
- idea.tags.append(tag)
- else:
- idea.tags.append(existent[0])
- url = "%s/ideas/%s" % (app_url, idea.idea_id)
- return HTTPFound(location=url)
+ tags = Tag.create_tags(tags_string)
+ if tags:
+ idea.tags = tags
+
+ redirect_url = request.route_url('idea', idea_id=idea.idea_id)
+
+ return HTTPFound(location=redirect_url)
+
target = params.get('target', None)
kind = 'idea'
if target is not None:
- target = session.query(Idea).join('users').filter(
+ target = session.query(Idea).join('author').filter(
Idea.idea_id==target).one()
kind = 'comment'
- login_form = login_form_view(context,request)
+ else:
+ kind = 'idea'
+ login_form = login_form_view(request)
+ app_url='oo'
return render_to_response(
'templates/idea_add.pt',
dict(
app_url=app_url,
message=message,
- toolbar=toolbar_view(context,request),
- cloud=cloud_view(context,request),
- latest=latest_view(context,request),
+ toolbar=toolbar_view(request),
+ cloud=cloud_view(request),
+ latest=latest_view(request),
login_form=login_form,
target=target,
kind=kind,
@@ -160,195 +182,111 @@ def idea_add(context, request):
request,
)
-class Registration(formencode.Schema):
- allow_extra_fields = True
- username = formencode.validators.PlainText(not_empty=True)
- password = formencode.validators.PlainText(not_empty=True)
- email = formencode.validators.Email(resolve_domain=False)
- name = formencode.validators.String(not_empty=True)
- password = formencode.validators.String(not_empty=True)
- confirm_password = formencode.validators.String(not_empty=True)
- chained_validators = [
- formencode.validators.FieldsMatch('password','confirm_password')]
-def user_add(context, request):
- app_url = request.application_url
- params = request.params
- message = params.get('message','')
- if params.get('form.submitted'):
- headers = []
- username = params.get('username', None)
- password = params.get('password', None)
- name = params.get('name', None)
- email = params.get('email', None)
- schema = Registration()
- session = DBSession()
- try:
- schema.to_python(params)
- except formencode.validators.Invalid, why:
- message=urllib.quote(str(why))
- url = "%s/register?message=%s" % (app_url, message)
- else:
- password='{SHA}%s' % sha1(password).hexdigest()
- user = User(username=username, password=password, name=name,
- email=email)
- session.add(user)
- # try to autolog the user in
- plugins = request.environ.get('repoze.who.plugins', {})
- identifier = plugins.get('auth_tkt')
- if identifier:
- identity = {'repoze.who.userid': username}
- headers = identifier.remember(request.environ, identity)
- request.environ['repoze.who.userid'] = username
- url = "%s?message=%s" % (app_url,message)
- return HTTPFound(location=url, headers=headers)
+def user_view(request):
+ username = request.matchdict['username']
+ user = User.get_by_username(username)
+ login_form = login_form_view(request)
+ return {
+ 'user': user,
+ 'toolbar': toolbar_view(request),
+ 'cloud': cloud_view(request),
+ 'latest': latest_view(context,request),
+ 'login_form' :login_form,
+ }
- login_form = login_form_view(context, request)
- return render_to_response(
- 'templates/user_add.pt',
- dict(
- message=message,
- toolbar=toolbar_view(context,request),
- cloud=cloud_view(context,request),
- latest=latest_view(context,request),
- login_form=login_form,
- app_url=app_url,
- ),
- request,
- )
-
-def user_view(context, request):
- app_url = request.application_url
- session = DBSession()
- user = session.query(User).filter(User.username==context.user).one()
- login_form = login_form_view(context, request)
- return render_to_response(
- 'templates/user.pt',
- dict(
- user=user,
- toolbar=toolbar_view(context,request),
- cloud=cloud_view(context,request),
- latest=latest_view(context,request),
- login_form=login_form,
- app_url=app_url,
- ),
- request,
- )
+def idea_view(request):
+ idea_id = request.matchdict['idea_id']
+ idea = Idea.get_by_id(idea_id)
-def idea_view(context, request):
- session = DBSession()
- idea = session.query(Idea).filter(Idea.idea_id==context.idea).one()
- poster = session.query(User).filter(User.user_id==idea.author).one()
viewer_username = authenticated_userid(request)
- idea_cookie = '%s.%s.%s' % (COOKIE_VOTED,idea.idea_id,viewer_username)
+ idea_cookie = '%s.%s.%s' % (COOKIE_VOTED, idea.idea_id, viewer_username)
voted = request.cookies.get(idea_cookie, None)
- comments = session.query(Idea).filter(Idea.target==context.idea).all()
- login_form = login_form_view(context, request)
- return render_to_response(
- 'templates/idea.pt',
- dict(
- app_url=request.application_url,
- toolbar=toolbar_view(context,request),
- cloud=cloud_view(context,request),
- latest=latest_view(context,request),
- login_form=login_form,
- poster=poster,
- voted=voted,
- comments=comments,
- viewer_username=viewer_username,
- idea=idea,
- ),
- request,
- )
-
-def tag_view(context, request):
- session = DBSession()
- ideas = session.query(Idea).filter(Idea.tags.any(name=context.tag)).all()
- login_form = login_form_view(context, request)
- return render_to_response(
- 'templates/tag.pt',
- dict(
- tag=context.tag,
- app_url=request.application_url,
- toolbar=toolbar_view(context,request),
- cloud=cloud_view(context,request),
- latest=latest_view(context,request),
- login_form=login_form,
- ideas=ideas,
- ),
- request,
- )
+ login_form = login_form_view(request)
-def about_view(context, request):
- login_form = login_form_view(context, request)
- return render_to_response(
- 'templates/about.pt',
- dict(
- app_url=request.application_url,
- toolbar=toolbar_view(context,request),
- cloud=cloud_view(context,request),
- latest=latest_view(context,request),
- login_form=login_form,
- ),
- request,
- )
+ return {
+ 'toolbar': toolbar_view(request),
+ 'cloud': cloud_view(request),
+ 'latest': latest_view(context,request),
+ 'login_form': login_form,
+ 'voted': voted,
+ 'viewer_username': viewer_username,
+ 'idea': idea,
+ }
-def logout_view(context, request):
- # the Location in the headers tells the form challenger to redirect
- return HTTPUnauthorized(headers=[('Location', request.application_url)])
-def login_view(context, request):
- return main_view(context, request)
+def tag_view(request):
+ tagname = request.matchdict['tagname']
+ ideas = Idea.get_by_tagname(tagname)
+ login_form = login_form_view(request)
+ return {
+ 'tag': tagname,
+ 'app_url': request.application_url,
+ 'toolbar': toolbar_view(request),
+ 'cloud': cloud_view(request),
+ 'latest': latest_view(context,request),
+ 'login_form': login_form,
+ 'ideas': ideas,
+ }
-def toolbar_view(context, request):
+def toolbar_view(request):
viewer_username = authenticated_userid(request)
return render(
'templates/toolbar.pt',
- dict(
- app_url=request.application_url,
- viewer_username=viewer_username,
- ),
- request,
- )
+ {'viewer_username': viewer_username},
+ request
+ )
-def login_form_view(context, request):
- loggedin = authenticated_userid(request)
- return render(
- 'templates/login.pt',
- dict(
- app_url=request.application_url,
- loggedin=loggedin,
- ),
- request,
- )
+def about_view(context, request):
+ return {
+ 'toolbar': toolbar_view(request),
+ 'cloud': cloud_view(request),
+ 'latest': latest_view(request),
+ 'login_form': login_form_view(request),
+ }
-def latest_view(context, request):
- latest = idea_bunch(Idea.idea_id.desc(), 10)
- return render(
- 'templates/latest.pt',
- dict(
- app_url=request.application_url,
- latest=latest,
- ),
- request,
- )
+def login_form_view(request):
+ logged_in = authenticated_userid(request)
+ return render('templates/login.pt', {'loggedin': logged_in}, request)
+
+def login_view(request):
+ main_view = request.route_url('main')
+ came_from = request.params.get('came_from', main_view)
+
+ post_data = request.POST
+ if 'submit' in post_data:
+ login = post_data['login']
+ password = post_data['password']
-def cloud_view(context, request):
+ if User.check_password(login, password):
+ headers = remember(request, login)
+ request.session.flash('Logged in successfully.')
+ return HTTPFound(location=came_from, headers=headers)
+
+ request.session.flash('Failed to login.')
+ return HTTPFound(location=came_from)
+
+def logout_view(request):
+ request.session.invalidate()
+ request.session.flash('Logged out successfully.')
+ headers = forget(request)
+ return HTTPFound(location=request.route_url('main'),
+ headers=headers)
+
+def latest_view(request):
+ latest = Idea.ideas_bunch(Idea.idea_id.desc())
+ return render('templates/latest.pt', {'latest': latest}, request)
+
+def cloud_view(request):
+ from sqlalchemy import func
session = DBSession()
tag_counts = session.query(
- Tag.name, func.count('*')).join(IdeaTag).group_by(Tag.name).all()
+ Tag.name, func.count('*')).join('ideas').group_by(Tag.name).all()
totalcounts = []
for tag in tag_counts:
weight = int((math.log(tag[1] or 1) * 4) + 10)
totalcounts.append((tag[0], tag[1],weight))
cloud = sorted(totalcounts, cmp=lambda x,y: cmp(x[0], y[0]))
- return render(
- 'templates/cloud.pt',
- dict(
- app_url=request.application_url,
- cloud=cloud
- ),
- request,
- )
+ return render('templates/cloud.pt', {'cloud': cloud}, request)
View
38 who.ini
@@ -1,38 +0,0 @@
-[plugin:form]
-# identification and challenge
-use = repoze.who.plugins.form:make_plugin
-login_form_qs = __do_login
-rememberer_name = auth_tkt
-
-[plugin:auth_tkt]
-# identification
-use = repoze.who.plugins.auth_tkt:make_plugin
-secret = secret
-cookie_name = shoot
-secure = False
-include_ip = False
-
-[plugin:sqlusers]
-# authentication
-use = shootout.models:make_authenticator_plugin
-
-[general]
-request_classifier = repoze.who.classifiers:default_request_classifier
-challenge_decider = repoze.who.classifiers:default_challenge_decider
-
-[identifiers]
-# plugin_name;classifier_name:.. or just plugin_name (good for any)
-plugins =
- form;browser
- auth_tkt
-
-[authenticators]
-# plugin_name;classifier_name.. or just plugin_name (good for any)
-plugins =
- sqlusers
-
-[challengers]
-# plugin_name;classifier_name:.. or just plugin_name (good for any)
-plugins =
- form
-

0 comments on commit 4390c18

Please sign in to comment.
Something went wrong with that request. Please try again.