[Checkins] SVN: grokapps/LoginDemo/src/logindemo/ added e-mail
field validation to IUser
Luciano Ramalho
luciano at ramalho.org
Fri Dec 28 18:29:25 EST 2007
Log message for revision 82509:
added e-mail field validation to IUser
Changed:
_U grokapps/LoginDemo/src/logindemo/
U grokapps/LoginDemo/src/logindemo/app.py
U grokapps/LoginDemo/src/logindemo/app_templates/index.pt
U grokapps/LoginDemo/src/logindemo/app_templates/login.pt
A grokapps/LoginDemo/src/logindemo/app_templates/master.pt
_U grokapps/LoginDemo/src/logindemo/ftests/
U grokapps/LoginDemo/src/logindemo/ftests/index.txt
U grokapps/LoginDemo/src/logindemo/interfaces.py
-=-
Property changes on: grokapps/LoginDemo/src/logindemo
___________________________________________________________________
Name: svn:ignore
+ *.pyc
Modified: grokapps/LoginDemo/src/logindemo/app.py
===================================================================
--- grokapps/LoginDemo/src/logindemo/app.py 2007-12-28 23:22:28 UTC (rev 82508)
+++ grokapps/LoginDemo/src/logindemo/app.py 2007-12-28 23:29:25 UTC (rev 82509)
@@ -13,11 +13,12 @@
from zope.app.securitypolicy.interfaces import IPrincipalRoleManager
from zope.app.securitypolicy.role import LocalRole
from zope.component import getUtility
+from zope.i18n import MessageFactory
+from logindemo.interfaces import IUser
+_ = MessageFactory('logindemo')
-from logindemo.interfaces import IUser
-
def setup_pau(pau):
pau['principals'] = PrincipalFolder()
pau.authenticatorPlugins = ('principals',)
@@ -39,30 +40,39 @@
grok.local_utility(role_factory(u'Site Member'), IRole,
name='logindemo.member',
name_in_container='logindemo.member')
+
+class Master(grok.View):
+ """
+ The master page template macro.
+ """
+ grok.context(Interface) # register this view for all objects
-class Index(grok.View):
+ message = '' # used to give feedback
+
+ def logged_in(self):
+ return not IUnauthenticatedPrincipal.providedBy(self.request.principal)
+
+class Index(Master):
"""
The main page, where the user can login or click a link to join.
"""
- def logged_in(self):
- return not IUnauthenticatedPrincipal.providedBy(self.request.principal)
-
-class Login(grok.View):
- grok.context(Interface)
-
- message = '' # used to give feedback on failed logins
-
+class Login(Master):
+ """
+ Login form and handler.
+ """
def update(self, login_submit=None):
- # XXX: need to display some kind of feedback when the login fails
if login_submit is not None:
if IUnauthenticatedPrincipal.providedBy(self.request.principal):
- self.message = u'Invalid login name and/or password'
+ self.message = _(u'Invalid login name and/or password')
else:
destination = self.request.get('camefrom', self.application_url())
self.redirect(destination)
class Logout(grok.View):
+ """
+ Logout handler.
+ """
grok.context(Interface)
def render(self):
session = getUtility(IAuthentication)['session']
@@ -70,10 +80,10 @@
self.redirect(self.application_url())
class Join(grok.AddForm):
- """User registration form"""
-
+ """
+ User registration form.
+ """
form_fields = grok.AutoFields(IUser)
- #template = grok.PageTemplateFile('form.pt')
form_title = u'User registration'
@grok.action('Save')
@@ -83,7 +93,7 @@
principals = pau['principals']
if login in principals: # duplicate login name
### XXX: find out how to display this message in the form template
- msg = u'Duplicate login. Please choose a different one.'
+ msg = _(u'Duplicate login. Please choose a different one.')
self.redirect(self.url()+'?'+urlencode({'error_msg':msg}))
else:
# add principal to principal folder
@@ -94,5 +104,12 @@
role_manager.assignRoleToPrincipal('logindemo.member',
principals.prefix + login)
self.redirect(self.url('login')+'?'+urlencode({'login':login}))
+
+class Account(grok.View):
+
+ def render(self):
+ return 'Not implemented'
+
+
\ No newline at end of file
Modified: grokapps/LoginDemo/src/logindemo/app_templates/index.pt
===================================================================
--- grokapps/LoginDemo/src/logindemo/app_templates/index.pt 2007-12-28 23:22:28 UTC (rev 82508)
+++ grokapps/LoginDemo/src/logindemo/app_templates/index.pt 2007-12-28 23:29:25 UTC (rev 82509)
@@ -1,8 +1,6 @@
-<html>
-<head>
-<title>Grok Login Sample Application</title>
-</head>
+<html metal:use-macro="context/@@master/macros/page">
<body>
+<div metal:fill-slot="main">
<h1>Front Page</h1>
<h3>User information</h3>
@@ -26,6 +24,6 @@
<form metal:use-macro="context/@@login/macros/loginform" />
</tal:not_logged_in>
-
+</div>
</body>
</html>
Modified: grokapps/LoginDemo/src/logindemo/app_templates/login.pt
===================================================================
--- grokapps/LoginDemo/src/logindemo/app_templates/login.pt 2007-12-28 23:22:28 UTC (rev 82508)
+++ grokapps/LoginDemo/src/logindemo/app_templates/login.pt 2007-12-28 23:29:25 UTC (rev 82509)
@@ -1,12 +1,8 @@
-<html>
-<head>
-<title>Login</title>
-</head>
+<html metal:use-macro="context/@@master/macros/page">
<body>
+<div metal:fill-slot="main">
<h1>Login</h1>
-
- <div tal:condition="view/message" tal:content="view/message" />
-
+
<form metal:define-macro="loginform" action="login" method="post">
<input type="hidden" name="camefrom"
tal:condition="exists:request/camefrom"
@@ -35,6 +31,6 @@
</table>
</form>
-
+</div>
</body>
</html>
Added: grokapps/LoginDemo/src/logindemo/app_templates/master.pt
===================================================================
--- grokapps/LoginDemo/src/logindemo/app_templates/master.pt (rev 0)
+++ grokapps/LoginDemo/src/logindemo/app_templates/master.pt 2007-12-28 23:29:25 UTC (rev 82509)
@@ -0,0 +1,31 @@
+<html metal:define-macro="page">
+<head>
+<title>Grok Login Sample Application</title>
+</head>
+<body>
+ <table border="1" width="100%">
+ <tr tal:condition="not:view/logged_in">
+ <td width="80%">you are not logged in</td>
+ <td width="10%"><a href="join">join</a></td>
+ <td width="10%"><a href="login">login</a></td>
+ </tr>
+ <tr tal:condition="view/logged_in">
+ <td width="80%"
+ tal:content="string:${request/principal/title}
+ (${request/principal/id})">
+ principal.title (principal.id)
+ </td>
+ <td width="10%"><a href="account">account</a></td>
+ <td width="10%"><a href="logout">logout</a></td>
+ </tr>
+ </table>
+ <div style="background: yellow;"
+ tal:condition="view/message"
+ tal:content="view/message"
+ />
+ <div metal:define-slot="main">
+ Here goes the main content of the page
+ </div>
+
+</body>
+</html>
Property changes on: grokapps/LoginDemo/src/logindemo/ftests
___________________________________________________________________
Name: svn:ignore
+ *.pyc
Modified: grokapps/LoginDemo/src/logindemo/ftests/index.txt
===================================================================
--- grokapps/LoginDemo/src/logindemo/ftests/index.txt 2007-12-28 23:22:28 UTC (rev 82508)
+++ grokapps/LoginDemo/src/logindemo/ftests/index.txt 2007-12-28 23:29:25 UTC (rev 82509)
@@ -29,9 +29,13 @@
Back to our original browser, let's use the login form to authenticate.
-First, we will provide the wrong password, and that will take us to the
-login page with a feedback message::
+(XXX I don't know why mgr:mgrpw authenticates when we add a basic auth header
+like in the previous test but does not work when we provide the values
+through the form like in the next test)
+Initially we don't have a regular user for testing, so any attempt to login
+will lead to the login form with a feedback message::
+
>>> browser.getControl(name='login').value = 'mgr'
>>> browser.getControl(name='password').value = 'mgrpw'
>>> browser.getControl('Log in').click()
@@ -39,4 +43,34 @@
'http://localhost/ld/login'
>>> 'Invalid login name and/or password' in browser.contents
True
+
+Now we use the join form to create an account::
+
+ >>> browser.getLink('join').click()
+ >>> browser.getControl(name='form.login').value = 'fred'
+ >>> browser.getControl(name='form.password').value = 'wilma'
+ >>> browser.getControl(name='form.name').value = 'Fred Flintstone'
+ >>> browser.getControl('Save').click()
+This redirects to the login form again. The login name is filled in, so we
+just need to fill the password to log in.
+
+ >>> browser.getControl(name='login').value
+ 'fred'
+ >>> browser.getControl(name='password').value = 'wilma'
+ >>> browser.getControl('Log in').click()
+
+After we log in, user name and login are shown in the top bar::
+
+ >>> browser.contents
+ '...Fred Flintstone...(fred)...'
+
+We can always log out, which leads us back to the main page::
+
+ >>> browser.getLink('logout').click()
+ >>> browser.url
+ 'http://localhost/ld'
+ >>> 'you are not logged in' in browser.contents
+ True
+
+
Modified: grokapps/LoginDemo/src/logindemo/interfaces.py
===================================================================
--- grokapps/LoginDemo/src/logindemo/interfaces.py 2007-12-28 23:22:28 UTC (rev 82508)
+++ grokapps/LoginDemo/src/logindemo/interfaces.py 2007-12-28 23:29:25 UTC (rev 82509)
@@ -1,6 +1,20 @@
+import re
+
from zope.interface import Interface
from zope import schema
+from zope.i18n import MessageFactory
+_ = MessageFactory('logindemo')
+
+class NotAnEmailAddress(schema.ValidationError):
+ __doc__ = _(u"Invalid email address")
+
+check_email = re.compile(r"[a-zA-Z0-9._%-]+@([a-zA-Z0-9-]+\.)*[a-zA-Z]{2,4}").match
+def validate_email(value):
+ if not check_email(value):
+ raise NotAnEmailAddress(value)
+ return True
+
class IUser(Interface):
"""Basic user data."""
login = schema.TextLine(title=u"Login",
@@ -10,4 +24,5 @@
name = schema.TextLine(title=u"Real name",
required=False)
email = schema.ASCIILine(title=u"E-mail",
- required=False)
+ required=False,
+ constraint=validate_email)
More information about the Checkins
mailing list