[Checkins] SVN: Sandbox/darrylcousins/tfws.website/ Added login and logout using z3c.authentication.cookie

Darryl Cousins darryl at darrylcousins.net.nz
Sun Jul 29 07:53:29 EDT 2007


Log message for revision 78457:
  Added login and logout using z3c.authentication.cookie

Changed:
  U   Sandbox/darrylcousins/tfws.website/CHANGES.txt
  U   Sandbox/darrylcousins/tfws.website/src/tfws/website/BROWSER.txt
  U   Sandbox/darrylcousins/tfws.website/src/tfws/website/authentication.py
  U   Sandbox/darrylcousins/tfws.website/src/tfws/website/breadcrumb.py
  U   Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/browser.py
  U   Sandbox/darrylcousins/tfws.website/src/tfws/website/configure.zcml
  U   Sandbox/darrylcousins/tfws.website/src/tfws/website/ftesting.zcml
  U   Sandbox/darrylcousins/tfws.website/src/tfws/website/interfaces.py
  U   Sandbox/darrylcousins/tfws.website/src/tfws/website/layer.py
  U   Sandbox/darrylcousins/tfws.website/src/tfws/website/site.py
  U   Sandbox/darrylcousins/tfws.website/src/tfws/website/site.txt
  U   Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/skin.py
  U   Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/template.pt
  U   Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/website.css
  A   Sandbox/darrylcousins/tfws.website/src/tfws/website/templates/autologin-widget.pt
  U   Sandbox/darrylcousins/tfws.website/src/tfws/website/testing.py
  A   Sandbox/darrylcousins/tfws.website/src/tfws/website/tools/
  A   Sandbox/darrylcousins/tfws.website/src/tfws/website/tools/__init__.py
  A   Sandbox/darrylcousins/tfws.website/src/tfws/website/tools/member.pt
  A   Sandbox/darrylcousins/tfws.website/src/tfws/website/tools/member.py

-=-
Modified: Sandbox/darrylcousins/tfws.website/CHANGES.txt
===================================================================
--- Sandbox/darrylcousins/tfws.website/CHANGES.txt	2007-07-29 11:17:46 UTC (rev 78456)
+++ Sandbox/darrylcousins/tfws.website/CHANGES.txt	2007-07-29 11:53:29 UTC (rev 78457)
@@ -2,4 +2,9 @@
 tfws.website
 ============
 
+July 29 2007
+------------
 
+* Login and logout working with z3c.authentication.cookie lifetime cookie.
+* Added first simple tool for members
+  

Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/BROWSER.txt
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/BROWSER.txt	2007-07-29 11:17:46 UTC (rev 78456)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/BROWSER.txt	2007-07-29 11:53:29 UTC (rev 78457)
@@ -9,14 +9,13 @@
   >>> browser.handleErrors = False
   >>> browser.open("http://localhost/")
 
-If we try to access the root object without credentials we get ``unauthorized``.
+Unauthorized users can access the site.
 
   >>> user = ExtendedTestBrowser()
   >>> user.open("http://localhost/")
   Traceback (most recent call last):
   ...
   HTTPError: HTTP Error 401: Unauthorized
-  >>> user.handleErrors = False
 
 Using our authenticated browser instance we can add a website.
 
@@ -38,8 +37,42 @@
   treefern
   Tree Fern
 
-We can edit the new site.
+We can edit the new site ... to be continued
 
   >>> browser.getLink('treefern').click()
   >>> testing.printElement(browser, "//h1")
   <h1>Tree Fern</h1>
+
+Unauthorized users can access the site.
+
+  >>> user.open("http://localhost/treefern/index")
+  >>> print user.url
+  http://localhost/treefern/index
+
+We have a login form.
+
+  >>> user.handleErrors = False
+  >>> user.open("http://localhost/treefern/login")
+  >>> user.getControl('Username').value = u'darrylcousins'
+  >>> user.getControl('Password').value = u'tfws'
+  >>> user.getControl('Login').click()
+  >>> print user.url
+  http://localhost/treefern
+
+We can log out also.
+
+  >>> user.open("http://localhost/treefern/logout")
+  >>> print user.url
+  http://localhost/treefern/
+
+Accessing an edit view will cause redirection to login form.
+
+  >>> user.handleErrors = True
+  >>> user.open("http://localhost/treefern/edit")
+  >>> print user.url
+  http://localhost/treefern/@@login?camefrom=%2Ftreefern%2Fedit
+  >>> user.getControl('Username').value = u'darrylcousins'
+  >>> user.getControl('Password').value = u'tfws'
+  >>> user.getControl('Login').click()
+  >>> print user.url
+  http://localhost/treefern/edit

Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/authentication.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/authentication.py	2007-07-29 11:17:46 UTC (rev 78456)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/authentication.py	2007-07-29 11:53:29 UTC (rev 78457)
@@ -1,4 +1,5 @@
 import zope.interface
