Revision e7cb4085 snf-astakos-app/astakos/im/views.py

b/snf-astakos-app/astakos/im/views.py
74 74

  
75 75
import astakos.im.messages as astakos_messages
76 76

  
77
from astakos.im.activation_backends import get_backend, SimpleBackend
77
from astakos.im import activation_backends
78 78
from astakos.im import tables
79 79
from astakos.im.models import (
80 80
    AstakosUser, ApprovalTerms,
......
91 91
    ProjectMembersSortForm)
92 92
from astakos.im.forms import ExtendedProfileForm as ProfileForm
93 93
from astakos.im.functions import (
94
    send_feedback, SendMailError,
94
    send_feedback,
95 95
    logout as auth_logout,
96
    activate as activate_func,
97 96
    invite as invite_func,
98
    send_activation as send_activation_func,
99
    SendNotificationError,
100 97
    qh_add_pending_app,
101 98
    accept_membership, reject_membership, remove_membership, cancel_membership,
102
    leave_project, join_project, enroll_member, can_join_request, can_leave_request,
99
    leave_project, join_project, enroll_member, can_join_request,
100
    can_leave_request,
103 101
    get_related_project_id, get_by_chain_or_404,
104 102
    approve_application, deny_application,
105 103
    cancel_application, dismiss_application)
......
110 108
    ACTIVATION_REDIRECT_URL,
111 109
    MODERATION_ENABLED)
112 110
from astakos.im import presentation
113
from astakos.im import settings as astakos_settings
111
from astakos.im import settings
114 112
from astakos.im import auth_providers as auth
115 113
from snf_django.lib.db.transaction import commit_on_success_strict
116 114
from astakos.im.ctx import ExceptionHandler
......
315 313
                    invite_func(inviter, email, realname)
316 314
                    message = _(astakos_messages.INVITATION_SENT) % locals()
317 315
                    messages.success(request, message)
318
                except SendMailError, e:
319
                    message = e.message
320
                    messages.error(request, message)
321
                    transaction.rollback()
322
                except BaseException, e:
323
                    message = _(astakos_messages.GENERIC_ERROR)
324
                    messages.error(request, message)
325
                    logger.exception(e)
316
                except Exception, e:
326 317
                    transaction.rollback()
318
                    raise
327 319
                else:
328 320
                    transaction.commit()
329 321
        else:
......
424 416

  
425 417
    extra_context['services'] = Service.catalog().values()
