change signup flow, remove activateuser command and introduce sendactivation command
authorSofia Papagiannaki <papagian@gmail.com>
Wed, 14 Mar 2012 15:14:54 +0000 (17:14 +0200)
committerSofia Papagiannaki <papagian@gmail.com>
Wed, 14 Mar 2012 15:14:54 +0000 (17:14 +0200)
snf-astakos-app/astakos/im/backends.py
snf-astakos-app/astakos/im/functions.py
snf-astakos-app/astakos/im/management/commands/sendactivation.py [moved from snf-astakos-app/astakos/im/management/commands/activateuser.py with 88% similarity]
snf-astakos-app/astakos/im/views.py

index e99bbef..ae699f4 100644 (file)
@@ -42,12 +42,12 @@ from django.db import transaction
 from django.core.urlresolvers import reverse
 
 from smtplib import SMTPException
-from urllib import quote
 from urlparse import urljoin
 
 from astakos.im.models import AstakosUser, Invitation
 from astakos.im.forms import *
 from astakos.im.util import get_invitation
+from astakos.im.functions import send_verification, send_notification, activate
 from astakos.im.settings import INVITATIONS_ENABLED, DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, MODERATION_ENABLED, SITENAME, BASEURL, DEFAULT_ADMIN_EMAIL, RE_USER_EMAIL_PATTERNS
 
 import socket
@@ -157,7 +157,7 @@ class InvitationsBackend(SignupBackend):
         return False
 
     @transaction.commit_manually
-    def signup(self, form, email_template_name='im/activation_email.txt', admin_email_template_name='im/admin_notification.txt'):
+    def signup(self, form, verification_template_name='im/activation_email.txt', greeting_template_name='im/welcome_email.txt', admin_email_template_name='im/admin_notification.txt'):
         """
         Initially creates an inactive user account. If the user is preaccepted
         (has a valid invitation code) the user is activated and if the request
@@ -172,23 +172,26 @@ class InvitationsBackend(SignupBackend):
             user = form.save()
             if self._is_preaccepted(user):
                 if user.email_verified:
-                    user.is_active = True
-                    user.save()
-                    message = _('Registration completed. You can now login.')
+                    try:
+                        activate(user, greeting_template_name)
+                        message = _('Registration completed. You can now login.')
+                    except (SMTPException, socket.error) as e:
+                        status = messages.ERROR
+                        name = 'strerror'
+                        message = getattr(e, 'name') if hasattr(e, 'name') else e
                 else:
                     try:
-                        _send_verification(self.request, user, email_template_name)
+                        send_verification(user, verification_template_name)
                         message = _('Verification sent to %s' % user.email)
                     except (SMTPException, socket.error) as e:
                         status = messages.ERROR
                         name = 'strerror'
-                        message = getattr(e, name) if hasattr(e, name) else e
+                        message = getattr(e, 'name') if hasattr(e, 'name') else e
             else:
-                _send_notification(user, admin_email_template_name)
-                message = _('Your request for an account was successfully sent \
-                            and pending approval from our administrators. You \
-                            will be notified by email the next days. \
-                            Thanks for being patient, the GRNET team')
+                send_notification(user, admin_email_template_name)
+                message = _('Your request for an account was successfully received and is now pending \
+                            approval. You will be notified by email in the next few days. Thanks for \
+                            your interest in ~okeanos! The GRNET team.')
             status = messages.SUCCESS
         except Invitation.DoesNotExist, e:
             status = messages.ERROR
@@ -264,23 +267,22 @@ class SimpleBackend(SignupBackend):
         status = messages.SUCCESS
         if not self._is_preaccepted(user):
             try:
-                _send_notification(user, admin_email_template_name)
-                message = _('Your request for an account was successfully sent \
-                            and pending approval from our administrators. You \
-                            will be notified by email the next days. \
-                            Thanks for being patient, the GRNET team')
+                send_notification(user, admin_email_template_name)
+                message = _('Your request for an account was successfully received and is now pending \
+                            approval. You will be notified by email in the next few days. Thanks for \
+                            your interest in ~okeanos! The GRNET team.')
             except (SMTPException, socket.error) as e:
                 status = messages.ERROR
                 name = 'strerror'
-                message = getattr(e, name) if hasattr(e, name) else e
+                message = getattr(e, 'name') if hasattr(e, 'name') else e
         else:
             try:
-                _send_verification(self.request, user, email_template_name)
+                send_verification(user, email_template_name)
                 message = _('Verification sent to %s' % user.email)
             except (SMTPException, socket.error) as e:
                 status = messages.ERROR
                 name = 'strerror'
-                message = getattr(e, name) if hasattr(e, name) else e
+                message = getattr(e, 'name') if hasattr(e, 'name') else e
 
         # rollback in case of error
         if status == messages.ERROR:
@@ -288,29 +290,3 @@ class SimpleBackend(SignupBackend):
         else:
             transaction.commit()
         return status, message, user
-
-def _send_verification(request, user, template_name):
-    url = '%s?auth=%s&next=%s' % (urljoin(BASEURL, reverse('astakos.im.views.activate')),
-                                    quote(user.auth_token),
-                                    quote(BASEURL))
-    message = render_to_string(template_name, {
-            'user': user,
-            'url': url,
-            'baseurl': BASEURL,
-            'site_name': SITENAME,
-            'support': DEFAULT_CONTACT_EMAIL})
-    sender = DEFAULT_FROM_EMAIL
-    send_mail('%s  alpha2 testing account activation' % SITENAME, message, sender, [user.email])
-    logger.info('Sent activation %s', user)
-
-def _send_notification(user, template_name):
-    if not DEFAULT_ADMIN_EMAIL:
-        return
-    message = render_to_string(template_name, {
-            'user': user,
-            'baseurl': BASEURL,
-            'site_name': SITENAME,
-            'support': DEFAULT_CONTACT_EMAIL})
-    sender = DEFAULT_FROM_EMAIL
-    send_mail('%s  alpha2 testing account notification' % SITENAME, message, sender, [DEFAULT_ADMIN_EMAIL])
-    logger.info('Sent admin notification for user %s', user)
index 43bb9d6..d9f3196 100644 (file)
@@ -37,22 +37,75 @@ from django.utils.translation import ugettext as _
 from django.template.loader import render_to_string
 from django.core.mail import send_mail
 from django.core.urlresolvers import reverse
+from urllib import quote
 from urlparse import urljoin
 from random import randint
 
-from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, SITENAME, BASEURL
+from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, SITENAME, BASEURL, DEFAULT_ADMIN_EMAIL
 from astakos.im.models import Invitation
 
 logger = logging.getLogger(__name__)
 
-def activate(user, email_template_name='im/welcome_email.txt'):
+def send_verification(user, template_name='im/activation_email.txt'):
     """