+import zope.component
 import zope.event
 import zope.lifecycleevent
 from zope.schema.fieldproperty import FieldProperty
@@ -8,6 +9,7 @@
 
 from z3c.authentication.simple import member
 from z3c.authentication.simple import group
+from z3c.authentication.cookie.plugin import CookieCredentialsPlugin
 
 import grok
 
@@ -23,10 +25,15 @@
 def setup_site_auth(auth):    
 
     # setup credentials plugin
-    cred = SessionCredentialsPlugin()
+    cred = CookieCredentialsPlugin()
     zope.event.notify(zope.lifecycleevent.ObjectCreatedEvent(cred))
-    auth[u'credentials'] = cred
-    auth.credentialsPlugins += (u'credentials',)
+    cred.loginpagename = 'login'
+    # form is generated with z3c.form so we need long request names
+    cred.loginfield = 'form.widgets.login'
+    cred.passwordfield = 'form.widgets.password'
+    cred.autologinfield = 'form.widgets.autologin'
+    auth[u'Cookie Credentials'] = cred
+    auth.credentialsPlugins += (u'Cookie Credentials',)
 
     site = auth.__parent__.__parent__
     prm = IPrincipalRoleManager(site)
@@ -53,16 +60,32 @@
     groups.addGroup('Administrators', grp) 
     prm.assignRoleToPrincipal(roles.ADMINISTRATOR, 'groups.Administrators')
 
+
+def setup_cookie_session_container(ccsdc):
+    # setup cookie session data container
+    # Expiry time of 0 means never (well - close enough)
+    ccsdc.timeout = 0
+
+
+def setup_cookie_client_manager(ccim):
+    # setup lifetime session cookie client id manager
+    # Expiry time of 0 means never (well - close enough)
+    ccim.cookieLifetime = 0
+
+
 def role_factory(*args):
     def factory():
         return LocalRole(*args)
     return factory
 
+
 def folder_factory(folderfactory, *args):
     def factory():
         return folderfactory(*args)
     return factory
 
+
+
 class WebSiteMember(member.Member):
     """An IMember for MemberContainer."""
 

Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/breadcrumb.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/breadcrumb.py	2007-07-29 11:17:46 UTC (rev 78456)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/breadcrumb.py	2007-07-29 11:53:29 UTC (rev 78457)
@@ -1,13 +1,37 @@
 import zope.interface
+import zope.component
+import zope.traversing
+from zope.app.component.interfaces import ISite
+from zope.publisher.interfaces import INotFound
 
 from z3c.breadcrumb.browser import Breadcrumbs as Breadcrumbs_
-from z3c.breadcrumb.interfaces import IBreadcrumbs
+from z3c.breadcrumb.interfaces import IBreadcrumbs, IBreadcrumb
 
 import grok
 
+from tfws.website import interfaces
+
 class Breadcrumbs(grok.MultiAdapter, Breadcrumbs_):
     """Breadcrumbs implementation using IBreadcrumb adapters."""
     grok.name('breadcrumbs')
     grok.context(zope.interface.Interface)
     grok.provides(IBreadcrumbs)
 
+    @property
+    def crumbs(self):
+        objects = []
+        for obj in ( [self.context] +
+                     list(zope.traversing.api.getParents(self.context)) ):
+            if INotFound.providedBy(obj):
+                obj = obj.getObject()
+            objects.append(obj)
+            if ISite.providedBy(obj):
+                break
+        objects.reverse()
+        for object in objects:
+            info = zope.component.getMultiAdapter((object, self.request),
+                                        IBreadcrumb)
+            yield {'name': info.name,
+                   'url': info.url,
+                   'activeURL': info.activeURL}
+

Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/browser.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/browser.py	2007-07-29 11:17:46 UTC (rev 78456)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/browser.py	2007-07-29 11:53:29 UTC (rev 78457)
@@ -61,10 +61,6 @@
 class Index(mars.view.PageletView):
     grok.context(IRootFolder)
     grok.require(permissions.MANAGESITE)
