[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