-    Activates the specific user and sends email.
+    Send email to user to verify his/her email and activate his/her account.
+    
+    Raises SMTPException, socket.error
+    """
+    url = '%s?auth=%s&next=%s' % (urljoin(BASEURL, reverse('astakos.im.views.activate')),
+                                    quote(user.auth_token),
+                                    quote(BASEURL))
+    message = render_to_string(template_name, {
+            'user': user,
+            'url': url,
+            'baseurl': BASEURL,
+            'site_name': SITENAME,
+            'support': DEFAULT_CONTACT_EMAIL})
+    sender = DEFAULT_FROM_EMAIL
+    send_mail('%s  alpha2 testing account activation' % SITENAME, message, sender, [user.email])
+    logger.info('Sent activation %s', user)
+
+def send_notification(user, template_name='im/admin_notification.txt'):
+    """
+    Send email to DEFAULT_ADMIN_EMAIL to notify for a new user registration.
+    
+    Raises SMTPException, socket.error
+    """
+    if not DEFAULT_ADMIN_EMAIL:
+        return
+    message = render_to_string(template_name, {
+            'user': user,
+            'baseurl': BASEURL,
+            'site_name': SITENAME,
+            'support': DEFAULT_CONTACT_EMAIL})
+    sender = DEFAULT_FROM_EMAIL
+    send_mail('%s  alpha2 testing account notification' % SITENAME, message, sender, [DEFAULT_ADMIN_EMAIL])
+    logger.info('Sent admin notification for user %s', user)
+
+def send_invitation(invitation, template_name='im/invitation.txt'):
+    """
+    Send invitation email.
+    
+    Raises SMTPException, socket.error
+    """
+    subject = _('Invitation to %s alpha2 testing' % SITENAME)
+    url = '%s?code=%d' % (urljoin(BASEURL, reverse('astakos.im.views.signup')), invitation.code)
+    message = render_to_string('im/invitation.txt', {
+                'invitation': invitation,
+                'url': url,
+                'baseurl': BASEURL,
+                'site_name': SITENAME,
+                'support': DEFAULT_CONTACT_EMAIL})
+    sender = DEFAULT_FROM_EMAIL
+    send_mail(subject, message, sender, [invitation.username])
+    logger.info('Sent invitation %s', invitation)
+
+def send_greeting(user, email_template_name='im/welcome_email.txt'):
+    """
+    Send welcome email.
     
     Raises SMTPException, socket.error
     """
-    user.is_active = True
-    user.save()
     subject = _('Welcome to %s alpha2 testing' % SITENAME)
     message = render_to_string(email_template_name, {
                 'user': user,
@@ -64,6 +117,16 @@ def activate(user, email_template_name='im/welcome_email.txt'):
     send_mail(subject, message, sender, [user.email])
     logger.info('Sent greeting %s', user)
 
+def activate(user, email_template_name='im/welcome_email.txt'):
+    """
+    Activates the specific user and sends email.
+    
+    Raises SMTPException, socket.error
+    """
+    user.is_active = True
+    user.save()
+    send_greeting(user, email_template_name)
+
 def _generate_invitation_code():
     while True:
         code = randint(1, 2L**63 - 1)
@@ -73,7 +136,7 @@ def _generate_invitation_code():
         except Invitation.DoesNotExist:
             return code
 
-def invite(inviter, username, realname):
+def invite(inviter, username, realname, email_template_name='im/welcome_email.txt'):
     """
     Send an invitation email and upon success reduces inviter's invitation by one.
     