426 418
    return render_response(template_name,
427
                           profile_form = form,
428
                           user_providers = user_providers,
429
                           user_disabled_providers = user_disabled_providers,
430
                           user_available_providers = user_available_providers,
431
                           context_instance = get_context(request,
419
                           profile_form=form,
420
                           user_providers=user_providers,
421
                           user_disabled_providers=user_disabled_providers,
422
                           user_available_providers=user_available_providers,
423
                           context_instance=get_context(request,
432 424
                                                          extra_context))
433 425

  
434 426

  
435 427
@transaction.commit_manually
436 428
@require_http_methods(["GET", "POST"])
437
def signup(request, template_name='im/signup.html', on_success='index', extra_context=None, backend=None):
429
def signup(request, template_name='im/signup.html', on_success='index',
430
           extra_context=None, activation_backend=None):
438 431
    """
439 432
    Allows a user to create a local account.
440 433

  
441 434
    In case of GET request renders a form for entering the user information.
442 435
    In case of POST handles the signup.
443 436

  
444
    The user activation will be delegated to the backend specified by the ``backend`` keyword argument
445
    if present, otherwise to the ``astakos.im.activation_backends.InvitationBackend``
446
    if settings.ASTAKOS_INVITATIONS_ENABLED is True or ``astakos.im.activation_backends.SimpleBackend`` if not
447
    (see activation_backends);
437
    The user activation will be delegated to the backend specified by the
438
    ``activation_backend`` keyword argument if present, otherwise to the
439
    ``astakos.im.activation_backends.InvitationBackend`` if
440
    settings.ASTAKOS_INVITATIONS_ENABLED is True or
441
    ``astakos.im.activation_backends.SimpleBackend`` if not (see
442
    activation_backends);
448 443

  
449
    Upon successful user creation, if ``next`` url parameter is present the user is redirected there
450
    otherwise renders the same page with a success message.
444
    Upon successful user creation, if ``next`` url parameter is present the
445
    user is redirected there otherwise renders the same page with a success
446
    message.
451 447

  
452 448
    On unsuccessful creation, renders ``template_name`` with an error message.
453 449

  
......
469 465
    """
470 466
    extra_context = extra_context or {}
471 467
    if request.user.is_authenticated():
472
        return HttpResponseRedirect(reverse('edit_profile'))
468
        logger.info("%s already signed in, redirect to index",
469
                    request.user.log_display)
470
        return HttpResponseRedirect(reverse('index'))
473 471

  
474 472
    provider = get_query(request).get('provider', 'local')
475 473
    if not auth.get_provider(provider).get_create_policy:
474
        logger.error("%s provider not available for signup", provider)
476 475
        raise PermissionDenied
477 476

  
478
    id = get_query(request).get('id')
479
    try:
480
        instance = AstakosUser.objects.get(id=id) if id else None
481
    except AstakosUser.DoesNotExist:
482
        instance = None
477
    instance = None
483 478

  
479
    # user registered using third party provider
484 480
    third_party_token = request.REQUEST.get('third_party_token', None)
485 481
    unverified = None
486 482
    if third_party_token:
483
        # retreive third party entry. This was created right after the initial
484
        # third party provider handshake.
487 485
        pending = get_object_or_404(PendingThirdPartyUser,
488 486
                                    token=third_party_token)
489 487

  
490 488
        provider = pending.provider
489

  
490
        # clone third party instance into the corresponding AstakosUser
491 491
        instance = pending.get_user_instance()
492 492
        get_unverified = AstakosUserAuthProvider.objects.unverified
493

  
494
        # check existing unverified entries
493 495
        unverified = get_unverified(pending.provider,
494 496
                                    identifier=pending.third_party_identifier)
495 497

  
496 498
        if unverified and request.method == 'GET':
497 499
            messages.warning(request, unverified.get_pending_registration_msg)
498
            if unverified.user.activation_sent:
500
            if unverified.user.moderated:
499 501
                messages.warning(request,
500 502
                                 unverified.get_pending_resend_activation_msg)
501 503
            else:
502 504
                messages.warning(request,
503 505
                                 unverified.get_pending_moderation_msg)
504 506

  
505
    try:
506
        if not backend:
507
            backend = get_backend(request)
508
        form = backend.get_signup_form(provider, instance)
509
    except Exception, e:
510
        form = SimpleBackend(request).get_signup_form(provider)
511
        messages.error(request, e)
507
    # prepare activation backend based on current request
508
    if not activation_backend:
509
        activation_backend = activation_backends.get_backend()
510

  
511
    form_kwargs = {'instance': instance}
512
    if third_party_token:
513
        form_kwargs['third_party_token'] = third_party_token
514

  
515
    form = activation_backend.get_signup_form(
516
        provider, None, **form_kwargs)
512 517

  
513 518
    if request.method == 'POST':
519
        form = activation_backend.get_signup_form(
520
            provider,
521
            request.POST,
522
            **form_kwargs)
523

  
514 524
        if form.is_valid():
515
            user = form.save(commit=False)
525
            commited = False
526
            try:
527
                user = form.save(commit=False)
516 528

  
517
            # delete previously unverified accounts
518
            if AstakosUser.objects.user_exists(user.email):
519
                AstakosUser.objects.get_by_identifier(user.email).delete()
529
                # delete previously unverified accounts
530
                if AstakosUser.objects.user_exists(user.email):
531
                    AstakosUser.objects.get_by_identifier(user.email).delete()
520 532

  
521
            try:
533
                # store_user so that user auth providers get initialized
522 534
                form.store_user(user, request)
523

  
524
                result = backend.handle_activation(user)
525
                status = messages.SUCCESS
535
                result = activation_backend.handle_registration(user)
536
                if result.status == \
537
                        activation_backend.Result.PENDING_MODERATION:
538
                    # user should be warned that his account is not active yet
539
                    status = messages.WARNING
540
                else:
541
                    status = messages.SUCCESS
526 542
                message = result.message
543
                activation_backend.send_result_notifications(result, user)
527 544

  
528
                if 'additional_email' in form.cleaned_data:
529
                    additional_email = form.cleaned_data['additional_email']
530
                    if additional_email != user.email:
531
                        user.additionalmail_set.create(email=additional_email)
532
                        msg = 'Additional email: %s saved for user %s.' % (
533
                            additional_email,
534
                            user.email
535
                        )
536
                        logger._log(LOGGING_LEVEL, msg, [])
545
                # commit user entry
546
                transaction.commit()
547
                # commited flag
548
                # in case an exception get raised from this point
549
                commited = True
537 550

  
538 551
                if user and user.is_active:
552
                    # activation backend directly activated the user
553
                    # log him in
539 554
                    next = request.POST.get('next', '')
540 555
                    response = prepare_response(request, user, next=next)
541
                    transaction.commit()
542 556
                    return response
543 557

  
544
                transaction.commit()
545 558
                messages.add_message(request, status, message)
546 559
                return HttpResponseRedirect(reverse(on_success))
547

  
548
            except SendMailError, e:
549
                status = messages.ERROR
550
                message = e.message
551
                messages.error(request, message)
552
                transaction.rollback()
553
            except BaseException, e:
554
                logger.exception(e)
555
                message = _(astakos_messages.GENERIC_ERROR)
556
                messages.error(request, message)
557
                logger.exception(e)
558
                transaction.rollback()
560
            except Exception, e:
561
                if not commited:
562
                    transaction.rollback()
563
                raise
559 564

  
560 565
    return render_response(template_name,
561 566
                           signup_form=form,
......
605 610
        if form.is_valid():
606 611
            msg = form.cleaned_data['feedback_msg']
607 612
            data = form.cleaned_data['feedback_data']
608
            try:
609
                send_feedback(msg, data, request.user, email_template_name)
610
            except SendMailError, e:
611
                message = e.message
612
                messages.error(request, message)
613
            else:
614
                message = _(astakos_messages.FEEDBACK_SENT)
615
                messages.success(request, message)
613
            send_feedback(msg, data, request.user, email_template_name)
614
            message = _(astakos_messages.FEEDBACK_SENT)
615
            messages.success(request, message)
616 616
            return HttpResponseRedirect(reverse('feedback'))
617

  
617 618
    return render_response(template_name,
618 619
                           feedback_form=form,
619
                           context_instance=get_context(request, extra_context))
620
                           context_instance=get_context(request,
621
                                                        extra_context))
620 622

  
621 623

  
622 624
@require_http_methods(["GET"])
623
@signed_terms_required
624
def logout(request, template='registration/logged_out.html', extra_context=None):
625
def logout(request, template='registration/logged_out.html',
626
           extra_context=None):
625 627
    """
626 628
    Wraps `django.contrib.auth.logout`.
627 629
    """
......
664 666
def activate(request, greeting_email_template_name='im/welcome_email.txt',
665 667
             helpdesk_email_template_name='im/helpdesk_notification.txt'):
666 668
    """
667
    Activates the user identified by the ``auth`` request parameter, sends a welcome email
668
    and renews the user token.
669
    Activates the user identified by the ``auth`` request parameter, sends a
670
    welcome email and renews the user token.
669 671

  
670
    The view uses commit_manually decorator in order to ensure the user state will be updated
671
    only if the email will be send successfully.
672
    The view uses commit_manually decorator in order to ensure the user state
673
    will be updated only if the email will be send successfully.
672 674
    """
673 675
    token = request.GET.get('auth')
674 676
    next = request.GET.get('next')
675
    try:
676
        user = AstakosUser.objects.get(auth_token=token)
677
    except AstakosUser.DoesNotExist:
678
        return HttpResponseBadRequest(_(astakos_messages.ACCOUNT_UNKNOWN))
679 677

  
680
    if user.is_active or user.email_verified:
681
        message = _(astakos_messages.ACCOUNT_ALREADY_ACTIVE)
678
    if request.user.is_authenticated():
679
        message = _(astakos_messages.LOGGED_IN_WARNING)
682 680
        messages.error(request, message)
683 681
        return HttpResponseRedirect(reverse('index'))
684 682

  
685
    if not user.activation_sent:
686
        provider = user.get_auth_provider()
687
        message = user.get_inactive_message(provider.module)
683
    try:
684
        user = AstakosUser.objects.get(verification_code=token)
685
    except AstakosUser.DoesNotExist:
686
        raise Http404
687

  
688
    if user.email_verified:
689
        message = _(astakos_messages.ACCOUNT_ALREADY_VERIFIED)
688 690
        messages.error(request, message)
689 691
        return HttpResponseRedirect(reverse('index'))
690 692

  
691 693
    try:
692
        activate_func(user, greeting_email_template_name,
693
                      helpdesk_email_template_name, verify_email=True)
694
        messages.success(request, _(astakos_messages.ACCOUNT_ACTIVATED))
694
        backend = activation_backends.get_backend()
695
        result = backend.handle_verification(user, token)
696
        backend.send_result_notifications(result, user)
695 697
        next = ACTIVATION_REDIRECT_URL or next
696
        response = prepare_response(request, user, next, renew=True)
698
        response = HttpResponseRedirect(reverse('index'))
699
        if user.is_active:
700
            response = prepare_response(request, user, next, renew=True)
701
            messages.success(request, _(result.message))
702
        else:
703
            messages.warning(request, _(result.message))
704
    except Exception:
705
        transaction.rollback()
706
        raise
707
    else:
697 708
        transaction.commit()
698 709
        return response
699
    except SendMailError, e:
700
        message = e.message
701
        messages.add_message(request, messages.ERROR, message)
702
        transaction.rollback()
703
        return index(request)
704
    except BaseException, e:
705
        status = messages.ERROR
706
        message = _(astakos_messages.GENERIC_ERROR)
707
        messages.add_message(request, messages.ERROR, message)
708
        logger.exception(e)
709
        transaction.rollback()
710
        return index(request)
711 710

  
712 711

  
713 712
@require_http_methods(["GET", "POST"])
714
def approval_terms(request, term_id=None, template_name='im/approval_terms.html', extra_context=None):
713
def approval_terms(request, term_id=None,
714
                   template_name='im/approval_terms.html', extra_context=None):
715 715
    extra_context = extra_context or {}
716 716
    term = None
717 717
    terms = None
......
734 734
    except IOError:
735 735
        messages.error(request, _(astakos_messages.GENERIC_ERROR))
736 736
        return render_response(
737
            template_name, context_instance=get_context(request, extra_context))
737
            template_name, context_instance=get_context(request,
738
                                                        extra_context))
