Commits

Walter Danilo Galante  committed 70c9557 Merge

Merged _amol_/tgapp-registration into default

  • Participants
  • Parent commits f7df69d, f556837

Comments (0)

Files changed (11)

 .pyc
+glob:*~
 .swp
 ^build
 ^dist
 .egg-info
 .idea
 .DS_Store
+
 e5438bfae0d5fb27c479a3e64cde9242ed413aa9 0.1
+5a2953fca37c5692a77b4f4548f63bc75e53371d 0.3
+47ce16bc3a88a93d8aa27cbe20c135d6a5e78a04 0.3.1
+85bdd93f1d314c860164382a81bbcd4c7b82b634 0.4.0
+31ea0ae7a03f3c8af50c6d46ee1ed945ed33afd1 0.4.1
 
 The hooks that can be used with TurboGears2 *register_hook* are:
 
+    * **registration.before_registration(submitted_values)** -> Runs after form submission. Can be used to change the values submitted by the form before they are used
+
     * **registration.after_registration(registration, submitted_values)** -> Runs after form submission. Can be used to store eventual data that the form sent and that the Registration model doesn't support.
 
     * **registration.on_complete(email_data)** -> Runs after registration completion before sending activation email, can be used to change outgoing email.
 
     * **registration.before_activation(registration, user)** -> Runs at activation before creating the user and setting the registration as active
 
-    * **registration.before_activation(registration, user)** -> Runs after creating user, can be used to call *redirect* to redirect to a different page at registration completion.
+    * **registration.after_activation(registration, user)** -> Runs after creating user, can be used to call *redirect* to redirect to a different page at registration completion.
 
 Exposed Templates
 --------------------

File registration/bootstrap.py

 from tgext.pluggable import app_model
 
 def bootstrap(command, conf, vars):
-    print 'Bootstrapping registration...'
+    print 'Bootstrapping registration...'
+
+    p = app_model.Permission(permission_name='registration-admin', description='Permits to manage registrations')
+    model.DBSession.add(p)
+    model.DBSession.flush()

File registration/controllers/root.py

 """Main Controller"""
 
 from tg import TGController
-from routes import url_for
-from tg.decorators import Decoration
-from tg import expose, flash, require, url, lurl, request, redirect, validate, config
+from tg import expose, flash, require, url, lurl, request, redirect, validate, config, predicates
 from tg.i18n import ugettext as _, lazy_ugettext as l_
 
-from registration import model
 from registration.model import DBSession, Registration
 from registration.lib import get_form, send_email
 from datetime import datetime
         Registration.clear_expired()
         return dict(form=get_form(), value=kw, action=self.mount_point+'/submit')
 
+    @expose('registration.templates.admin')
+    @require(predicates.has_permission('registration-admin'))
+    def admin(self, **kw):
+        Registration.clear_expired()
+        pending_activation = DBSession.query(Registration).filter(Registration.activated==None)
+        return dict(registrations=pending_activation)
+
     @expose()
     @validate(get_form(), error_handler=index)
     def submit(self, *args, **kw):
             func(new_reg, kw)
 
         return redirect(url(self.mount_point + '/complete',
-                            params=dict(code=new_reg.code, email=new_reg.email_address)))
+                            params=dict(email= new_reg.email_address)))
 
     @expose('registration.templates.complete')
-    @validate(dict(code=UnicodeString(not_empty=True),
-                   email=UnicodeString(not_empty=True)), error_handler=index)
-    def complete(self, email, code):
-        reg = Registration.get_inactive(email, code)
+    @validate(dict(email=UnicodeString(not_empty=True)), error_handler=index)
+    def complete(self, email, **kw):
+        reg = DBSession.query(Registration).filter_by(email_address=email).first()
+
         if not reg:
             flash(_('Registration not found or already activated'))
             return redirect(self.mount_point)
 Please click on this link to confirm your registration
 
 %s
-''' % (url_for(self.mount_point+'/activate', code=code, email=email, qualified=True))}
+''' % reg.activation_link}
 
         hooks = config['hooks'].get('registration.on_complete', [])
         for func in hooks:
             func(email_data)
 
-        send_email(email, email_data['sender'], email_data['subject'], email_data['body'])
+        send_email(reg.email_address, email_data['sender'], email_data['subject'], email_data['body'])
 
-        return dict(email=email, email_data=email_data)
+        return dict(email = email, email_data=email_data)
 
     @expose()
-    @validate(dict(code=UnicodeString(not_empty=True),
-                   email=UnicodeString(not_empty=True)), error_handler=index)
-    def activate(self, email, code):
-        reg = Registration.get_inactive(email, code)
+    @validate(dict(code=UnicodeString(not_empty=True)), error_handler=index)
+    def activate(self, code, **kw):
+        reg = Registration.get_inactive(code)
         if not reg:
             flash(_('Registration not found or already activated'))
             return redirect(self.mount_point)

File registration/lib/__init__.py

     registration_form = config.get('registration.form_instance')
     if not registration_form:
         form_path = config.get('registration.form', 'registration.lib.forms.RegistrationForm')
-        root_module, path = form_path.split('.', 1)
-        form_class = reduce(getattr, path.split('.'), sys.modules[root_module])
+        module, form_name = form_path.rsplit('.', 1)
+        module = __import__(module, fromlist=form_name)
+        form_class = getattr(module, form_name)
         registration_form = config['registration.form_instance'] = form_class()
     return registration_form
 

