[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" /> <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