Special handling for login failure messages
authorSofia Papagiannaki <papagian@gmail.com>
Tue, 20 Nov 2012 12:19:20 +0000 (14:19 +0200)
committerSofia Papagiannaki <papagian@gmail.com>
Tue, 20 Nov 2012 12:19:20 +0000 (14:19 +0200)
Refs: #3041

snf-astakos-app/astakos/im/forms.py
snf-astakos-app/astakos/im/target/local.py
snf-astakos-app/astakos/im/target/shibboleth.py
snf-astakos-app/astakos/im/urls.py
snf-astakos-app/astakos/im/views.py

index 3e498db..c7e6098 100644 (file)
@@ -359,9 +359,17 @@ class LoginForm(AuthenticationForm):
             raise forms.ValidationError(_('You have not entered the correct words'))
     
     def clean(self):
-        super(LoginForm, self).clean()
-        if self.user_cache and self.user_cache.provider not in ('local', ''):
-            raise forms.ValidationError(_('Local login is not the current authentication method for this account.'))
+        """
+        Override default behavior in order to check user's activation later
+        """
+        try:
+            super(LoginForm, self).clean()
+        except forms.ValidationError, e:
+            if self.user_cache is None:
+                raise
+            if self.request:
+                if not self.request.session.test_cookie_worked():
+                    raise
         return self.cleaned_data
 
 class ProfileForm(forms.ModelForm):
index d993fdb..be01455 100644 (file)
@@ -81,14 +81,21 @@ def login(request, on_failure='im/login.html'):
     if not user:
         message = _('Cannot authenticate account')
     elif not user.is_active:
-        if user.sent_activation:
+        if not user.activation_sent:
             message = _('Your request is pending activation')
         else:
-            message = _('You have not followed the activation link')
+            url = reverse('send_activation', kwargs={'user_id':user.id})
+            message = _('You have not followed the activation link. \
+            <a href="%s">Provide new email?</a>' % url)
+    elif user.provider not in ('local', ''):
+        message = _(
+            'Local login is not the current authentication method for this account.'
+        )
+    
     if message:
-        messages.add_message(request, messages.ERROR, message)
+        messages.error(request, message)
         return render_to_response(on_failure,
-                                  {'form':form},
+                                  {'login_form':form},
                                   context_instance=RequestContext(request))
     
     # hook for switching account to use third party authentication
index c6866d6..789b0bb 100644 (file)
@@ -70,8 +70,8 @@ class Tokens:
 @requires_anonymous
 def login(
     request,
-    on_login_template='im/login.html',
-    on_signup_template='im/third_party_check_local.html',
+    login_template='im/login.html',
+    signup_template='im/third_party_check_local.html',
     extra_context=None
 ):
     extra_context = extra_context or {}
