From 1f3b4b39c7447ceb4b3dae38538279f75e250377 Mon Sep 17 00:00:00 2001 From: Sofia Papagiannaki Date: Tue, 20 Nov 2012 14:19:20 +0200 Subject: [PATCH] Special handling for login failure messages Refs: #3041 --- snf-astakos-app/astakos/im/forms.py | 14 ++++-- snf-astakos-app/astakos/im/target/local.py | 15 +++++-- snf-astakos-app/astakos/im/target/shibboleth.py | 55 +++++++++++++---------- snf-astakos-app/astakos/im/urls.py | 1 + snf-astakos-app/astakos/im/views.py | 55 ++++++++++++++++++----- 5 files changed, 98 insertions(+), 42 deletions(-) diff --git a/snf-astakos-app/astakos/im/forms.py b/snf-astakos-app/astakos/im/forms.py index 3e498db..c7e6098 100644 --- a/snf-astakos-app/astakos/im/forms.py +++ b/snf-astakos-app/astakos/im/forms.py @@ -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): diff --git a/snf-astakos-app/astakos/im/target/local.py b/snf-astakos-app/astakos/im/target/local.py index d993fdb..be01455 100644 --- a/snf-astakos-app/astakos/im/target/local.py +++ b/snf-astakos-app/astakos/im/target/local.py @@ -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. \ + Provide new email?' % 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 diff --git a/snf-astakos-app/astakos/im/target/shibboleth.py b/snf-astakos-app/astakos/im/target/shibboleth.py index c6866d6..789b0bb 100644 --- a/snf-astakos-app/astakos/im/target/shibboleth.py +++ b/snf-astakos-app/astakos/im/target/shibboleth.py @@ -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. \ + Provide new email?' % 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' diff --git a/snf-astakos-app/astakos/im/urls.py b/snf-astakos-app/astakos/im/urls.py index 44d5fb9..25c4825 100644 --- a/snf-astakos-app/astakos/im/urls.py +++ b/snf-astakos-app/astakos/im/urls.py @@ -50,6 +50,7 @@ urlpatterns = patterns('astakos.im.views', url(r'^approval_terms/?$', 'approval_terms', {}, name='latest_terms'), url(r'^approval_terms/(?P\d+)/?$', 'approval_terms'), url(r'^password/?$', 'change_password', {}, name='password_change'), + url(r'^send/activation/(?P\d+)/?$', 'send_activation', {}, name='send_activation') ) if EMAILCHANGE_ENABLED: diff --git a/snf-astakos-app/astakos/im/views.py b/snf-astakos-app/astakos/im/views.py index 0b28ceb..12997ae 100644 --- a/snf-astakos-app/astakos/im/views.py +++ b/snf-astakos-app/astakos/im/views.py @@ -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 + ) + ) + -- 1.7.10.4