Switch to side-by-side view

--- a/opensourceprojects/controllers.py
+++ b/opensourceprojects/controllers.py
@@ -1,3 +1,175 @@
 
-class RootController:
-    pass
+import allura.tasks.mail_tasks
+from allura.controllers.root import RootController as AlluraRootController
+from allura.controllers.auth import AuthController
+from allura.lib.decorators import require_post
+from allura.lib.widgets import forms
+from allura import model as M
+from allura.lib import plugin
+
+from tg import expose, session, flash, redirect, validate, config
+from tg.decorators import with_trailing_slash, without_trailing_slash
+from pylons import c, g, request, response
+
+import ew as ew_core
+import ew.jinja2_ew as ew
+from allura.lib import validators as V
+from formencode import validators as fev
+import formencode
+from allura.lib import helpers as h
+import string, random, os
+from hashlib import sha256
+import logging
+
+log = logging.getLogger(__name__)
+
+class OSPRegistrationForm(forms.ForgeForm):
+    template = 'jinja:opensourceprojects:templates/widgets/forge_form.html'
+    class fields(ew_core.NameList):
+        display_name = ew.TextField(
+            label='Display Name',
+            validator=fev.UnicodeString(not_empty=True),
+            attrs={'placeholder':'Display Name', 'class':'displayname'},
+            show_label=False
+            )
+        username = ew.TextField(
+            label='Desired Username',
+            validator=fev.Regex(h.re_path_portion, not_empty=True),
+            attrs={'placeholder':'Username', 'class':'username'},
+            show_label=False
+            )
+        username.validator._messages['invalid'] = (
+            'Usernames can include letters, numbers, and dashes, but must start with a letter' )
+        email = ew.TextField(
+            label = 'Email Address',
+            validator=fev.Email(not_empty=True),
+            attrs={'placeholder':'Email Address', 'class':'email'},
+            show_label=False
+            )
+
+    @ew_core.core.validator
+    def to_python(self, value, state):
+        d = super(OSPRegistrationForm, self).to_python(value, state)
+        value['username'] = username = value['username'].lower()
+        if M.User.by_username(username):
+            raise formencode.Invalid('That username is already taken. Please choose another.',
+                                    value, state)
+
+        if M.EmailAddress.query.get(_id=value['email'].lower(), confirmed=True):
+            raise formencode.Invalid('That email address is already taken. Please choose another.',
+                                    value, state)
+        
+        return d
+
+form = OSPRegistrationForm(action='/auth2/save_new', submit_text='Sign Up')
+
+class OSPAuthController(AuthController):
+    """
+    This Auth controller modifies account registration
+    """
+
+    @expose('jinja:opensourceprojects:templates/create_account.html')
+    def create_account(self, **kw):
+        c.form = form
+        return dict()
+
+    @expose()
+    @require_post()
+    @validate(form, error_handler=create_account)
+    def save_new(self, display_name=None, username=None, email=None, **kw):
+        pw = OSPAuthController.random_pass(20)
+        user = M.User.register(
+            dict(username=username,
+                 display_name=display_name,
+                 password=pw,
+                 disabled=True))
+
+        user.email_addresses.append(email)
+        em = M.EmailAddress.upsert(str(email))
+        em.claimed_by_user_id=user._id
+        self.send_account_link(em, pw)
+        flash('User "%s" registered, check you email for confirmation' % user.get_pref('display_name'))
+        redirect('/')
+
+    @staticmethod
+    def send_account_link(email, passwd):
+        email.nonce = sha256(os.urandom(10)).hexdigest()
+        log.info('Sending verification link to %s', email._id)
+        text = '''
+You are receiving this email, to confirm the creationg of the account
+%s at opensourceprojects.eu.
+
+To verify the account please visit the following URL:
+
+    %s
+
+Your password for this account is
+   
+   %s
+
+If you did not request this account, please ignore this email.
+
+''' % (email.claimed_by_user().username, g.url('/auth2/verify_acct', a=email.nonce), passwd)
+
+        allura.tasks.mail_tasks.sendmail.post(
+            destinations=[email._id],
+            fromaddr=email._id,
+            reply_to='',
+            subject='OpensourceProjects.eu: Account creation',
+            message_id=h.gen_message_id(),
+            text=text)
+
+    @expose('jinja:opensourceprojects:templates/verify_acct.html')
+    def verify_acct(self, a):
+        """
+        Verify an account using an email token
+        """
+        addr = M.EmailAddress.query.get(nonce=a)
+        if not addr:
+            flash('Unknown verification link', 'error')
+            redirect('/')
+
+        addr.confirmed = True
+        user = addr.claimed_by_user()
+        user.disabled = False
+        return dict(username=user.username)
+        
+    @staticmethod
+    def random_pass(size=8, chars=string.ascii_letters + string.digits):
+        """
+        Generate a random password
+        """
+        return ''.join(random.choice(chars) for i in range(size))
+        
+
+class RootController(AlluraRootController):
+
+    """
+    The root controller for OpenSourceProjects.eu
+    
+    Add the following to the .ini config file to enable
+    this root.
+
+    [app:main]
+    override_root = opensourceprojects
+
+    This controller adds:
+    * An about page
+    * A new auth controller
+    * A new front page
+    """
+
+#    auth = OSPAuthController()
+    auth2 = OSPAuthController()
+
+    @expose('jinja:opensourceprojects:templates/about.html')
+    def about(self):
+        return dict()
+
+    @expose('jinja:opensourceprojects:templates/frontpage.html')
+    @with_trailing_slash
+    def index(self, **kw):
+        return dict(form=OSPRegistrationForm(submit_text='Sign Up now!', action='/auth2/save_new'))
+
+
+