738 739

  
739 740
    terms = f.read()
740 741

  
......
750 751
            return render_response(template_name,
751 752
                                   terms=terms,
752 753
                                   approval_terms_form=form,
753
                                   context_instance=get_context(request, extra_context))
754
                                   context_instance=get_context(request,
755
                                                                extra_context))
754 756
        user = form.save()
755 757
        return HttpResponseRedirect(next)
756 758
    else:
......
760 762
        return render_response(template_name,
761 763
                               terms=terms,
762 764
                               approval_terms_form=form,
763
                               context_instance=get_context(request, extra_context))
765
                               context_instance=get_context(request,
766
                                                            extra_context))
764 767

  
765 768

  
766 769
@require_http_methods(["GET", "POST"])
......
772 775
                 extra_context=None):
773 776
    extra_context = extra_context or {}
774 777

  
775

  
776
    if not astakos_settings.EMAILCHANGE_ENABLED:
778
    if not settings.EMAILCHANGE_ENABLED:
777 779
        raise PermissionDenied
778 780

  
779 781
    if activation_key:
780 782
        try:
781 783
            user = EmailChange.objects.change_email(activation_key)
782
            if request.user.is_authenticated() and request.user == user or not \
784
            if request.user.is_authenticated() and \
785
                request.user == user or not \