@@ -79,24 +79,28 @@ def login(
     tokens = request.META
     
     try:
-        eppn = tokens[Tokens.SHIB_EPPN]
+        eppn = tokens.get(Tokens.SHIB_EPPN)
         if not eppn:
-            raise KeyError
-    except KeyError:
-        return HttpResponseBadRequest("Missing unique token in request")
-    
-    if Tokens.SHIB_DISPLAYNAME in tokens:
-        realname = tokens[Tokens.SHIB_DISPLAYNAME]
-    elif Tokens.SHIB_CN in tokens:
-        realname = tokens[Tokens.SHIB_CN]
-    elif Tokens.SHIB_NAME in tokens and Tokens.SHIB_SURNAME in tokens:
-        realname = tokens[Tokens.SHIB_NAME] + ' ' + tokens[Tokens.SHIB_SURNAME]
-    else:
-        return HttpResponseBadRequest("Missing user name in request")
+            raise KeyError(_('Missing unique token in request'))
+        if Tokens.SHIB_DISPLAYNAME in tokens:
+            realname = tokens[Tokens.SHIB_DISPLAYNAME]
+        elif Tokens.SHIB_CN in tokens:
+            realname = tokens[Tokens.SHIB_CN]
+        elif Tokens.SHIB_NAME in tokens and Tokens.SHIB_SURNAME in tokens:
+            realname = tokens[Tokens.SHIB_NAME] + ' ' + tokens[Tokens.SHIB_SURNAME]
+        else:
+            raise KeyError(_('Missing user name in request'))
+    except KeyError, e:
+        extra_context['login_form'] = LoginForm(request=request)
+        messages.error(request, e)
+        return render_response(
+            login_template,
+            context_instance=get_context(request, extra_context)
+        )
     
     affiliation = tokens.get(Tokens.SHIB_EP_AFFILIATION, '')
     email = tokens.get(Tokens.SHIB_MAIL, '')
-        
+    
     try:
         user = AstakosUser.objects.get(
             provider='shibboleth',
@@ -107,12 +111,17 @@ def login(
                                     user,
                                     request.GET.get('next'),
                                     'renew' in request.GET)
+        elif not user.activation_sent:
+            message = _('Your request is pending activation')
+            messages.error(request, message)
         else:
-            message = _('Inactive account')
-            messages.add_message(request, messages.ERROR, message)
-            return render_response(on_login_template,
-                                   login_form = LoginForm(request=request),
-                                   context_instance=RequestContext(request))
+            url = reverse('send_activation', kwargs={'user_id':user.id})
+            message = _('You have not followed the activation link. \
+            <a href="%s">Provide new email?</a>' % url)
+            messages.error(request, message)
+        return render_response(login_template,
+                               login_form = LoginForm(request=request),
+                               context_instance=RequestContext(request))
     except AstakosUser.DoesNotExist, e:
         # First time
         try:
@@ -128,7 +137,7 @@ def login(
             user.save()
         except BaseException, e:
             logger.exception(e)
-            template = on_login_template
+            template = login_template
             extra_context['login_form'] = LoginForm(request=request)
             messages.error(request, _('Something went wrong.'))
         else:
@@ -141,7 +150,7 @@ def login(
                 url = urlunsplit(parts)
                 return HttpResponseRedirect(url)
             else:
-                template = on_signup_template
+                template = signup_template
                 extra_context['key'] = user.username
         
         extra_context['provider']='shibboleth'
index 44d5fb9..25c4825 100644 (file)
@@ -50,6 +50,7 @@ urlpatterns = patterns('astakos.im.views',
     url(r'^approval_terms/?$', 'approval_terms', {}, name='latest_terms'),
     url(r'^approval_terms/(?P<term_id>\d+)/?$', 'approval_terms'),
     url(r'^password/?$', 'change_password', {}, name='password_change'),
+    url(r'^send/activation/(?P<user_id>\d+)/?$', 'send_activation', {}, name='send_activation')
 )
 
 if EMAILCHANGE_ENABLED:
index 0b28ceb..12997ae 100644 (file)
@@ -61,7 +61,8 @@ from astakos.im.util import (
 )
 from astakos.im.forms import *
 from astakos.im.functions import (send_greeting, send_feedback, SendMailError,
-    invite as invite_func, logout as auth_logout, activate as activate_func
+    invite as invite_func, logout as auth_logout, activate as activate_func,
+    send_activation as send_activation_func
 )
 from astakos.im.settings import (DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL,
     COOKIE_NAME, COOKIE_DOMAIN, IM_MODULES, SITENAME, LOGOUT_NEXT, LOGGING_LEVEL
@@ -116,7 +117,7 @@ def signed_terms_required(func):
 
 @require_http_methods(["GET", "POST"])
 @signed_terms_required
-def index(request, login_template_name='im/login.html', profile_template_name='im/profile.html', extra_context={}):
+def index(request, login_template_name='im/login.html', profile_template_name='im/profile.html', extra_context=None):
     """
     If there is logged on user renders the profile page otherwise renders login page.
 
@@ -138,6 +139,7 @@ def index(request, login_template_name='im/login.html', profile_template_name='i
     im/profile.html or im/login.html or ``template_name`` keyword argument.
 
     """
+    extra_context = extra_context or {}
     template_name = login_template_name
     if request.user.is_authenticated():
         return HttpResponseRedirect(reverse('astakos.im.views.edit_profile'))
@@ -152,7 +154,7 @@ def index(request, login_template_name='im/login.html', profile_template_name='i
 @login_required
 @signed_terms_required
 @transaction.commit_manually
-def invite(request, template_name='im/invitations.html', extra_context={}):
+def invite(request, template_name='im/invitations.html', extra_context=None):
     """
     Allows a user to invite somebody else.
 
@@ -186,6 +188,7 @@ def invite(request, template_name='im/invitations.html', extra_context={}):
     * ASTAKOS_DEFAULT_CONTACT_EMAIL: service support email
     * ASTAKOS_DEFAULT_FROM_EMAIL: from email
     """
+    extra_context = extra_context or {}
     status = None
     message = None
     form = InvitationForm()
@@ -230,7 +233,7 @@ def invite(request, template_name='im/invitations.html', extra_context={}):
 @require_http_methods(["GET", "POST"])
 @login_required
 @signed_terms_required
-def edit_profile(request, template_name='im/profile.html', extra_context={}):
+def edit_profile(request, template_name='im/profile.html', extra_context=None):
     """
     Allows a user to edit his/her profile.
 
@@ -259,6 +262,7 @@ def edit_profile(request, template_name='im/profile.html', extra_context={}):
 
     * LOGIN_URL: login uri
     """
+    extra_context = extra_context or {}
     form = ProfileForm(instance=request.user)
     extra_context['next'] = request.GET.get('next')
     reset_cookie = False
@@ -290,7 +294,7 @@ def edit_profile(request, template_name='im/profile.html', extra_context={}):
                                                           extra_context))
 
 @require_http_methods(["GET", "POST"])
-def signup(request, template_name='im/signup.html', on_success='im/signup_complete.html', extra_context={}, backend=None):
+def signup(request, template_name='im/signup.html', on_success='im/signup_complete.html', extra_context=None, backend=None):
     """
     Allows a user to create a local account.
 
@@ -325,6 +329,7 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple
     im/signup.html or ``template_name`` keyword argument.
     im/signup_complete.html or ``on_success`` keyword argument. 
     """
+    extra_context = extra_context or {}
     if request.user.is_authenticated():
         return HttpResponseRedirect(reverse('astakos.im.views.edit_profile'))
     
@@ -375,7 +380,7 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple
 @require_http_methods(["GET", "POST"])
 @login_required
 @signed_terms_required
-def feedback(request, template_name='im/feedback.html', email_template_name='im/feedback_mail.txt', extra_context={}):
+def feedback(request, template_name='im/feedback.html', email_template_name='im/feedback_mail.txt', extra_context=None):
     """
     Allows a user to send feedback.
 
@@ -402,6 +407,7 @@ def feedback(request, template_name='im/feedback.html', email_template_name='im/
     * LOGIN_URL: login uri
     * ASTAKOS_DEFAULT_CONTACT_EMAIL: List of feedback recipients
     """
+    extra_context = extra_context or {}
     if request.method == 'GET':
         form = FeedbackForm()
     if request.method == 'POST':
@@ -426,10 +432,11 @@ def feedback(request, template_name='im/feedback.html', email_template_name='im/
                            context_instance = get_context(request, extra_context))
 
 @require_http_methods(["GET"])
-def logout(request, template='registration/logged_out.html', extra_context={}):
+def logout(request, template='registration/logged_out.html', extra_context=None):
     """
     Wraps `django.contrib.auth.logout` and delete the cookie.
     """
+    extra_context = extra_context or {}
     response = HttpResponse()
     msg = None
     if request.user.is_authenticated():
@@ -501,7 +508,8 @@ def activate(request, greeting_email_template_name='im/welcome_email.txt', helpd
         return index(request)
 
 @require_http_methods(["GET", "POST"])
-def approval_terms(request, term_id=None, template_name='im/approval_terms.html', extra_context={}):
+def approval_terms(request, term_id=None, template_name='im/approval_terms.html', extra_context=None):
+    extra_context = extra_context or {}
     term = None
     terms = None
     if not term_id:
@@ -559,7 +567,8 @@ def change_email(request, activation_key=None,
                  email_template_name='registration/email_change_email.txt',
                  form_template_name='registration/email_change_form.html',
                  confirm_template_name='registration/email_change_done.html',
-                 extra_context={}):
+                 extra_context=None):
+    extra_context = extra_context or {}
     if activation_key:
         try:
             user = EmailChange.objects.change_email(activation_key)
@@ -599,6 +608,28 @@ def change_email(request, activation_key=None,
             transaction.commit()
         messages.add_message(request, status, msg)
     return render_response(form_template_name,
-                           form = form,
-                           context_instance = get_context(request,
-                                                          extra_context))
+                           form = form,)
+
+
+def send_activation(request, user_id, template_name='im/login.html', extra_context=None):
+    extra_context = extra_context or {}
+    try:
+        u = AstakosUser.objects.get(id=user_id)
+    except AstakosUser.DoesNotExist:
+        messages.error(request, _('Invalid user id'))
+    else:
+        try:
+            send_activation_func(u)
+            msg = _('Activation sent.')
+            messages.success(request, msg)
+        except SendMailError, e:
+            messages.error(request, e)
+    return render_response(
+        template_name,
+        login_form = LoginForm(request=request), 
+        context_instance = get_context(
+            request,
+            extra_context
+        )
+    )
+