X-Git-Url: https://code.grnet.gr/git/astakos/blobdiff_plain/d37e4e21f1ee0fcf01ae71a861322b1c3fcdfa86..678b2236de5d9cd11bf4cc65519d57b95ffa053b:/snf-astakos-app/astakos/im/views.py diff --git a/snf-astakos-app/astakos/im/views.py b/snf-astakos-app/astakos/im/views.py index 2fbaf80..86e54a1 100644 --- a/snf-astakos-app/astakos/im/views.py +++ b/snf-astakos-app/astakos/im/views.py @@ -39,7 +39,7 @@ from urllib import quote from functools import wraps from django.core.mail import send_mail -from django.http import HttpResponse +from django.http import HttpResponse, HttpResponseBadRequest from django.shortcuts import redirect from django.template.loader import render_to_string from django.utils.translation import ugettext as _ @@ -47,19 +47,23 @@ from django.core.urlresolvers import reverse from django.contrib.auth.decorators import login_required 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, HttpResponseBadRequest from django.db.utils import IntegrityError from django.contrib.auth.views import password_change +from django.core.exceptions import ValidationError +from django.views.decorators.http import require_http_methods from astakos.im.models import AstakosUser, Invitation, ApprovalTerms from astakos.im.activation_backends import get_backend, SimpleBackend -from astakos.im.util import get_context, prepare_response, set_cookie, has_signed_terms +from astakos.im.util import get_context, prepare_response, set_cookie, get_query from astakos.im.forms import * -from astakos.im.functions import send_greeting, send_feedback, SendMailError -from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, COOKIE_NAME, COOKIE_DOMAIN, IM_MODULES, SITENAME, LOGOUT_NEXT -from astakos.im.functions import invite as invite_func +from astakos.im.functions import (send_greeting, send_feedback, SendMailError, + invite as invite_func, logout as auth_logout, activate as activate_func +) +from astakos.im.settings import (DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, + COOKIE_NAME, COOKIE_DOMAIN, IM_MODULES, SITENAME, LOGOUT_NEXT, LOGGING_LEVEL +) logger = logging.getLogger(__name__) @@ -100,7 +104,7 @@ def signed_terms_required(func): """ @wraps(func) def wrapper(request, *args, **kwargs): - if request.user.is_authenticated() and not has_signed_terms(request.user): + if request.user.is_authenticated() and not request.user.signed_terms(): params = urlencode({'next': request.build_absolute_uri(), 'show_form':''}) terms_uri = reverse('latest_terms') + '?' + params @@ -108,6 +112,7 @@ def signed_terms_required(func): return func(request, *args, **kwargs) return wrapper +@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={}): """ @@ -134,10 +139,14 @@ def index(request, login_template_name='im/login.html', profile_template_name='i template_name = login_template_name if request.user.is_authenticated(): return HttpResponseRedirect(reverse('astakos.im.views.edit_profile')) - return render_response(template_name, - login_form = LoginForm(), - context_instance = get_context(request, extra_context)) + + return render_response( + template_name, + login_form = LoginForm(request=request), + context_instance = get_context(request, extra_context) + ) +@require_http_methods(["GET", "POST"]) @login_required @signed_terms_required @transaction.commit_manually @@ -216,6 +225,7 @@ def invite(request, template_name='im/invitations.html', extra_context={}): invitation_form = form, context_instance = context) +@require_http_methods(["GET", "POST"]) @login_required @signed_terms_required def edit_profile(request, template_name='im/profile.html', extra_context={}): @@ -261,21 +271,25 @@ def edit_profile(request, template_name='im/profile.html', extra_context={}): next = request.POST.get('next') if next: return redirect(next) - msg = _('Profile has been updated successfully') + msg = _('

Profile has been updated successfully