783 786
                    request.user.is_authenticated():
784 787
                msg = _(astakos_messages.EMAIL_CHANGED)
785 788
                messages.success(request, msg)
......
791 794
            return HttpResponseRedirect(reverse('index'))
792 795

  
793 796
        return render_response(confirm_template_name,
794
                               modified_user=user if 'user' in locals() \
797
                               modified_user=user if 'user' in locals()
795 798
                               else None, context_instance=get_context(request,
796
                                                            extra_context))
799
                               extra_context))
797 800

  
798 801
    if not request.user.is_authenticated():
799 802
        path = quote(request.get_full_path())
......
812 815
    if request.method == 'POST' and form.is_valid():
813 816
        try:
814 817
            ec = form.save(request, email_template_name, request)
815
        except SendMailError, e:
816
            msg = e
817
            messages.error(request, msg)
818
        except Exception, e:
818 819
            transaction.rollback()
819
            return HttpResponseRedirect(reverse('edit_profile'))
820
            raise
820 821
        else:
821 822
            msg = _(astakos_messages.EMAIL_CHANGE_REGISTERED)
822 823
            messages.success(request, msg)
......
833 834
    )
834 835

  
835 836

  
836
def send_activation(request, user_id, template_name='im/login.html', extra_context=None):
837
def send_activation(request, user_id, template_name='im/login.html',
838
                    extra_context=None):