@@ -85,16 +148,6 @@ def invite(inviter, username, realname):
                             code=code,
                             realname=realname)
     invitation.save()
-    subject = _('Invitation to %s alpha2 testing' % SITENAME)
-    url = '%s?code=%d' % (urljoin(BASEURL, reverse('astakos.im.views.signup')), code)
-    message = render_to_string('im/invitation.txt', {
-                'invitation': invitation,
-                'url': url,
-                'baseurl': BASEURL,
-                'service': SITENAME,
-                'support': DEFAULT_CONTACT_EMAIL})
-    sender = DEFAULT_FROM_EMAIL
-    send_mail(subject, message, sender, [invitation.username])
-    logger.info('Sent invitation %s', invitation)
+    send_invitation(invitation, email_template_name)
     inviter.invitations = max(0, inviter.invitations - 1)
     inviter.save()
 from django.core.management.base import BaseCommand, CommandError
 from django.db import transaction
 
-from astakos.im.functions import activate
+from astakos.im.functions import send_verification
 
 from ._common import get_user
     
 
 class Command(BaseCommand):
     args = "<user ID or email> [user ID or email] ..."
-    help = "Activates one or more users"
+    help = "Sends an activation email to one or more users"
     
-    @transaction.commit_manually
     def handle(self, *args, **options):
         if not args:
             raise CommandError("No user was given")
@@ -59,11 +58,6 @@ class Command(BaseCommand):
                 self.stderr.write(msg)
                 continue
             
-            try:
-                activate(user)
-                transaction.commit()
-            except Exception, e:
-                transaction.rollback()
-                raise e
+            send_verification(user)
             
             self.stdout.write("Activated '%s'\n" % (user.email,))
\ No newline at end of file
index ad85749..30c0cc6 100644 (file)
@@ -49,13 +49,14 @@ from django.contrib import messages
 from django.db import transaction
 from django.contrib.auth import logout as auth_logout
 from django.utils.http import urlencode
-from django.http import HttpResponseRedirect
+from django.http import HttpResponseRedirect, HttpResponseBadRequest
 from django.db.utils import IntegrityError
 
 from astakos.im.models import AstakosUser, Invitation
 from astakos.im.backends import get_backend
 from astakos.im.util import get_context, prepare_response, set_cookie
 from astakos.im.forms import *
+from astakos.im.functions import send_greeting
 from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, COOKIE_NAME, COOKIE_DOMAIN, IM_MODULES, SITENAME, BASEURL, LOGOUT_NEXT
 from astakos.im.functions import invite as invite_func
 
@@ -396,18 +397,32 @@ def logout(request, template='registration/logged_out.html', extra_context={}):
     response.write(render_to_string(template, context_instance=context))
     return response
 
-def activate(request):
+@transaction.commit_manually
+def activate(request, email_template_name='im/welcome_email.txt', on_failure=''):
     """
-    Activates the user identified by the ``auth`` request parameter
+    Activates the user identified by the ``auth`` request parameter, sends a welcome email
+    and renews the user token.
+    
+    The view uses commit_manually decorator in order to ensure the user state will be updated
+    only if the email will be send successfully.
     """
     token = request.GET.get('auth')
     next = request.GET.get('next')
     try:
         user = AstakosUser.objects.get(auth_token=token)
     except AstakosUser.DoesNotExist:
-        return HttpResponseBadRequest('No such user')
+        return HttpResponseBadRequest(_('No such user'))
     
     user.is_active = True
     user.email_verified = True
     user.save()
-    return prepare_response(request, user, next, renew=True)
+    try:
+        send_greeting(user, email_template_name)
+        response = prepare_response(request, user, next, renew=True)
+        transaction.commit()
+        return response
+    except (SMTPException, socket.error) as e:
+        message = getattr(e, 'name') if hasattr(e, 'name') else e
+        messages.add_message(request, messages.ERROR, message)
+        transaction.rollback()
+        return signup(request, on_failure='im/signup.html')