-    # this allows the standard http auth to get called, @@absolute_url
-    # wasn't able to be rendered with Unauthorized
-    # See zope.traversing.browser.absoluteurl.py
-    __name__ = u'bug-fix'
 
     columns = (
         CheckboxColumn(_('Sel')),
@@ -122,7 +118,8 @@
     _finishedAdd = False
 
     fields = field.Fields(zope.schema.TextLine(__name__='__name__',
-                                title=_(u"name"), required=True))
+                                               title=_(u"name"), 
+                                               required=True))
 
     groups = (site.ContentMetaDataGroup, site.InitialManagerGroup)
 

Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/configure.zcml
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/configure.zcml	2007-07-29 11:17:46 UTC (rev 78456)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/configure.zcml	2007-07-29 11:53:29 UTC (rev 78457)
@@ -5,7 +5,7 @@
 
   <include package="grok" />
 
-  <!-- extra package includes, check grok configure first -->
+  <!-- extra package includes -->
   <include package="zope.contentprovider" />
   <include package="zope.app.session" />
 
@@ -29,6 +29,7 @@
   <include package="z3c.macro" />
   <include package="z3c.pagelet" />
   <include package="z3c.authentication.simple" />
+  <include package="z3c.authentication.cookie" />
 
   <include package="zc.resourcelibrary" />
   <include package="zc.table" />

Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/ftesting.zcml
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/ftesting.zcml	2007-07-29 11:17:46 UTC (rev 78456)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/ftesting.zcml	2007-07-29 11:53:29 UTC (rev 78457)
@@ -15,6 +15,10 @@
       id="zope.anybody"
       title="Unauthenticated User"
       />
+  <unauthenticatedGroup
+      id="zope.Anybody"
+      title="Unauthenticated Users"
+      />
   <grant
       permission="zope.View"
       principal="zope.anybody"

Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/interfaces.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/interfaces.py	2007-07-29 11:17:46 UTC (rev 78456)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/interfaces.py	2007-07-29 11:53:29 UTC (rev 78457)
@@ -76,3 +76,4 @@
         description=_(u'The email address of the administrator.'),
         required=True)
 
+

Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/layer.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/layer.py	2007-07-29 11:17:46 UTC (rev 78456)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/layer.py	2007-07-29 11:53:29 UTC (rev 78457)
@@ -1,6 +1,8 @@
 from jquery.layer import IJQueryJavaScriptBrowserLayer
+from zope.publisher.interfaces.browser import IDefaultBrowserLayer
 
 import mars.form
 
 class IWebSiteLayer(mars.form.IDivFormLayer, IJQueryJavaScriptBrowserLayer):
+#class IWebSiteLayer(IDefaultBrowserLayer, mars.form.IDivFormLayer, IJQueryJavaScriptBrowserLayer):
     pass

Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/site.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/site.py	2007-07-29 11:17:46 UTC (rev 78456)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/site.py	2007-07-29 11:53:29 UTC (rev 78457)
@@ -9,10 +9,24 @@
 from zope.app.intid.interfaces import IIntIds
 from zope.app.catalog.catalog import Catalog
 from zope.app.catalog.interfaces import ICatalog
-from zope.app.security.interfaces import IAuthentication
-from zope.app.securitypolicy.interfaces import IRolePermissionManager
+from zope.app.security.interfaces import (ILogout,
+                                          IAuthentication,
+                                          IUnauthenticatedGroup,
+                                          IUnauthenticatedPrincipal)
+from zope.app.securitypolicy.interfaces import (IRolePermissionManager,
+                                                IPrincipalPermissionManager)
+from zope.app.session.interfaces import (IClientIdManager,
+                                         ISessionDataContainer)
+from zope.app.session.http import CookieClientIdManager
+from zope.app.session.interfaces import ISessionDataContainer
+from zope.app.session.session import PersistentSessionDataContainer
 
+from z3c.authentication.cookie.interfaces import SESSION_KEY
+from z3c.authentication.cookie.session import \
+                              CookieCredentialSessionDataContainer
+
 from z3c.form import form, field, button, group
+from z3c.form.browser.checkbox import CheckBoxFieldWidget
 from z3c.form.interfaces import IWidgets
 from z3c.formui import layout
 from z3c.formjs import jsaction, jsevent, jsvalidator, ajax
@@ -36,6 +50,10 @@
 
 mars.layer.layer(IWebSiteLayer)
 