837 839

  
838 840
    if request.user.is_authenticated():
839
        return HttpResponseRedirect(reverse('edit_profile'))
841
        return HttpResponseRedirect(reverse('index'))
840 842

  
841 843
    extra_context = extra_context or {}
842 844
    try:
......
844 846
    except AstakosUser.DoesNotExist:
845 847
        messages.error(request, _(astakos_messages.ACCOUNT_UNKNOWN))
846 848
    else:
847
        if not u.activation_sent and astakos_settings.MODERATION_ENABLED:
848
            raise PermissionDenied
849
        try:
850
            send_activation_func(u)
851
            msg = _(astakos_messages.ACTIVATION_SENT)
852
            messages.success(request, msg)
853
        except SendMailError, e:
854
            messages.error(request, e)
849
        if u.email_verified:
850
            logger.warning("[resend activation] Account already verified: %s",
851
                           u.log_display)
852

  
853
            messages.error(request,
854
                           _(astakos_messages.ACCOUNT_ALREADY_VERIFIED))
855
        else:
856
            activation_backend = activation_backends.get_backend()
857
            activation_backend.send_user_verification_email(u)
858
            messages.success(request, astakos_messages.ACTIVATION_SENT)
855 859

  
856 860
    return HttpResponseRedirect(reverse('index'))
857 861

  
......
881 885
                           resource_groups=resource_groups,
882 886
                           resources_order=resources_order,
883 887
                           current_usage=current_usage,
884
                           token_cookie_name=astakos_settings.COOKIE_NAME,
888
                           token_cookie_name=settings.COOKIE_NAME,
885 889
                           usage_update_interval=
886
                           astakos_settings.USAGE_UPDATE_INTERVAL)
890
                           settings.USAGE_UPDATE_INTERVAL)
887 891

  
888 892

  
889 893
# TODO: action only on POST and user should confirm the removal

Also available in: Unified diff