Email invite users - peer review

87 views
Skip to first unread message

James Burke

unread,
May 20, 2015, 4:12:24 AM5/20/15
to web...@googlegroups.com
Hi,

I'm looking for a peer review of some code I put together for email inviting users to join an application. I couldn't find anything suitable looking around, hopefully I didn't overlook anything!

The idea is, you enter in email addresses into a form, click submit and it will send an email to the email address with an invite to your application. The email will contain a link which the user clicks to take them to a form to fill in the rest of their required details, name etc.

I've tested this and it works, but I would like to know what others thoughts are and there are any improvements that could be made.

Thank you!

default.py controller
def index():
    form=FORM('Enter a comma separated list of emails to send invites:',
              BR(),
              INPUT(_id='emails', _value=''),
              INPUT(_type='submit'))

    if form.accepts(request,session):
        # send the invitations
        for email in form.vars.email.split(','):
            auth.invite_user(email=email)
        response.flash = 'Invitations sent'

    return dict(form=form)

def confirm_registration():
   
return dict(form=auth.confirm_registration())




gluon/tools.py
def confirm_registration(
       
self,
       
next=DEFAULT,
        onvalidation
=DEFAULT,
        onaccept
=DEFAULT,
        log
=DEFAULT,
       
):
       
"""
        Modified version of Auth.reset_password()
        """



        table_user
= self.table_user()
        request
= current.request
       
# response = current.response
        session
= current.session


       
if next is DEFAULT:
           
next = self.get_vars_next() or self.settings.reset_password_next


       
if self.settings.prevent_password_reset_attacks:
            key
= request.vars.key
           
if not key and len(request.args)>1:
                key
= request.args[-1]
           
if key:
                session
._reset_password_key = key
                redirect
(self.url('confirm_registration'))
           
else:
                key
= session._reset_password_key
       
else:
            key
= request.vars.key or getarg(-1)
       
try:
            t0
= int(key.split('-')[0])
           
if time.time() - t0 > 60 * 60 * 24:
               
raise Exception
            user
= table_user(reset_password_key=key)
           
if not user:
               
raise Exception
       
except Exception as e:
            session
.flash = self.messages.invalid_reset_password
            redirect
(self.url('login', vars=dict(test=e)))
            redirect
(next, client_side=self.settings.client_side)
        passfield
= self.settings.password_field
        form
= SQLFORM.factory(
           
Field('first_name',
                  label
='First Name',
                   required
=True),
           
Field('last_name',
                  label
='Last Name',
                   required
=True),
           
Field('new_password', 'password',
                  label
=self.messages.new_password,
                  requires
=self.table_user()[passfield].requires),
           
Field('new_password2', 'password',
                  label
=self.messages.verify_password,
                  requires
=[IS_EXPR(
                     
'value==%s' % repr(request.vars.new_password),
                                   
self.messages.mismatched_password)]),
            submit_button
='Confirm Registration',
            hidden
=dict(_next=next),
            formstyle
=self.settings.formstyle,
            separator
=self.settings.label_separator
       
)
       
if form.accepts(request, session,
                        hideerror
=self.settings.hideerror):
            user
.update_record(
               
**{passfield: str(form.vars.new_password),
                   
'first_name': str(form.vars.first_name),
                   
'last_name': str(form.vars.last_name),
                   
'registration_key': '',
                   
'reset_password_key': ''})
            session
.flash = self.messages.password_changed
           
if self.settings.login_after_password_change:
               
self.login_user(user)
            redirect
(next, client_side=self.settings.client_side)
       
return form


   
def email_registration(self, user):
       
"""
        Modified version of Auth.email_reset_password()
        """

       
import time
       
from gluon.utils import web2py_uuid


        reset_password_key
= str(int(time.time())) + '-' + web2py_uuid()
        link
= self.url('confirm_registration',
                        vars
={'key': reset_password_key},
                        scheme
=True)


        d
= dict(user)
        d
.update(dict(key=reset_password_key, link=link))
       
if self.settings.mailer and self.settings.mailer.send(
            to
=user.email,
            subject
='Invite to join web2py app',
            message
='Click on the link %(link)s to finalise your registration.' % d):
            user
.update_record(reset_password_key=reset_password_key)
           
return True
       
return False




   
def invite_user(self, email):
        """
        Register the user with only an email and password then send them an email to complete their registration
        """
        user
= self.register_bare(email=email, password=self.random_password())
       
if user:
           
self.email_registration(user)
           
return True
       
else:
           
return False

Massimo Di Pierro

unread,
May 28, 2015, 1:19:07 AM5/28/15
to web...@googlegroups.com, james.b...@gmail.com
think this is an excellent idea. Please submit a pull request.
...

James Burke

unread,
May 28, 2015, 4:22:03 AM5/28/15
to web...@googlegroups.com, james.b...@gmail.com
Will do. Thank you for your feedback.

Anthony

unread,
May 28, 2015, 9:50:31 AM5/28/15
to web...@googlegroups.com, massimo....@gmail.com, james.b...@gmail.com, web2py-developers
I like the idea, but I wonder if the use case is common enough to justify including in the framework (where it will have to be tested and maintained by the developers indefinitely). Instead, maybe this could be a plugin.

Anthony

Ron Chatterjee

unread,
May 28, 2015, 3:38:16 PM5/28/15
to web...@googlegroups.com, massimo....@gmail.com, web2py-d...@googlegroups.com, james.b...@gmail.com
I am little confused. Isn't what bitbucket does anyway. Someone can put their application there and invite others to join? How is this any different?

James Burke

unread,
May 28, 2015, 5:54:26 PM5/28/15
to web...@googlegroups.com
Sorry I probably should have posted this in the Developer group instead.

Ron, this is a possible enhancement to the web2py framework itself, not a suggested application.

Carlos Zenteno

unread,
May 29, 2015, 6:15:48 PM5/29/15
to web...@googlegroups.com
Great idea.  My webapp needs something like this.  Not in bulk but I can modify it
to serve my needs....

James Burke

unread,
May 29, 2015, 9:15:38 PM5/29/15
to web...@googlegroups.com, james.b...@gmail.com
I've submitted a pull request under the username Peregrinius.

As noted my initial code relies on register_bare, which seems to have since been removed.

On Thursday, May 28, 2015 at 5:19:07 PM UTC+12, Massimo Di Pierro wrote:
Reply all
Reply to author
Forward
0 new messages