+grok.global_utility(PersistentSessionDataContainer,
+                   ISessionDataContainer,
+                   name='')
+
 class WebSite(grok.Application, grok.Container):
     """Mars/Grok/Z3C demo website
 
@@ -43,10 +61,20 @@
     zope.interface.implements(interfaces.IWebSite)
     grok.local_utility(IntIds, IIntIds) # needed for the catalog
     grok.local_utility(Catalog, ICatalog, setup=setup_catalog,
-                       name_in_container='wcatalog')
+                   name_in_container='wcatalog')
     grok.local_utility(SimpleAuthentication, IAuthentication,
-                       setup=authentication.setup_site_auth, 
-                       name_in_container='auth')
+                   setup=authentication.setup_site_auth, 
+                   name_in_container='auth')
+    grok.local_utility(CookieCredentialSessionDataContainer,
+                   ISessionDataContainer,
+                   setup=authentication.setup_cookie_session_container, 
+                   name_in_container='CookieCredentialSessionDataContainer',
+                   name=SESSION_KEY)
+    grok.local_utility(CookieClientIdManager,
+                   IClientIdManager,
+                   setup=authentication.setup_cookie_client_manager, 
+                   name_in_container='LifeTimeSessionClientIdManager',
+                   name='LifeTimeSessionClientIdManager')
 
     title = FieldProperty(interfaces.IWebSite['title'])
     description = FieldProperty(interfaces.IWebSite['description'])
@@ -59,8 +87,10 @@
     def __repr__(self):
         return '<%s %r>' % (self.__class__.__name__, self.__name__)
 
+
 class Index(mars.view.PageletView):
     """Temp display view for site"""
+    grok.require(permissions.VIEW)
 
     def render(self):
         """First try to locate an index page for the site"""
@@ -102,8 +132,9 @@
                                group.GroupForm, form.EditForm):
     """Edit form for site"""
     grok.name('edit')
+    grok.require(permissions.MANAGECONTENT)
     form.extends(form.EditForm)
-    label = u'Tree Fern Web Site Edit Form'
+    label = _('Edit Metadata for the site.')
     groups = (ContentMetaDataGroup,)
 
     @button.buttonAndHandler(u'Apply and View', name='applyView')
@@ -114,7 +145,90 @@
             self.request.response.redirect(url)
 
 
+class Login(mars.form.FormView, layout.FormLayoutSupport, 
+                                form.Form):
+    grok.context(zope.interface.Interface)
+    fields = field.Fields(zope.schema.TextLine(
+                                __name__ = 'login',
+                                title=_(u'Username'),
+                                description=_(u'Username for login.'),
+                                required=True),
+                          zope.schema.Password(
+                                __name__ = 'password',
+                                title=_(u'Password'),
+                                description=_(u'Password for login.'),
+                                required=True),
+                          zope.schema.Bool(
+                                __name__ = 'autologin',
+                                title=_(u'Remember me'),
+                                description=_(u'Auto login.'),
+                                default=True,
+                                required=False),
+                          zope.schema.TextLine(
+                                __name__ = 'camefrom',
+                                title=_(u'Came from'),
+                                description=_(u'Redirect to this url.'),
+                                required=True))
+    status = ''
+    label = _('Login')
 
+    @button.buttonAndHandler(_('Login'), name='login')
+    def handleLogin(self, action):
+        if (not IUnauthenticatedPrincipal.providedBy(self.request.principal)):
+            self.request.response.redirect(self.camefrom)
+        else:
+            self.status = _("Login unsuccessfull, please try again.")
+
+    def updateWidgets(self):
+        '''See interfaces.IForm'''
+        self.widgets = zope.component.getMultiAdapter(
+            (self, self.request, self.getContent()), IWidgets)
+        self.widgets.ignoreContext = True
+        self.widgets.update()
+        self.widgets['camefrom'].value = self.camefrom
+        self.widgets['camefrom'].mode = 'hidden'
+
+    @property
+    def camefrom(self):
+        camefrom = self.request.get('camefrom', None)
+        if camefrom is None:
+            camefrom = self.request.get('form.widgets.camefrom', None)
+        if camefrom is None:
+            camefrom = absoluteURL(self.context, self.request)
+        return camefrom
+
+class AutoLoginTemplateFactory(mars.form.WidgetTemplateFactory):
+    """Define a custom template for autologin field.
+
+    I'm thinking that I could use this field to choose between using cookie (ie
+    lifetime) and session credentials. In the meantime I'm leaving it with
+    lifetime cookie.
+    """
+    grok.name('input')
+    grok.context(zope.interface.Interface)
+    grok.template('templates/autologin-widget.pt')
+    mars.form.view(Login)
+    mars.form.field(zope.schema.Bool)
+
+
+class Logout(mars.view.PageletView):
+    grok.context(zope.interface.Interface)
+    grok.require(permissions.VIEW)
+
+    def update(self):
+        camefrom = self.request.get('camefrom', '.')
+        if not IUnauthenticatedPrincipal.providedBy(self.request.principal):
+            pau = zope.component.getUtility(IAuthentication)
+            ILogout(pau).logout(self.request)
+            if camefrom:
+                return self.request.response.redirect(camefrom)
+        if camefrom is None:
+## get and use site instead of self.context?
+            url = absoluteURL(self.context, self.request)
+            return self.request.response.redirect(url)
+        else:
+            return self.request.response.redirect(camefrom)
+
 class SiteConfigurator(grok.Adapter, configurator.ConfigurationPluginBase):
     """Configure the site, this has access to the data submitted by the add
     form as well as local utilities defined with grok.local_utility."""
@@ -150,3 +264,11 @@
                                            roles.MEMBER)
         role_manager.grantPermissionToRole(permissions.VIEW, 
                                            roles.MEMBER)
+
+        # grant VIEW to unauthenticated users.
+        prin_manager = IPrincipalPermissionManager(self.context)
+        unauth = zope.component.queryUtility(IUnauthenticatedGroup,
+                                    context=self.context)
+        if unauth is not None:
+            prin_manager.grantPermissionToPrincipal(permissions.VIEW, 
+                                                        unauth.id)

Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/site.txt
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/site.txt	2007-07-29 11:17:46 UTC (rev 78456)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/site.txt	2007-07-29 11:53:29 UTC (rev 78457)
@@ -15,23 +15,100 @@
     >>> from zope.app.catalog.interfaces import ICatalog
     >>> from tfws.website import interfaces
     >>> from tfws.website import site
+    >>> from tfws.website import authentication
     >>> from tfws.website.skin import skin
 
 And a request for later.
 
     >>> from zope.publisher.browser import TestRequest
     >>> request = TestRequest()
+    >>> from zope.app.session.interfaces import ISession
+    >>> print ISession(request)
+    <zope.app.session.session.Session object at 0x...>
 
 Create a site
 
     >>> from tfws.website.site import WebSite
     >>> root['treefern'] = website = WebSite(u'Tree Fern')
 
-It has an authentication utility and a catalog.
+Authentication
+--------------
 
+It has an authentication utility.
+
     >>> auth = zope.component.getUtility(IAuthentication, context=website)
     >>> print auth
     <z3c.authentication.simple.authentication.SimpleAuthentication object at 0x...>
+    >>> for plugin in auth:
+    ...    print plugin
+    Cookie Credentials
+    groups
+    members
+
+    >>> print len(auth['groups'])
+    2
+    >>> print len(auth['members'])
+    0
+
+    >>> print auth.authenticate(request)
+    None
+
+tfws.website endeavours to use a lifetime cookie to manage logins. The package
+z3c.authentication.cookie provides the components for this setup. Here we check
+that the correct components are indeed installed for the website.
+
+    >>> sm = zope.component.getSiteManager(website)
+    >>> ccim = sm['LifeTimeSessionClientIdManager']
+    >>> ccim.cookieLifetime
+    0
+
+The cookie session data container session storage has to provide a timeout of 0
+(zero) which means it's item the persistent CookieCredentials will never expire.
+
+    >>> sdc = sm['CookieCredentialSessionDataContainer']
+    >>> sdc
+    <z3c.authentication.cookie.session.CookieCredentialSessionDataContainer ...> 
+
+Check if this container is also available as utility.
+
+    >>> from z3c.authentication.cookie.interfaces import SESSION_KEY
+    >>> from zope.app.session.interfaces import ISessionDataContainer
+    >>> ccsdc = zope.component.getUtility(ISessionDataContainer, 
+    ...     name=SESSION_KEY, context=website)
+    >>> ccsdc
+    <z3c.authentication.cookie.session.CookieCredentialSessionDataContainer ...>
+
+    >>> ccsdc.timeout
+    0
+
+Test authentication
+-------------------
+
+First we add a member to the site for testing authentication.
+
+    >>> member = authentication.WebSiteMember(u'darryl', 'tfws',
+    ...                  u'Darryl', u'Cousins', u'darryl at tfws.org.nz')
+    >>> auth['members'].add(member)
+    ('...', <WebSiteMember u'Darryl Cousins'>)
+    >>> print len(auth['members'])
+    1
+
+    >>> request = TestRequest(form={'form.widgets.login':'darryl', \
+    ...                             'form.widgets.password':'tfws'})
+    >>> darryl = auth.authenticate(request)
+    >>> darryl
+    <AuthenticatedPrincipal...>
+
+    >>> #IAuthenticatedPrincipal.providedBy(bob)
+    True
+
+we get an authenticated principal.
+
+Catalog
+-------
+
+It has a catalog also.
+
     >>> catalog = zope.component.getUtility(ICatalog, context=website)
     >>> print catalog
     <zope.app.catalog.catalog.Catalog object at 0x...>

Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/skin.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/skin.py	2007-07-29 11:17:46 UTC (rev 78456)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/skin.py	2007-07-29 11:53:29 UTC (rev 78457)
@@ -33,11 +33,6 @@
     grok.context(IBrowserPage)
     grok.template('template.pt')
 
-class NavigationManager(mars.viewlet.ViewletManager):
-    """navigation column viewletmanager"""
-    grok.name('INavigationColumn')
-    grok.context(zope.interface.Interface)
-
 ### javascript viewlet manager and viewlets
 class JavaScriptManager(mars.viewlet.ViewletManager):
     """javascript viewletmanager"""

Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/template.pt
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/template.pt	2007-07-29 11:17:46 UTC (rev 78456)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/template.pt	2007-07-29 11:53:29 UTC (rev 78457)
@@ -35,8 +35,8 @@
       </tal:block>
     </div>
     <div id="mainContainer">
-      <div id="naviContainer">
-         <tal:block replace="structure provider:INavigationColumn">
+      <div id="toolsContainer">
+         <tal:block replace="structure provider:ITools">
            tools
          </tal:block>
       </div>

Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/website.css
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/website.css	2007-07-29 11:17:46 UTC (rev 78456)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/website.css	2007-07-29 11:53:29 UTC (rev 78457)
@@ -141,54 +141,66 @@
     padding: 10px 0px 10px 0px;
 }
 
-/*---[ navigation ]-----------------------------------------------------------*/
+/*---[ tools ]-----------------------------------------------------------*/
 
-#naviContainer {
+#toolsContainer {
 	width: 140px;
 	float: left;
     background-color: white;
 	padding: 25px 20px 0px 0px;
 }
 
-#naviContainer a {
-    color: #000000;
+#toolsContainer a {
 }
 
-div.naviBox {
+div.tool {
     padding: 5px;
     margin: 0px;
     background-color: #F2F2F2;
-/*    background: url("./img/naviBG.jpg") repeat-y left top;*/
+/*    background: url("./img/toolBG.jpg") repeat-y left top;*/
 }
 
-div.naviBox .naviBoxHeader {
-    height: 40px;
-    line-height: 40px;
+div.tool .toolHeader {
+    line-height: 20px;
     color: #3257C2;
+    font-family: serif;
+    font-weight: bold;
     vertical-align: top;
 }
 
-div.naviBox .naviBoxHeader img {
+div.tool .toolHeader img {
     vertical-align: middle;
     padding: 5px 10px 5px 0px;
 }
 
 
-div.naviBox .naviBoxBody {
+div.tool .toolBody {
 	font-size: 90%;
     color: #000000;
 }
 
 
-div.naviBox .naviBoxBody div {
+div.tool .toolBody div {
 	padding-bottom: 5px;
 }
 
+div.tool .toolBody ul {
+    list-style: none;
+    padding: 0;
+    margin: 0.5em 0em;
+}
+
+div.tool .toolBody ul li {
+    list-style: none;
+    padding: 0.2em;
+    margin: 0;
+}
+
 div.boxSpacer {
     height: 10px;
 }
 
-div.naviBox #searchForm input {
+div.tool #searchForm input {
     vertical-align: middle;
 }
 

Added: Sandbox/darrylcousins/tfws.website/src/tfws/website/templates/autologin-widget.pt
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/templates/autologin-widget.pt	                        (rev 0)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/templates/autologin-widget.pt	2007-07-29 11:53:29 UTC (rev 78457)
@@ -0,0 +1,21 @@
+<span class="option">
+    <input type="checkbox" id="form-widgets-autologin-0"
+            name="form.widgets.autologin:list"
+            class="radioWidget bool-field" value="yes"
+            checked="checked"
+            disabled="true" />
+    <label for="form-widgets-autologin-0">
+        <span class="label">yes</span>
+    </label>
+</span>
+    <input type="hidden"
+        id="form-widgets-autologin-1"
+        name="form.widgets.autologin:list"
+        class="radioWidget bool-field"
+        value="no"
+        />
+<input name="form.widgets.autologin-empty-marker"
+        type="hidden"
+        value="1"
+        />
+

Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/testing.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/testing.py	2007-07-29 11:17:46 UTC (rev 78456)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/testing.py	2007-07-29 11:53:29 UTC (rev 78457)
@@ -15,6 +15,22 @@
 from zope.app.securitypolicy.rolepermission \
      import AnnotationRolePermissionManager
 
+from zope.app.session.interfaces import IClientId, IClientIdManager, ISession
+from zope.app.session.interfaces import ISessionDataContainer
+from zope.app.session.session import PersistentSessionDataContainer
+from zope.app.session.interfaces import ISessionPkgData, ISessionData
+from zope.app.session.session import ClientId, Session
+from zope.app.session.http import CookieClientIdManager
+from zope.publisher.interfaces import IRequest
+
+from z3c.authentication.cookie.session import LifeTimeSession
+from z3c.authentication.cookie.interfaces import (ILifeTimeClientId,
+                                                  ILifeTimeSession)
+from z3c.authentication.simple.principal import AuthenticatedPrincipal
+from z3c.authentication.simple.principal import FoundPrincipal
+from z3c.authentication.simple.interfaces import (IAuthenticatedPrincipal,
+                                                 IFoundPrincipal)
+
 import grok
 from martian.interfaces import IModuleInfo
 import tfws.website
@@ -24,6 +40,7 @@
 TestLayer = ZCMLLayer(ftesting_zcml, __name__, 'FunctionalLayer')
 
 def printElement(browser, xpath, multiple=False, serialize=True):
+    """Print method from z3c.form to use with z3c.etestbrowser"""
     result = [serialize and lxml.etree.tounicode(elem) or elem
               for elem in browser.etree.xpath(xpath)]
     if not multiple:
@@ -33,6 +50,7 @@
         print elem
 
 class ModuleInfo(object):
+    """Dummy module info for martians"""
     zope.interface.implements(IModuleInfo)
     path = tfws.website.__file__
     package_dotted_name = 'tfws.website'
@@ -40,6 +58,11 @@
     def getAnnotation(self, name, default):
         return default
 
+class TestClientId(object):
+    zope.interface.implements(IClientId)
+    def __new__(cls, request):
+        return 'dummyclientidfortesting'
+
 def setUp(test):
     root = setup.placefulSetUp(site=True)
     test.globs['root'] = root
@@ -50,6 +73,26 @@
                             AnnotationRolePermissionManager)
     metaconfigure.registerType('provider', tales.TALESProviderExpression)
 
+    # testing setup borrowed from z3c.authentication.cookie testing
+    # setup client ids
+    ztapi.provideAdapter(IRequest, IClientId, TestClientId)
+    ztapi.provideAdapter(IRequest, ILifeTimeClientId, TestClientId)
+
+    # setup session adapters
+    ztapi.provideAdapter(IRequest, ISession, Session)
+    ztapi.provideAdapter(IRequest, ILifeTimeSession, LifeTimeSession)
+
+    # setup session data containers
+    #defaultSDC = PersistentSessionDataContainer()
+    #ztapi.provideUtility(ISessionDataContainer, defaultSDC, '')
+
+    # setup principal adapters
+    zope.component.provideAdapter(AuthenticatedPrincipal, 
+                   provides=IAuthenticatedPrincipal)
+    zope.component.provideAdapter(FoundPrincipal, 
+                   provides=IFoundPrincipal)
+
+
 def tearDown(test):
     setup.placefulTearDown()
 

Added: Sandbox/darrylcousins/tfws.website/src/tfws/website/tools/__init__.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/tools/__init__.py	                        (rev 0)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/tools/__init__.py	2007-07-29 11:53:29 UTC (rev 78457)
@@ -0,0 +1,16 @@
+import zope.interface
+
+import grok
+
+import mars.viewlet
+import mars.layer
+
+from tfws.website.layer import IWebSiteLayer
+
+mars.layer.layer(IWebSiteLayer)
+
+class ITools(mars.viewlet.ViewletManager):
+    """Tools viewletmanager"""
+    grok.name('ITools')
+    grok.context(zope.interface.Interface)
+


Property changes on: Sandbox/darrylcousins/tfws.website/src/tfws/website/tools/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: Sandbox/darrylcousins/tfws.website/src/tfws/website/tools/member.pt
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/tools/member.pt	                        (rev 0)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/tools/member.pt	2007-07-29 11:53:29 UTC (rev 78457)
@@ -0,0 +1,25 @@
+<div class="toolContainer">
+  <div class="tool">
+    <div class="toolHeader">
+      <tal:block i18n:translate="">Members</tal:block>
+    </div>
+    <div class="toolBody">
+<ul class="menu" id="memberTool">
+  <li tal:repeat="menuitem view/menu">
+    <a href="#"
+     tal:define="id menuitem/id|nothing"
+     tal:attributes="href menuitem/action;
+                     class menuitem/selected;
+                     title menuitem/description;
+                     id id"><img tal:condition="menuitem/icon|nothing"
+         tal:replace="structure menuitem/icon" />&nbsp;<span
+     tal:content="menuitem/title"
+     i18n:translate="">Title</span>
+    </a></li>
+</ul>
+    </div>
+  </div>
+  <div class="boxSpacer">
+  </div>
+</div>
+

Added: Sandbox/darrylcousins/tfws.website/src/tfws/website/tools/member.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/tools/member.py	                        (rev 0)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/tools/member.py	2007-07-29 11:53:29 UTC (rev 78457)
@@ -0,0 +1,93 @@
+from urllib import urlencode
+
+import zope.interface
+from zope.traversing.browser import absoluteURL
+from zope.app.component import hooks
+from zope.app.security.interfaces import IUnauthenticatedPrincipal
+
+import grok
+
+import mars.viewlet
+import mars.template
+
+import mars.layer
+
+from tfws.website.layer import IWebSiteLayer
+from tfws.website import tools
+from tfws.website.i18n import MessageFactory as _
+
+mars.layer.layer(IWebSiteLayer)
+
+class MemberTool(mars.viewlet.Viewlet):
+    """A viewlet that has its own template"""
+    grok.context(zope.interface.Interface) # maybe IContent?
+    mars.viewlet.manager(tools.ITools)
+    weight = 1
+
+    @property
+    def menu(self):
+        """Return menu item entries in a TAL-friendly form."""
+        result = []
+
+        principal = getattr(self.request, 'principal', None)
+        if not principal:
+            return result
+
+        if IUnauthenticatedPrincipal.providedBy(principal):
+            return self.getUnauthenticatedMenu()
+        else:
+            return self.getAuthenticatedMenu()
+
+    def getUnauthenticatedMenu(self):
+        result = []
+
+        request_url = self.request.getURL()
+        site_url = absoluteURL(hooks.getSite(), self.request)
+
+        action = site_url + '/login'
+        fullaction = '%s?%s' % (action, urlencode({'camefrom': request_url}))
+        result.append(
+            {'title': _("Login"),
+             'action': fullaction,
+             'description': _("Login"),
+             'selected': request_url.endswith(action) and u'selected' or u''
+            })
+    
+        return result
+
+    def getAuthenticatedMenu(self):
+        result = []
+
+        request_url = self.request.getURL()
+        site_url = absoluteURL(hooks.getSite(), self.request)
+
+        action = site_url + '/logout'
+        fullaction = '%s?%s' % (action, urlencode({'camefrom': request_url}))
+        result.append(
+            {'title': _("Logout"),
+             'action': fullaction,
+             'description': _("Logout"),
+             'selected': u''
+            })
+    
+        action = site_url + '/edit-account'
+        result.append(
+            {'title': _("Edit Account"),
+             'action': action,
+             'description': _("Edit user account"),
+             'selected': request_url.endswith(action) and u'selected' or u''
+            })
+    
+        action = site_url + '/account'
+        result.append(
+            {'title': _("Account"),
+             'action': action,
+             'description': _("User account"),
+             'selected': request_url.endswith(action) and u'selected' or u''
+            })
+    
+        return result
+
+class MemberToolTemplate(mars.template.TemplateFactory):
+    grok.template('member.pt')
+    grok.context(MemberTool)


Property changes on: Sandbox/darrylcousins/tfws.website/src/tfws/website/tools/member.py
___________________________________________________________________
Name: svn:keywords
   + Id



More information about the Checkins mailing list