X-Git-Url: https://git.openstreetmap.org./osqa.git/blobdiff_plain/1a949f7c97dc2f34c135f5cdf088df2927d3d652..174c53e97bcf1e5412c141829d152aa5a2b8684c:/forum/views/auth.py diff --git a/forum/views/auth.py b/forum/views/auth.py index 9dafc41..27cf5c9 100644 --- a/forum/views/auth.py +++ b/forum/views/auth.py @@ -2,24 +2,27 @@ from django.shortcuts import render_to_response, get_object_or_404 from django.template import RequestContext from django.core.urlresolvers import reverse from forum.models import User -from django.http import HttpResponseRedirect, Http404 +from django.http import HttpResponseRedirect, Http404, HttpResponseForbidden from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ from django.utils.http import urlquote_plus from django.contrib.auth.decorators import login_required -from django.contrib.auth import login, logout +from django.contrib.auth import login, logout from django.http import get_host +from forum.actions import SuspendAction import types import datetime +import logging -from forum.authentication.forms import SimpleRegistrationForm, SimpleEmailSubscribeForm, \ +from forum.forms import SimpleRegistrationForm, SimpleEmailSubscribeForm, \ TemporaryLoginRequestForm, ChangePasswordForm, SetPasswordForm -from forum.utils.mail import send_email +from forum.utils.mail import send_email, send_template_email from forum.authentication.base import InvalidAuthentication -from forum.authentication import AUTH_PROVIDERS, user_logged_in +from forum.authentication import AUTH_PROVIDERS from forum.models import AuthKeyUserAssociation, ValidationHash, Question, Answer +from forum.actions import UserJoinsAction def signin_page(request, action=None): if action is None: @@ -34,19 +37,19 @@ def signin_page(request, action=None): can_show = lambda c: not request.user.is_authenticated() or c.show_to_logged_in_user bigicon_providers = sorted([ - context for context in all_providers if context.mode == 'BIGICON' and can_show(context) + context for context in all_providers if context.mode == 'BIGICON' and can_show(context) ], sort) smallicon_providers = sorted([ - context for context in all_providers if context.mode == 'SMALLICON' and can_show(context) + context for context in all_providers if context.mode == 'SMALLICON' and can_show(context) ], sort) top_stackitem_providers = sorted([ - context for context in all_providers if context.mode == 'TOP_STACK_ITEM' and can_show(context) + context for context in all_providers if context.mode == 'TOP_STACK_ITEM' and can_show(context) ], sort) stackitem_providers = sorted([ - context for context in all_providers if context.mode == 'STACK_ITEM' and can_show(context) + context for context in all_providers if context.mode == 'STACK_ITEM' and can_show(context) ], sort) try: @@ -58,25 +61,26 @@ def signin_page(request, action=None): return render_to_response( 'auth/signin.html', { - 'msg': msg, - 'all_providers': all_providers, - 'bigicon_providers': bigicon_providers, - 'top_stackitem_providers': top_stackitem_providers, - 'stackitem_providers': stackitem_providers, - 'smallicon_providers': smallicon_providers, + 'msg': msg, + 'all_providers': all_providers, + 'bigicon_providers': bigicon_providers, + 'top_stackitem_providers': top_stackitem_providers, + 'stackitem_providers': stackitem_providers, + 'smallicon_providers': smallicon_providers, }, RequestContext(request)) def prepare_provider_signin(request, provider): force_email_request = request.REQUEST.get('validate_email', 'yes') == 'yes' request.session['force_email_request'] = force_email_request - + if provider in AUTH_PROVIDERS: provider_class = AUTH_PROVIDERS[provider].consumer try: request_url = provider_class.prepare_authentication_request(request, - reverse('auth_provider_done', kwargs={'provider': provider})) + reverse('auth_provider_done', + kwargs={'provider': provider})) return HttpResponseRedirect(request_url) except NotImplementedError, e: @@ -84,7 +88,9 @@ def prepare_provider_signin(request, provider): except InvalidAuthentication, e: request.session['auth_error'] = e.message - return HttpResponseRedirect(reverse('auth_signin')) + return HttpResponseRedirect(reverse('auth_signin')) + else: + raise Http404() def process_provider_signin(request, provider): @@ -100,26 +106,32 @@ def process_provider_signin(request, provider): if request.user.is_authenticated(): if isinstance(assoc_key, (type, User)): if request.user != assoc_key: - request.session['auth_error'] = _("Sorry, these login credentials belong to anoother user. Plese terminate your current session and try again.") + request.session['auth_error'] = _( + "Sorry, these login credentials belong to anoother user. Plese terminate your current session and try again." + ) else: request.session['auth_error'] = _("You are already logged in with that user.") else: try: assoc = AuthKeyUserAssociation.objects.get(key=assoc_key) if assoc.user == request.user: - request.session['auth_error'] = _("These login credentials are already associated with your account.") + request.session['auth_error'] = _( + "These login credentials are already associated with your account.") else: - request.session['auth_error'] = _("Sorry, these login credentials belong to anoother user. Plese terminate your current session and try again.") + request.session['auth_error'] = _( + "Sorry, these login credentials belong to anoother user. Plese terminate your current session and try again." + ) except: uassoc = AuthKeyUserAssociation(user=request.user, key=assoc_key, provider=provider) uassoc.save() - request.user.message_set.create(message=_('The new credentials are now associated with your account')) - return HttpResponseRedirect(reverse('user_authsettings')) + request.user.message_set.create( + message=_('The new credentials are now associated with your account')) + return HttpResponseRedirect(reverse('user_authsettings', args=[request.user.id])) return HttpResponseRedirect(reverse('auth_signin')) else: if isinstance(assoc_key, User): - return login_and_forward(request, assoc_key) + return login_and_forward(request, assoc_key) try: assoc = AuthKeyUserAssociation.objects.get(key=assoc_key) @@ -144,20 +156,23 @@ def external_register(request): if User.objects.all().count() == 0: user_.is_superuser = True - - user_.save() + user_.is_staff = True - if not user_.email_isvalid: - send_validation_email(user_) + user_.save() + UserJoinsAction(user=user_, ip=request.META['REMOTE_ADDR']).save() try: assoc_key = request.session['assoc_key'] auth_provider = request.session['auth_provider'] except: - request.session['auth_error'] = _("Oops, something went wrong in the middle of this process. Please try again.") - return HttpResponseRedirect(request.session.get('on_signin_url', reverse('auth_signin'))) - - uassoc = AuthKeyUserAssociation(user=user_, key=request.session['assoc_key'], provider=request.session['auth_provider']) + request.session['auth_error'] = _( + "Oops, something went wrong in the middle of this process. Please try again. Note that you need to have cookies enabled for the authentication to work." + ) + logging.error("Missing session data when trying to complete user registration: %s" % ", ".join( + ["%s: %s" % (k, v) for k, v in request.META.items()])) + return HttpResponseRedirect(reverse('auth_signin')) + + uassoc = AuthKeyUserAssociation(user=user_, key=assoc_key, provider=auth_provider) uassoc.save() if email_feeds_form.cleaned_data['subscribe'] == 'n': @@ -167,38 +182,43 @@ def external_register(request): del request.session['assoc_key'] del request.session['auth_provider'] - if user_.email_isvalid: - return login_and_forward(request, user_) - else: - return HttpResponseRedirect(reverse('index')) + return login_and_forward(request, user_, message=_("A welcome email has been sent to your email address. ")) else: - provider_class = AUTH_PROVIDERS[request.session['auth_provider']].consumer + auth_provider = request.session.get('auth_provider', None) + if not auth_provider: + request.session['auth_error'] = _( + "Oops, something went wrong in the middle of this process. Please try again.") + logging.error("Missing session data when trying to complete user registration: %s" % ", ".join( + ["%s: %s" % (k, v) for k, v in request.META.items()])) + return HttpResponseRedirect(reverse('auth_signin')) + + provider_class = AUTH_PROVIDERS[auth_provider].consumer user_data = provider_class.get_user_data(request.session['assoc_key']) + if not user_data: + user_data = request.session.get('auth_consumer_data', {}) + username = user_data.get('username', '') email = user_data.get('email', '') - if not email: - email = request.session.get('auth_email_request', '') - if email: request.session['auth_validated_email'] = email form1 = SimpleRegistrationForm(initial={ - 'next': '/', - 'username': username, - 'email': email, + 'next': '/', + 'username': username, + 'email': email, }) email_feeds_form = SimpleEmailSubscribeForm() provider_context = AUTH_PROVIDERS[request.session['auth_provider']].context return render_to_response('auth/complete.html', { - 'form1': form1, - 'email_feeds_form': email_feeds_form, - 'provider':mark_safe(provider_context.human_name), - 'login_type':provider_context.id, - 'gravatar_faq_url':reverse('faq') + '#gravatar', + 'form1': form1, + 'email_feeds_form': email_feeds_form, + 'provider':mark_safe(provider_context.human_name), + 'login_type':provider_context.id, + 'gravatar_faq_url':reverse('faq') + '#gravatar', }, context_instance=RequestContext(request)) def request_temp_login(request): @@ -208,6 +228,9 @@ def request_temp_login(request): if form.is_valid(): user = form.user_cache + if user.is_suspended(): + return forward_suspended_user(request, user, False) + try: hash = get_object_or_404(ValidationHash, user=user, type='templogin') if hash.expiration < datetime.datetime.now(): @@ -216,10 +239,7 @@ def request_temp_login(request): except: hash = ValidationHash.objects.create_new(user, 'templogin', [user.id]) - send_email(_("Temporary login link"), [(user.username, user.email)], "auth/temp_login_email.html", { - 'temp_login_code': hash, - 'user': user - }) + send_template_email([user], "auth/temp_login_email.html", {'temp_login_code': hash}) request.user.message_set.create(message=_("An email has been sent with your temporary login key")) @@ -228,65 +248,61 @@ def request_temp_login(request): form = TemporaryLoginRequestForm() return render_to_response( - 'auth/temp_login_request.html', {'form': form}, + 'auth/temp_login_request.html', {'form': form}, context_instance=RequestContext(request)) def temp_signin(request, user, code): user = get_object_or_404(User, id=user) if (ValidationHash.objects.validate(code, user, 'templogin', [user.id])): - return login_and_forward(request, user, reverse('user_authsettings'), - _("You are logged in with a temporary access key, please take the time to fix your issue with authentication.")) + return login_and_forward(request, user, reverse('user_authsettings', kwargs={'id': user.id}), + _( + "You are logged in with a temporary access key, please take the time to fix your issue with authentication." + )) else: raise Http404() -def send_validation_email(user): - hash = ValidationHash.objects.create_new(user, 'email', [user.email]) - send_email(_("Email Validation"), [(user.username, user.email)], "auth/email_validation.html", { - 'validation_code': hash, - 'user': user - }) - def validate_email(request, user, code): user = get_object_or_404(User, id=user) if (ValidationHash.objects.validate(code, user, 'email', [user.email])): user.email_isvalid = True user.save() - return login_and_forward(request, user, None, _("Thank you, your email is now validated.")) + return login_and_forward(request, user, None, _("Thank you, your email is now validated.")) else: raise Http404() @login_required -def auth_settings(request): - """ - change password view. - - url : /changepw/ - template: authopenid/changepw.html - """ - user_ = request.user +def auth_settings(request, id): + user_ = get_object_or_404(User, id=id) + + if not (request.user.is_superuser or request.user == user_): + return HttpResponseForbidden() + auth_keys = user_.auth_keys.all() - if user_.has_usable_password(): - FormClass = ChangePasswordForm - else: + if request.user.is_superuser or (not user_.has_usable_password()): FormClass = SetPasswordForm + else: + FormClass = ChangePasswordForm if request.POST: form = FormClass(request.POST, user=user_) if form.is_valid(): - if user_.has_usable_password(): - request.user.message_set.create(message=_("Your password was changed")) - else: - request.user.message_set.create(message=_("New password set")) - FormClass = ChangePasswordForm - + is_new_pass = not user_.has_usable_password() user_.set_password(form.cleaned_data['password1']) user_.save() - return HttpResponseRedirect(reverse('user_authsettings')) - - form = FormClass(user=user_) + + if is_new_pass: + request.user.message_set.create(message=_("New password set")) + if not request.user.is_superuser: + form = ChangePasswordForm(user=user_) + else: + request.user.message_set.create(message=_("Your password was changed")) + + return HttpResponseRedirect(reverse('user_authsettings', kwargs={'id': user_.id})) + else: + form = FormClass(user=user_) auth_keys_list = [] @@ -300,21 +316,26 @@ def auth_settings(request): "unknown: %s" % ConsumerTemplateContext.readable_key(k) auth_keys_list.append({ - 'name': name, - 'id': k.id + 'name': name, + 'id': k.id }) return render_to_response('auth/auth_settings.html', { - 'form': form, - 'has_password': user_.has_usable_password(), - 'auth_keys': auth_keys_list, + 'view_user': user_, + "can_view_private": (user_ == request.user) or request.user.is_superuser, + 'form': form, + 'has_password': user_.has_usable_password(), + 'auth_keys': auth_keys_list, }, context_instance=RequestContext(request)) def remove_external_provider(request, id): association = get_object_or_404(AuthKeyUserAssociation, id=id) + if not (request.user.is_superuser or request.user == association.user): + return HttpResponseForbidden() + request.user.message_set.create(message=_("You removed the association with %s") % association.provider) association.delete() - return HttpResponseRedirect(reverse('user_authsettings')) + return HttpResponseRedirect(reverse('user_authsettings', kwargs={'id': association.user.id})) def newquestion_signin_action(user): question = Question.objects.filter(author=user).order_by('-added_at')[0] @@ -325,16 +346,28 @@ def newanswer_signin_action(user): return answer.get_absolute_url() POST_SIGNIN_ACTIONS = { - 'newquestion': newquestion_signin_action, - 'newanswer': newanswer_signin_action, +'newquestion': newquestion_signin_action, +'newanswer': newanswer_signin_action, } -def login_and_forward(request, user, forward=None, message=None): - old_session = request.session.session_key +def login_and_forward(request, user, forward=None, message=None): + if user.is_suspended(): + return forward_suspended_user(request, user) + user.backend = "django.contrib.auth.backends.ModelBackend" - login(request, user) + login(request, user) + + temp_data = request.session.pop('temp_node_data', None) + if temp_data: + request.POST = temp_data + node_type = request.session.pop('temp_node_type') - user_logged_in.send(user=user,old_session=old_session,sender=None) + if node_type == "question": + from forum.views.writers import ask + return ask(request) + elif node_type == "answer": + from forum.views.writers import answer + return answer(request, request.session.pop('temp_question_id')) if not forward: signin_action = request.session.get('on_signin_action', None) @@ -355,13 +388,21 @@ def login_and_forward(request, user, forward=None, message=None): request.user.message_set.create(message=message) return HttpResponseRedirect(forward) -@login_required -def signout(request): - """ - signout from the website. Remove openid from session and kill it. +def forward_suspended_user(request, user, show_private_msg=True): + message = _("Sorry, but this account is suspended") + if show_private_msg: + msg_type = 'privatemsg' + else: + msg_type = 'publicmsg' + + suspension = user.suspension + if suspension: + message += (":
" + suspension.extra.get(msg_type, '')) - url : /signout/" - """ + request.user.message_set.create(message) + return HttpResponseRedirect(reverse('index')) +@login_required +def signout(request): logout(request) return HttpResponseRedirect(reverse('index')) \ No newline at end of file