') messages.add_message(request, messages.SUCCESS, msg) except ValueError, ve: messages.add_message(request, messages.ERROR, ve) + elif request.method == "GET": + request.user.is_verified = True + request.user.save() return render_response(template_name, reset_cookie = reset_cookie, profile_form = form, context_instance = get_context(request, 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): """ Allows a user to create a local account. - In case of GET request renders a form for providing the user information. + In case of GET request renders a form for entering the user information. In case of POST handles the signup. The user activation will be delegated to the backend specified by the ``backend`` keyword argument @@ -283,7 +297,7 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple if settings.ASTAKOS_INVITATIONS_ENABLED is True or ``astakos.im.activation_backends.SimpleBackend`` if not (see activation_backends); - Upon successful user creation if ``next`` url parameter is present the user is redirected there + Upon successful user creation, if ``next`` url parameter is present the user is redirected there otherwise renders the same page with a success message. On unsuccessful creation, renders ``template_name`` with an error message. @@ -294,7 +308,6 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple A custom template to render. This is optional; if not specified, this will default to ``im/signup.html``. - ``on_success`` A custom template to render in case of success. This is optional; if not specified, this will default to ``im/signup_complete.html``. @@ -308,15 +321,14 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple im/signup_complete.html or ``on_success`` keyword argument. """ if request.user.is_authenticated(): - return HttpResponseRedirect(reverse('astakos.im.views.index')) + return HttpResponseRedirect(reverse('astakos.im.views.edit_profile')) - query_dict = request.__getattribute__(request.method) - provider = query_dict.get('provider', 'local') + provider = get_query(request).get('provider', 'local') try: if not backend: backend = get_backend(request) form = backend.get_signup_form(provider) - except (Invitation.DoesNotExist, ValueError), e: + except Exception, e: form = SimpleBackend(request).get_signup_form(provider) messages.add_message(request, messages.ERROR, e) if request.method == 'POST': @@ -327,6 +339,12 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple status = messages.SUCCESS message = result.message user.save() + if 'additional_email' in form.cleaned_data: + additional_email = form.cleaned_data['additional_email'] + if additional_email != user.email: + user.additionalmail_set.create(email=additional_email) + msg = 'Additional email: %s saved for user %s.' % (additional_email, user.email) + logger._log(LOGGING_LEVEL, msg, []) if user and user.is_active: next = request.POST.get('next', '') return prepare_response(request, user, next=next) @@ -338,13 +356,17 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple message = e.message messages.add_message(request, status, message) except BaseException, e: + logger.exception(e) status = messages.ERROR message = _('Something went wrong.') messages.add_message(request, status, message) + logger.exception(e) return render_response(template_name, signup_form = form, + provider = provider, context_instance=get_context(request, extra_context)) +@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={}): @@ -382,7 +404,7 @@ def feedback(request, template_name='im/feedback.html', email_template_name='im/ form = FeedbackForm(request.POST) if form.is_valid(): - msg = form.cleaned_data['feedback_msg'], + msg = form.cleaned_data['feedback_msg'] data = form.cleaned_data['feedback_data'] try: send_feedback(msg, data, request.user, email_template_name) @@ -397,13 +419,18 @@ def feedback(request, template_name='im/feedback.html', email_template_name='im/ feedback_form = form, context_instance = get_context(request, extra_context)) +@require_http_methods(["GET", "POST"]) def logout(request, template='registration/logged_out.html', extra_context={}): """ Wraps `django.contrib.auth.logout` and delete the cookie. """ - auth_logout(request) response = HttpResponse() - response.delete_cookie(COOKIE_NAME, path='/', domain=COOKIE_DOMAIN) + if request.user.is_authenticated(): + email = request.user.email + auth_logout(request) + response.delete_cookie(COOKIE_NAME, path='/', domain=COOKIE_DOMAIN) + msg = 'Cookie deleted for %s' % email + logger._log(LOGGING_LEVEL, msg, []) next = request.GET.get('next') if next: response['Location'] = next @@ -413,13 +440,14 @@ def logout(request, template='registration/logged_out.html', extra_context={}): response['Location'] = LOGOUT_NEXT response.status_code = 301 return response - messages.add_message(request, messages.SUCCESS, _('You have successfully logged out.')) + messages.add_message(request, messages.SUCCESS, _('

You have successfully logged out.

')) context = get_context(request, extra_context) response.write(render_to_string(template, context_instance=context)) return response +@require_http_methods(["GET", "POST"]) @transaction.commit_manually -def activate(request, email_template_name='im/welcome_email.txt', on_failure=''): +def activate(request, greeting_email_template_name='im/welcome_email.txt', helpdesk_email_template_name='im/helpdesk_notification.txt'): """ Activates the user identified by the ``auth`` request parameter, sends a welcome email and renews the user token. @@ -433,27 +461,31 @@ def activate(request, email_template_name='im/welcome_email.txt', on_failure='') user = AstakosUser.objects.get(auth_token=token) except AstakosUser.DoesNotExist: return HttpResponseBadRequest(_('No such user')) - - user.is_active = True - user.email_verified = True - user.save() + + if user.is_active: + message = _('Account already active.') + messages.add_message(request, messages.ERROR, message) + return index(request) + try: - send_greeting(user, email_template_name) + activate_func(user, greeting_email_template_name, helpdesk_email_template_name, verify_email=True) response = prepare_response(request, user, next, renew=True) transaction.commit() return response - except SendEmailError, e: + except SendMailError, e: message = e.message messages.add_message(request, messages.ERROR, message) transaction.rollback() - return signup(request, on_failure='im/signup.html') + return index(request) except BaseException, e: status = messages.ERROR message = _('Something went wrong.') + messages.add_message(request, messages.ERROR, message) logger.exception(e) transaction.rollback() - return signup(request, on_failure='im/signup.html') + return index(request) +@require_http_methods(["GET", "POST"]) def approval_terms(request, term_id=None, template_name='im/approval_terms.html', extra_context={}): term = None terms = None @@ -487,13 +519,68 @@ def approval_terms(request, term_id=None, template_name='im/approval_terms.html' return HttpResponseRedirect(next) else: form = None - if request.user.is_authenticated() and not has_signed_terms(request.user): + if request.user.is_authenticated() and not request.user.signed_terms(): form = SignApprovalTermsForm(instance=request.user) return render_response(template_name, terms = terms, approval_terms_form = form, context_instance = get_context(request, extra_context)) +@require_http_methods(["GET", "POST"]) @signed_terms_required def change_password(request): - return password_change(request, post_change_redirect=reverse('astakos.im.views.edit_profile')) + return password_change(request, + post_change_redirect=reverse('astakos.im.views.edit_profile'), + password_change_form=ExtendedPasswordChangeForm) + +@require_http_methods(["GET", "POST"]) +@login_required +@signed_terms_required +@transaction.commit_manually +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={}): + if activation_key: + try: + user = EmailChange.objects.change_email(activation_key) + if request.user.is_authenticated() and request.user == user: + msg = _('Email changed successfully.') + messages.add_message(request, messages.SUCCESS, msg) + auth_logout(request) + response = prepare_response(request, user) + transaction.commit() + return response + except ValueError, e: + messages.add_message(request, messages.ERROR, e) + return render_response(confirm_template_name, + modified_user = user if 'user' in locals() else None, + context_instance = get_context(request, + extra_context)) + + if not request.user.is_authenticated(): + path = quote(request.get_full_path()) + url = request.build_absolute_uri(reverse('astakos.im.views.index')) + return HttpResponseRedirect(url + '?next=' + path) + form = EmailChangeForm(request.POST or None) + if request.method == 'POST' and form.is_valid(): + try: + ec = form.save(email_template_name, request) + except SendMailError, e: + status = messages.ERROR + msg = e + transaction.rollback() + except IntegrityError, e: + status = messages.ERROR + msg = _('There is already a pending change email request.') + else: + status = messages.SUCCESS + msg = _('Change email request has been registered succefully.\ + You are going to receive a verification email in the new address.') + transaction.commit() + messages.add_message(request, status, msg) + return render_response(form_template_name, + form = form, + context_instance = get_context(request, + extra_context))