File registration/lib/validators.py

 import re
+from registration.model.models import Registration
 from tg.i18n import ugettext as _
 from registration.model import DBSession
 from formencode import Invalid
-from tw.forms import validators
+from formencode import validators
 
 from tgext.pluggable import app_model
 
 class UniqueUserValidator(validators.UnicodeString):
+    outputEncoding=None
+
     def validate_python(self, value, state):
         super(UniqueUserValidator, self).validate_python(value, state)
         if re.match("^[a-zA-Z0-9_-]*[a-zA-Z_-][a-zA-Z0-9_-]*$", value):
-            reg = DBSession.query(app_model.User).filter_by(user_name=value).first()
             user = DBSession.query(app_model.User).filter_by(user_name=value).first()
-            if reg or user:
-                raise Invalid(_('username already in use.'), value, state)
+            if user:
+                raise Invalid(_('Username already in use.'), value, state)
         else:
             raise Invalid(_('Invalid username'), value, state)
 
     def validate_python(self, value, state):
         super(UniqueEmailValidator, self).validate_python(value, state)
         if re.match("^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+@((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6}$", value):
-            reg = DBSession.query(app_model.User).filter_by(email_address=value).first()
             user = DBSession.query(app_model.User).filter_by(email_address=value).first()
-            if reg or user:
+            if user:
                 raise Invalid(_('Email address has already been taken'), value, state)
         else:
-            raise Invalid(_('Invalid email'), value, state)
+            raise Invalid(_('Invalid email'), value, state)

File registration/model/models.py

+from tg import url
+from tg.decorators import cached_property
+
 from sqlalchemy import Table, ForeignKey, Column
 from sqlalchemy.types import Unicode, Integer, DateTime
 from sqlalchemy.orm import backref, relation
 
 from registration.model import DeclarativeBase, DBSession
 from tgext.pluggable import app_model, primary_key
+from tgext.pluggable.utils import mount_point
 
 from datetime import datetime, timedelta
 import string, random, time, hashlib
     user_id = Column(Integer, ForeignKey(primary_key(app_model.User)))
     user = relation(app_model.User, uselist=False, backref=backref('registration', uselist=False, cascade='all'))
 
+    @cached_property
+    def activation_link(self):
+        return url(mount_point('registration') + '/activate',
+                   params=dict(code=self.code),
+                   qualified=True)
+
     @classmethod
     def generate_code(cls, email):
         code_space = string.ascii_letters + string.digits
                                       .filter(Registration.time<datetime.now()-timedelta(7)).delete()
 
     @classmethod
-    def get_inactive(cls, email_address, code):
+    def get_inactive(cls, code):
         return DBSession.query(Registration).filter_by(activated=None)\
-                                            .filter_by(code=code)\
-                                            .filter_by(email_address=email_address).first()
+                                            .filter_by(code=code).first()
+                                            

File registration/public/css/style.css

+#registration_admin > table {
+    width: 100%;
+    margin-top: 20px;
+}
+
+#registration_admin > table th,
+#registration_admin > table td {
+    line-height: 20px;
+    padding: 8px;
+    border-top: 1px solid #dddddd;
+    text-align: left;
+}
+
+#registration_admin > table tr:nth-child(even) > td,
+#registration_admin > table tr:nth-child(even) > th {
+    background-color: #f9f9f9;
+}

File registration/templates/admin.html

+<!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://genshi.edgewall.org/"
+      xmlns:xi="http://www.w3.org/2001/XInclude">
+
+<xi:include href="master.html" />
+
+<head>
+    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" py:if="False"/>
+    <title>Registration Admin</title>
+    <link rel="stylesheet" type="text/css" media="screen" href="${tg.url('/_pluggable/registration/css/style.css')}" />
+</head>
+
+<body>
+<div id="registration_admin">
+    <h1>Registration Admin</h1>
+    <table>
+      <tr>
+        <th>Date</th>
+        <th>Email</th>
+        <th>Username</th>
+        <th>Activation Link</th>
+      </tr>
+      <tr py:for="reg in registrations">
+        <td>${reg.time.strftime('%Y-%m-%d %H:%M:%S')}</td>
+        <td>${reg.email_address}</td>
+        <td>${reg.user_name}</td>
+        <td><a href="${reg.activation_link}">activate</a></td>
+      </tr>
+    </table>
+</div>
+</body>
+</html>
     from setuptools import setup, find_packages
 
 install_requires=[
-    "TurboGears2 >= 2.1.4",
+    "TurboGears2 >= 2.2.0",
     "tgext.pluggable"
 ]
 
 
 setup(
     name='tgapp-registration',
-    version='0.2',
+    version='0.4.1',
     description='Pluggable registration application for TurboGears2 with hooks for fine customization',
     long_description=README,
     author='Alessandro Molina',
     author_email='alessandro.molina@axant.it',
     url='http://bitbucket.org/_amol_/tgapp-registration',
     keywords='turbogears2.application',
-    setup_requires=["PasteScript >= 1.7"],
+    setup_requires=[],
     paster_plugins=[],
     packages=find_packages(exclude=['ez_setup']),
     install_requires=install_requires,