changeset 110:64ff134868c4 trunk

update the example TurboGears app and include an example of using TurboGears wigets
author mgood
date Fri, 28 Jul 2006 18:57:55 +0000
parents 230ee6a2c6b2
children 2368c3becc52
files examples/turbogears/README.txt examples/turbogears/dev.cfg examples/turbogears/markuptest/config/app.cfg examples/turbogears/markuptest/controllers.py examples/turbogears/markuptest/model.py examples/turbogears/markuptest/release.py examples/turbogears/markuptest/templates/master.html examples/turbogears/markuptest/templates/sitetemplate.html examples/turbogears/markuptest/templates/welcome.html examples/turbogears/sample-prod.cfg examples/turbogears/setup.py examples/turbogears/start-markuptest.py
diffstat 12 files changed, 269 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/examples/turbogears/README.txt
+++ b/examples/turbogears/README.txt
@@ -1,4 +1,4 @@
 MarkupTest
 
 This is a TurboGears (http://www.turbogears.org) project. It can be
-started by running the start-markuptest.py script.
\ No newline at end of file
+started by running the start-markuptest.py script.
--- a/examples/turbogears/dev.cfg
+++ b/examples/turbogears/dev.cfg
@@ -24,7 +24,6 @@
 # for Windows users, sqlite URIs look like:
 # sqlobject.dburi="sqlite:///drive_letter:/path/to/file"
 
-
 # SERVER
 
 # Some server parameters that you may want to tweak
--- a/examples/turbogears/markuptest/config/app.cfg
+++ b/examples/turbogears/markuptest/config/app.cfg
@@ -10,10 +10,7 @@
 
 # which view (template engine) to use if one is not specified in the
 # template name
-# tg.defaultview = "kid"
 tg.defaultview = "markup"
-markup.search_path = ["%(current_dir_uri)s"]
-markup.outputformat = "xml"
 
 # The following kid settings determine the settings used by the kid serializer.
 
@@ -29,12 +26,92 @@
 # Allow every exposed function to be called as json,
 # tg.allow_json = False
 
-# Set to True if you'd like all of your pages to include MochiKit
-# tg.mochikit_all = False
+# List of Widgets to include on every page.
+# for exemple ['turbogears.mochikit']
+# tg.include_widgets = []
 
 # Set to True if the scheduler should be started
 # tg.scheduler = False
 
+# VISIT TRACKING
+# Each visit to your application will be assigned a unique visit ID tracked via
+# a cookie sent to the visitor's browser.
+# --------------
+
+# Enable Visit tracking
+visit.on=True
+
+# Number of minutes a visit may be idle before it expires.
+# visit.timeout=20
+
+# The name of the cookie to transmit to the visitor's browser.
+# visit.cookie.name="tg-visit"
+
+# Domain name to specify when setting the cookie (must begin with . according to
+# RFC 2109). The default (None) should work for most cases and will default to
+# the machine to which the request was made. NOTE: localhost is NEVER a valid
+# value and will NOT WORK.
+# visit.cookie.domain=None
+
+# Specific path for the cookie
+# visit.cookie.path="/"
+
+# The name of the VisitManager plugin to use for visitor tracking.
+visit.manager="sqlobject"
+
+# Database class to use for visit tracking
+visit.soprovider.model = "markuptest.model.Visit"
+
+# IDENTITY
+# General configuration of the TurboGears Identity management module
+# --------
+
+# Switch to turn on or off the Identity management module
+identity.on=True
+
+# [REQUIRED] URL to which CherryPy will internally redirect when an access
+# control check fails. If Identity management is turned on, a value for this
+# option must be specified.
+identity.failure_url="/login"
+
+# identity.provider='sqlobject'
+
+# The names of the fields on the login form containing the visitor's user ID
+# and password. In addition, the submit button is specified simply so its
+# existence may be stripped out prior to passing the form data to the target
+# controller.
+# identity.form.user_name="user_name"
+# identity.form.password="password"
+# identity.form.submit="login"
+
+# What sources should the identity provider consider when determining the
+# identity associated with a request? Comma separated list of identity sources.
+# Valid sources: form, visit, http_auth
+# identity.source="form,http_auth,visit"
+
+# SqlObjectIdentityProvider
+# Configuration options for the default IdentityProvider
+# -------------------------
+
+# The classes you wish to use for your Identity model. Remember to not use reserved
+# SQL keywords for class names (at least unless you specify a different table
+# name using sqlmeta).
+identity.soprovider.model.user="markuptest.model.User"
+identity.soprovider.model.group="markuptest.model.Group"
+identity.soprovider.model.permission="markuptest.model.Permission"
+
+# The password encryption algorithm used when comparing passwords against what's
+# stored in the database. Valid values are 'md5' or 'sha1'. If you do not
+# specify an encryption algorithm, passwords are expected to be clear text.
+#
+# The SqlObjectProvider *will* encrypt passwords supplied as part of your login
+# form.  If you set the password through the password property, like:
+# my_user.password = 'secret'
+# the password will be encrypted in the database, provided identity is up and 
+# running, or you have loaded the configuration specifying what encryption to
+# use (in situations where identity may not yet be running, like tests).
+
+# identity.soprovider.encryption_algorithm=None
 [/static]
 static_filter.on = True
 static_filter.dir = "%(top_level_dir)s/static"
--- a/examples/turbogears/markuptest/controllers.py
+++ b/examples/turbogears/markuptest/controllers.py
@@ -3,7 +3,8 @@
 import cherrypy
 
 import turbogears
-from turbogears import controllers, expose, validate, redirect
+from turbogears import controllers, expose, validate, redirect, widgets
+from turbogears import identity
 
 from markuptest import json
 
@@ -14,4 +15,40 @@
     def index(self):
         import time
         log.debug("Happy TurboGears Controller Responding For Duty")
-        return dict(now=time.ctime())
+        return dict(now=time.ctime(),
+                    widget=widgets.TextArea(name="widget_test",
+                                            default="This is a test of using "
+                                                    "TurboGears widgets with "
+                                                    "Markup",
+                                            rows=5, cols=40))
+
+
+    @expose(template="markuptest.templates.login")
+    def login(self, forward_url=None, previous_url=None, *args, **kw):
+
+        if not identity.current.anonymous \
+            and identity.was_login_attempted() \
+            and not identity.get_identity_errors():
+            raise redirect(forward_url)
+
+        forward_url=None
+        previous_url= cherrypy.request.path
+
+        if identity.was_login_attempted():
+            msg=_("The credentials you supplied were not correct or "
+                   "did not grant access to this resource.")
+        elif identity.get_identity_errors():
+            msg=_("You must provide your credentials before accessing "
+                   "this resource.")
+        else:
+            msg=_("Please log in.")
+            forward_url= cherrypy.request.headers.get("Referer", "/")
+        cherrypy.response.status=403
+        return dict(message=msg, previous_url=previous_url, logging_in=True,
+                    original_parameters=cherrypy.request.params,
+                    forward_url=forward_url)
+
+    @expose()
+    def logout(self):
+        identity.current.logout()
+        raise redirect("/")
--- a/examples/turbogears/markuptest/model.py
+++ b/examples/turbogears/markuptest/model.py
@@ -1,1 +1,109 @@
+from datetime import datetime
 
+from sqlobject import *
+
+from turbogears import identity 
+from turbogears.database import PackageHub
+
+hub = PackageHub("markuptest")
+__connection__ = hub
+
+# class YourDataClass(SQLObject):
+#     pass
+
+class Visit(SQLObject):
+    class sqlmeta:
+        table="visit"
+
+    visit_key= StringCol( length=40, alternateID=True,
+                          alternateMethodName="by_visit_key" )
+    created= DateTimeCol( default=datetime.now )
+    expiry= DateTimeCol()
+
+    def lookup_visit( cls, visit_key ):
+        try:
+            return cls.by_visit_key( visit_key )
+        except SQLObjectNotFound:
+            return None
+    lookup_visit= classmethod(lookup_visit)
+
+class VisitIdentity(SQLObject):
+    visit_key = StringCol(length=40, alternateID=True,
+                          alternateMethodName="by_visit_key")
+    user_id = IntCol()
+
+
+class Group(SQLObject):
+    """
+    An ultra-simple group definition.
+    """
+    
+    # names like "Group", "Order" and "User" are reserved words in SQL
+    # so we set the name to something safe for SQL
+    class sqlmeta:
+        table="tg_group"
+    
+    group_name = UnicodeCol(length=16, alternateID=True,
+                            alternateMethodName="by_group_name")
+    display_name = UnicodeCol(length=255)
+    created = DateTimeCol(default=datetime.now)
+
+    # collection of all users belonging to this group
+    users = RelatedJoin("User", intermediateTable="user_group",
+                        joinColumn="group_id", otherColumn="user_id")
+
+    # collection of all permissions for this group
+    permissions = RelatedJoin("Permission", joinColumn="group_id", 
+                              intermediateTable="group_permission",
+                              otherColumn="permission_id")
+
+
+class User(SQLObject):
+    """
+    Reasonably basic User definition. Probably would want additional attributes.
+    """
+    # names like "Group", "Order" and "User" are reserved words in SQL
+    # so we set the name to something safe for SQL
+    class sqlmeta:
+        table="tg_user"
+
+    user_name = UnicodeCol(length=16, alternateID=True,
+                           alternateMethodName="by_user_name")
+    email_address = UnicodeCol(length=255, alternateID=True,
+                               alternateMethodName="by_email_address")
+    display_name = UnicodeCol(length=255)
+    password = UnicodeCol(length=40)
+    created = DateTimeCol(default=datetime.now)
+
+    # groups this user belongs to
+    groups = RelatedJoin("Group", intermediateTable="user_group",
+                         joinColumn="user_id", otherColumn="group_id")
+
+    def _get_permissions(self):
+        perms = set()
+        for g in self.groups:
+            perms = perms | set(g.permissions)
+        return perms
+        
+    def _set_password(self, cleartext_password):
+        "Runs cleartext_password through the hash algorithm before saving."
+        hash = identity.encrypt_password(cleartext_password)
+        self._SO_set_password(hash)
+        
+    def set_password_raw(self, password):
+        "Saves the password as-is to the database."
+        self._SO_set_password(password)
+
+
+
+class Permission(SQLObject):
+    permission_name = UnicodeCol(length=16, alternateID=True,
+                                 alternateMethodName="by_permission_name")
+    description = UnicodeCol(length=255)
+    
+    groups = RelatedJoin("Group",
+                        intermediateTable="group_permission",
+                         joinColumn="permission_id", 
+                         otherColumn="group_id")
+
+
--- a/examples/turbogears/markuptest/release.py
+++ b/examples/turbogears/markuptest/release.py
@@ -3,6 +3,7 @@
 version = "1.0"
 
 # description = "Your plan to rule the world"
+# long_description = "More description about your plan"
 # author = "Your Name Here"
 # email = "YourEmail@YourDomain"
 # copyright = "Vintage 2006 - a good year indeed"
--- a/examples/turbogears/markuptest/templates/master.html
+++ b/examples/turbogears/markuptest/templates/master.html
@@ -1,13 +1,15 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml"
       xmlns:py="http://markup.edgewall.org/"
       xmlns:xi="http://www.w3.org/2001/XInclude"
       py:strip="">
+
 <xi:include href="sitetemplate.html"><xi:fallback/></xi:include>
 
 <head py:match="head" py:attrs="select('@*')">
     <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
     <title py:replace="''">Your title goes here</title>
-    ${select('*')}
+    <meta py:replace="select('*')"/>
     <style type="text/css">
         #pageLogin
         {
@@ -19,12 +21,13 @@
 </head>
 
 <body py:match="body" py:attrs="select('@*')">
-    <div py:if="tg.config('identity.on', False) and not logging_in"
-        id="pageLogin">
-        <span py:if="tg.identity.anonymous">
+    <div py:if="tg.config('identity.on',False) and not logging_in"
+        id="pageLogin"
+        py:choose="">
+        <span py:when="tg.identity.anonymous">
             <a href="/login">Login</a>
         </span>
-        <span py:if="not tg.identity.anonymous">
+        <span py:otherwise="">
             Welcome ${tg.identity.user.display_name}.
             <a href="/logout">Logout</a>
         </span>
@@ -32,7 +35,7 @@
 
     <div py:if="tg_flash" class="flash" py:content="tg_flash"></div>
 
-    ${select('*')}
+    <div py:replace="select('*')"/>
 
     <p align="center"><img src="/static/images/tg_under_the_hood.png" alt="TurboGears under the hood"/></p>
 </body>
new file mode 100644
--- /dev/null
+++ b/examples/turbogears/markuptest/templates/sitetemplate.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://markup.edgewall.org/"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      py:strip="">
+<head py:match="head" py:attrs="select('@*')">
+    <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
+    <title py:replace="''">Your title goes here</title>
+    <link py:for="css in tg_css" py:replace="ET(css.display())" />
+    <link py:for="js in tg_js_head" py:replace="ET(js.display())" />
+    ${select('*')}
+</head>
+<body py:match="body" py:attrs="select('@*')">
+    <div py:for="js in tg_js_bodytop" py:replace="ET(js.display())" />
+    ${select('*')}
+    <div py:for="js in tg_js_bodybottom" py:replace="ET(js.display())" />
+</body>
+</html>
--- a/examples/turbogears/markuptest/templates/welcome.html
+++ b/examples/turbogears/markuptest/templates/welcome.html
@@ -9,7 +9,7 @@
     <title>Welcome to TurboGears</title>
 </head>
 
-<body id="welcome">
+<body>
     <p>Congratulations, your TurboGears application is running as of <span py:replace="now">now</span>.</p>
 
     <h2>Are you ready to Gear Up?</h2>
@@ -31,5 +31,7 @@
 
     <p>Thanks for using TurboGears! See you on the <a href="http://groups.google.com/group/turbogears" >mailing list</a> and the "turbogears" channel on irc.freenode.org!</p>
 
+    ${ET(widget.display())}
+
 </body>
 </html>
--- a/examples/turbogears/sample-prod.cfg
+++ b/examples/turbogears/sample-prod.cfg
@@ -6,20 +6,23 @@
 # (such as template engine, encodings, etc.) all go in 
 # markuptest/config/app.cfg
 
-# DATABASE
-
 # pick the form for your database
 # sqlobject.dburi="postgres://username@hostname/databasename"
 # sqlobject.dburi="mysql://username:password@hostname:port/databasename"
 # sqlobject.dburi="sqlite:///file_name_and_path"
 
+# If you have sqlite, here's a simple default to get you started
+# in development
+sqlobject.dburi="sqlite://%(current_dir_uri)s/devdata.sqlite"
+
+
 # if you are using a database or table type without transactions
 # (MySQL default, for example), you should turn off transactions
 # by prepending notrans_ on the uri
 # sqlobject.dburi="notrans_mysql://username:password@hostname:port/databasename"
 
 # for Windows users, sqlite URIs look like:
-# sqlobject.dburi="sqlite:///drive_letter|/path/to/file"
+# sqlobject.dburi="sqlite:///drive_letter:/path/to/file"
 
 
 # SERVER
--- a/examples/turbogears/setup.py
+++ b/examples/turbogears/setup.py
@@ -17,7 +17,7 @@
     #license=license,
     
     install_requires = [
-        "TurboGears >= 0.9a7dev-r1517",
+        "TurboGears >= 0.9a9dev-r1686",
     ],
     scripts = ["start-markuptest.py"],
     zip_safe=False,
--- a/examples/turbogears/start-markuptest.py
+++ b/examples/turbogears/start-markuptest.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
 import pkg_resources
 pkg_resources.require("TurboGears")
 
Copyright (C) 2012-2017 Edgewall Software