Revision 8fb8d0cf

b/snf-astakos-app/astakos/api/quotas.py
49 49
from .util import (json_response, is_integer, are_integer,
50 50
                   user_from_token, component_from_token)
51 51

  
52

  
52 53
@api.api_method(http_method='GET', token_required=True, user_required=False)
53 54
@user_from_token
54 55
def quotas(request):
b/snf-astakos-app/astakos/im/activation_backends.py
387 387
        if result.status == self.Result.PENDING_MODERATION:
388 388
            logger.info("Sending notifications for user"
389 389
                        " verification: %s", user.log_display)
390
            functions.send_account_pending_moderation_notification(user,
391
                                        self.pending_moderation_template_name)
390
            functions.send_account_pending_moderation_notification(
391
                user,
392
                self.pending_moderation_template_name)
392 393
            # TODO: notify user
393 394

  
394 395
        if result.status == self.Result.ACCEPTED:
395 396
            logger.info("Sending notifications for user"
396 397
                        " moderation: %s", user.log_display)
397
            functions.send_account_activated_notification(user,
398
                                         self.activated_email_template_name)
398
            functions.send_account_activated_notification(
399
                user,
400
                self.activated_email_template_name)
399 401
            functions.send_greeting(user,
400 402
                                    self.greeting_template_name)
401 403
            # TODO: notify admins
b/snf-astakos-app/astakos/im/auth_backends.py
48 48
    def authenticate(self, email=None, auth_token=None):
49 49
        try:
50 50
            user = AstakosUser.objects.get_by_identifier(email, is_active=True,
51
                                                        auth_token=auth_token)
51
                                                         auth_token=auth_token)
52 52
            return user
53 53
        except AstakosUser.DoesNotExist:
54 54
            return None
......
65 65

  
66 66
class EmailBackend(ModelBackend):
67 67
    """
68
    If the ``username`` parameter is actually an email uses email to authenticate
69
    the user else tries the username.
68
    If the ``username`` parameter is actually an email uses email to
69
    authenticate the user else tries the username.
70 70

  
71 71
    Used from ``astakos.im.forms.LoginForm`` to authenticate.
72 72
    """
......
83 83
            msg = 'Invalid password during authentication for %s' % username
84 84
            logger._log(settings.LOGGING_LEVEL, msg, [])
85 85

  
86

  
87 86
    def get_user(self, user_id):
88 87
        try:
89 88
            return AstakosUser.objects.get(pk=user_id)
b/snf-astakos-app/astakos/im/auth_providers.py
286 286
                    self.provider_details['info'] = \
287 287
                        json.loads(self.provider_details['info'])
288 288
                for key, val in self.provider_details['info'].iteritems():
289
                   params['provider_info_%s' % key.lower()] = val
289
                    params['provider_info_%s' % key.lower()] = val
290 290

  
291 291
        # resolve username, handle unexisting defined username key
292 292
        if self.user and self.username_key in params:
......
440 440
            })
441 441
        if self.identifier and self._instance:
442 442
            urls.update({
443
                'switch': reverse(self.login_view) + '?switch_from=%d' % \
444
                    self._instance.pk,
443
                'switch': reverse(self.login_view) + '?switch_from=%d' %
444
                self._instance.pk,
445 445
                'remove': reverse('remove_auth_provider',
446 446
                                  kwargs={'pk': self._instance.pk})
447 447
            })
b/snf-astakos-app/astakos/im/context_processors.py
49 49
def im_modules(request):
50 50
    return {'im_modules': settings.IM_MODULES}
51 51

  
52

  
52 53
def auth_providers(request):
53 54
    active_auth_providers = []
54 55
    for module in settings.IM_MODULES:
......
59 60
    return {'auth_providers': active_auth_providers,
60 61
            'master_auth_provider': active_auth_providers[0]}
61 62

  
63

  
62 64
def next(request):
63 65
    return {'next': get_query(request).get('next', '')}
64 66

  
......
66 68
def code(request):
67 69
    return {'code': request.GET.get('code', '')}
68 70

  
71

  
69 72
def last_login_method(request):
70
    return {'last_login_method': request.COOKIES.get('astakos_last_login_method', None)}
73
    return {'last_login_method':
74
            request.COOKIES.get('astakos_last_login_method', None)}
75

  
71 76

  
72 77
def invitations(request):
73 78
    return {'invitations_enabled': settings.INVITATIONS_ENABLED}
......
112 117
    else:
113 118
        return {'menu': menu_items}
114 119

  
120

  
115 121
def membership_policies(request):
116 122
    return {'join_policies': presentation.PROJECT_MEMBER_JOIN_POLICIES,
117 123
            'leave_policies': presentation.PROJECT_MEMBER_LEAVE_POLICIES}
118

  
b/snf-astakos-app/astakos/im/cookie.py
67 67

  
68 68
    @property
69 69
    def is_valid(self):
70
        cookie_attribute = 'uuid' if not settings.TRANSLATE_UUIDS else 'username'
70
        cookie_attribute = ('uuid' if not settings.TRANSLATE_UUIDS
71
                            else 'username')
71 72
        return (self.uuid == getattr(self.user, cookie_attribute, '') and
72 73
                self.auth_token == getattr(self.user, 'auth_token', ''))
73 74

  
......
86 87
        else:
87 88
            cookie_value = quote(user.uuid + '|' + user.auth_token)
88 89
        self.response.set_cookie(
89
            settings.COOKIE_NAME, value=cookie_value, expires=expire_fmt, path='/',
90
            settings.COOKIE_NAME, value=cookie_value, expires=expire_fmt,
91
            path='/',
90 92
            domain=settings.COOKIE_DOMAIN, secure=settings.COOKIE_SECURE
91 93
        )
92 94
        msg = str(('Cookie [expiring %(auth_token_expires)s]',
b/snf-astakos-app/astakos/im/forms.py
323 323
            self.fields[f].widget.attrs['readonly'] = True
324 324

  
325 325
    def save(self, commit=True):
326
        user = super(InvitedThirdPartyUserCreationForm, self).save(commit=False)
326
        user = super(
327
            InvitedThirdPartyUserCreationForm, self).save(commit=False)
327 328
        user.set_invitation_level()
328 329
        user.email_verified = True
329 330
        if commit:
......
340 341
        # copy email value to additional_mail in case user will change it
341 342
        name = 'email'
342 343
        field = self.fields[name]
343
        self.initial['additional_email'] = self.initial.get(name, field.initial)
344
        self.initial['additional_email'] = self.initial.get(
345
            name, field.initial)
344 346
        self.initial['email'] = None
345 347

  
346 348

  
......
359 361
        was_limited = kwargs.get('was_limited', False)
360 362
        request = kwargs.get('request', None)
361 363
        if request:
362
            self.ip = request.META.get('REMOTE_ADDR',
363
                                       request.META.get('HTTP_X_REAL_IP', None))
364
            self.ip = request.META.get(
365
                'REMOTE_ADDR',
366
                request.META.get('HTTP_X_REAL_IP', None))
364 367

  
365 368
        t = ('request', 'was_limited')
366 369
        for elem in t:
......
431 434
    Most of the fields are readonly since the user is not allowed to change
432 435
    them.
433 436

  
434
    The class defines a save method which sets ``is_verified`` to True so as the
435
    user during the next login will not to be redirected to profile page.
437
    The class defines a save method which sets ``is_verified`` to True so as
438
    the user during the next login will not to be redirected to profile page.
436 439
    """
437
    email = forms.EmailField(label='E-mail address', help_text='E-mail address')
440
    email = forms.EmailField(label='E-mail address',
441
                             help_text='E-mail address')
438 442
    renew = forms.BooleanField(label='Renew token', required=False)
439 443

  
440 444
    class Meta:
......
466 470
        return user
467 471

  
468 472

  
469

  
470 473
class FeedbackForm(forms.Form):
471 474
    """
472 475
    Form for writing feedback.
......
517 520
            raise forms.ValidationError(_(astakos_messages.EMAIL_UNKNOWN))
518 521
        return email
519 522

  
520
    def save(
521
        self, domain_override=None, email_template_name='registration/password_reset_email.html',
522
            use_https=False, token_generator=default_token_generator, request=None):
523
    def save(self, domain_override=None,
524
             email_template_name='registration/password_reset_email.html',
525
             use_https=False, token_generator=default_token_generator,
526
             request=None):
523 527
        """
524
        Generates a one-use only link for resetting password and sends to the user.
528
        Generates a one-use only link for resetting password and sends to the
529
        user.
525 530
        """
526 531
        for user in self.users_cache:
527 532
            url = user.astakosuser.get_password_reset_url(token_generator)
......
555 560
            raise forms.ValidationError(_(astakos_messages.EMAIL_USED))
556 561
        return addr
557 562

  
558
    def save(self, request, email_template_name='registration/email_change_email.txt', commit=True):
563
    def save(self, request,
564
             email_template_name='registration/email_change_email.txt',
565
             commit=True):
559 566
        ec = super(EmailChangeForm, self).save(commit=False)
560 567
        ec.user = request.user
561 568
        # delete pending email changes
......
607 614
        username = self.cleaned_data['username']
608 615
        try:
609 616
            Invitation.objects.get(username=username)
610
            raise forms.ValidationError(_(astakos_messages.INVITATION_EMAIL_EXISTS))
617
            raise forms.ValidationError(
618
                _(astakos_messages.INVITATION_EMAIL_EXISTS))
611 619
        except Invitation.DoesNotExist:
612 620
            pass
613 621
        return username
......
619 627
    to optionally renew also the token.
620 628
    """
621 629
    if not settings.NEWPASSWD_INVALIDATE_TOKEN:
622
        renew = forms.BooleanField(label='Renew token', required=False,
623
                                   initial=True,
624
                                   help_text='Unsetting this may result in security risk.')
630
        renew = forms.BooleanField(
631
            label='Renew token', required=False,
632
            initial=True,
633
            help_text='Unsetting this may result in security risk.')
625 634

  
626 635
    def __init__(self, user, *args, **kwargs):
627 636
        self.session_key = kwargs.pop('session_key', None)
......
638 647
            pass
639 648
        return super(ExtendedPasswordChangeForm, self).save(commit=commit)
640 649

  
650

  
641 651
class ExtendedSetPasswordForm(SetPasswordForm):
642 652
    """
643 653
    Extends SetPasswordForm by enabling user
......
670 680
        return super(ExtendedSetPasswordForm, self).save(commit=commit)
671 681

  
672 682

  
673

  
674

  
675
app_name_label       =  "Project name"
683
app_name_label = "Project name"
676 684
app_name_placeholder = _("myproject.mylab.ntua.gr")
677
app_name_validator   =  validators.RegexValidator(
678
                            DOMAIN_VALUE_REGEX,
679
                            _(astakos_messages.DOMAIN_VALUE_ERR),
680
                            'invalid')
681
app_name_help        =  _("""
685
app_name_validator = validators.RegexValidator(
686
    DOMAIN_VALUE_REGEX,
687
    _(astakos_messages.DOMAIN_VALUE_ERR),
688
    'invalid')
689
app_name_help = _("""
682 690
        The project's name should be in a domain format.
683 691
        The domain shouldn't neccessarily exist in the real
684 692
        world but is helpful to imply a structure.
685 693
        e.g.: myproject.mylab.ntua.gr or
686 694
        myservice.myteam.myorganization""")
687
app_name_widget      =  forms.TextInput(
688
                            attrs={'placeholder': app_name_placeholder})
695
app_name_widget = forms.TextInput(
696
    attrs={'placeholder': app_name_placeholder})
689 697

  
690 698

  
691
app_home_label       =  "Homepage URL"
692
app_home_placeholder =  'myinstitution.org/myproject/'
693
app_home_help        =  _("""
699
app_home_label = "Homepage URL"
700
app_home_placeholder = 'myinstitution.org/myproject/'
701
app_home_help = _("""
694 702
        URL pointing at your project's site.
695 703
        e.g.: myinstitution.org/myproject/.
696 704
        Leave blank if there is no website.""")
697
app_home_widget      =  forms.TextInput(
698
                            attrs={'placeholder': app_home_placeholder})
705
app_home_widget = forms.TextInput(
706
    attrs={'placeholder': app_home_placeholder})
699 707

  
700
app_desc_label       =  _("Description")
701
app_desc_help        =  _("""
708
app_desc_label = _("Description")
709
app_desc_help = _("""
702 710
        Please provide a short but descriptive abstract of your
703 711
        project, so that anyone searching can quickly understand
704 712
        what this project is about.""")
705 713

  
706
app_comment_label    =  _("Comments for review (private)")
707
app_comment_help     =  _("""
714
app_comment_label = _("Comments for review (private)")
715
app_comment_help = _("""
708 716
        Write down any comments you may have for the reviewer
709 717
        of this application (e.g. background and rationale to
710 718
        support your request).
711 719
        The comments are strictly for the review process
712 720
        and will not be made public.""")
713 721

  
714
app_start_date_label =  _("Start date")
715
app_start_date_help  =  _("""
722
app_start_date_label = _("Start date")
723
app_start_date_help = _("""
716 724
        Provide a date when your need your project to be created,
717 725
        and members to be able to join and get resources.
718 726
        This date is only a hint to help prioritize reviews.""")
719 727

  
720
app_end_date_label   =  _("Termination date")
721
app_end_date_help    =  _("""
728
app_end_date_label = _("Termination date")
729
app_end_date_help = _("""
722 730
        At this date, the project will be automatically terminated
723 731
        and its resource grants revoked from all members. If you are
724 732
        not certain, it is best to start with a conservative estimation.
725 733
        You can always re-apply for an extension, if you need.""")
726 734

  
727
join_policy_label    =  _("Joining policy")
728
app_member_join_policy_help    =  _("""
735
join_policy_label = _("Joining policy")
736
app_member_join_policy_help = _("""
729 737
        Select how new members are accepted into the project.""")
730
leave_policy_label   =  _("Leaving policy")
731
app_member_leave_policy_help    =  _("""
738
leave_policy_label = _("Leaving policy")
739
app_member_leave_policy_help = _("""
732 740
        Select how new members can leave the project.""")
733 741

  
734
max_members_label    =  _("Maximum member count")
735
max_members_help     =  _("""
742
max_members_label = _("Maximum member count")
743
max_members_help = _("""
736 744
        Specify the maximum number of members this project may have,
737 745
        including the owner. Beyond this number, no new members
738 746
        may join the project and be granted the project resources.
......
742 750
join_policies = presentation.PROJECT_MEMBER_JOIN_POLICIES.items()
743 751
leave_policies = presentation.PROJECT_MEMBER_LEAVE_POLICIES.items()
744 752

  
753

  
745 754
class ProjectApplicationForm(forms.ModelForm):
746 755

  
747 756
    name = forms.CharField(
748
        label     = app_name_label,
749
        help_text = app_name_help,
750
        widget    = app_name_widget,
751
        validators = [app_name_validator])
757
        label=app_name_label,
758
        help_text=app_name_help,
759
        widget=app_name_widget,
760
        validators=[app_name_validator])
752 761

  
753 762
    homepage = forms.URLField(
754
        label     = app_home_label,
755
        help_text = app_home_help,
756
        widget    = app_home_widget,
757
        required  = False)
763
        label=app_home_label,
764
        help_text=app_home_help,
765
        widget=app_home_widget,
766
        required=False)
758 767

  
759 768
    description = forms.CharField(
760
        label     = app_desc_label,
761
        help_text = app_desc_help,
762
        widget    = forms.Textarea,
763
        required  = False)
769
        label=app_desc_label,
770
        help_text=app_desc_help,
771
        widget=forms.Textarea,
772
        required=False)
764 773

  
765 774
    comments = forms.CharField(
766
        label     = app_comment_label,
767
        help_text = app_comment_help,
768
        widget    = forms.Textarea,
769
        required  = False)
775
        label=app_comment_label,
776
        help_text=app_comment_help,
777
        widget=forms.Textarea,
778
        required=False)
770 779

  
771 780
    start_date = forms.DateTimeField(
772
        label     = app_start_date_label,
773
        help_text = app_start_date_help,
774
        required  = False)
781
        label=app_start_date_label,
782
        help_text=app_start_date_help,
783
        required=False)
775 784

  
776 785
    end_date = forms.DateTimeField(
777
        label     = app_end_date_label,
778
        help_text = app_end_date_help)
786
        label=app_end_date_label,
787
        help_text=app_end_date_help)
779 788

  
780
    member_join_policy  = forms.TypedChoiceField(
781
        label     = join_policy_label,
782
        help_text = app_member_join_policy_help,
783
        initial   = 2,
784
        coerce    = int,
785
        choices   = join_policies)
789
    member_join_policy = forms.TypedChoiceField(
790
        label=join_policy_label,
791
        help_text=app_member_join_policy_help,
792
        initial=2,
793
        coerce=int,
794
        choices=join_policies)
786 795

  
787 796
    member_leave_policy = forms.TypedChoiceField(
788
        label     = leave_policy_label,
789
        help_text = app_member_leave_policy_help,
790
        coerce    = int,
791
        choices   = leave_policies)
797
        label=leave_policy_label,
798
        help_text=app_member_leave_policy_help,
799
        coerce=int,
800
        choices=leave_policies)
792 801

  
793 802
    limit_on_members_number = forms.IntegerField(
794
        label     = max_members_label,
795
        help_text = max_members_help,
796
        min_value = 0,
797
        required  = False)
803
        label=max_members_label,
804
        help_text=max_members_help,
805
        min_value=0,
806
        required=False)
798 807

  
799 808
    class Meta:
800 809
        model = ProjectApplication
801
        fields = ( 'name', 'homepage', 'description',
802
                    'start_date', 'end_date', 'comments',
803
                    'member_join_policy', 'member_leave_policy',
804
                    'limit_on_members_number')
810
        fields = ('name', 'homepage', 'description',
811
                  'start_date', 'end_date', 'comments',
812
                  'member_join_policy', 'member_leave_policy',
813
                  'limit_on_members_number')
805 814

  
806 815
    def __init__(self, *args, **kwargs):
807 816
        instance = kwargs.get('instance')
......
820 829
            today = datetime(today.year, today.month, today.day)
821 830
            if start_date and (start_date - today).days < 0:
822 831
                raise forms.ValidationError(
823
                _(astakos_messages.INVALID_PROJECT_START_DATE))
832
                    _(astakos_messages.INVALID_PROJECT_START_DATE))
824 833
        return start_date
825 834

  
826 835
    def clean_end_date(self):
......
867 876
                    raise forms.ValidationError("Resource %s does not exist" %
868 877
                                                resource.name)
869 878
                # keep only resource limits for selected resource groups
870
                if self.data.get(
871
                    'is_selected_%s' % resource.group, "0"
872
                 ) == "1":
879
                if self.data.get('is_selected_%s' %
880
                                 resource.group, "0") == "1":
873 881
                    if not resource.allow_in_projects:
874 882
                        raise forms.ValidationError("Invalid resource %s" %
875 883
                                                    resource.name)
......
881 889
                    append(d)
882 890

  
883 891
        ordered_keys = presentation.RESOURCES['resources_order']
892

  
884 893
        def resource_order(r):
885 894
            if r['str_repr'] in ordered_keys:
886 895
                return ordered_keys.index(r['str_repr'])
......
910 919
                 ('issue_date', 'Sort by Issue date'),
911 920
                 ('start_date', 'Sort by Start Date'),
912 921
                 ('end_date', 'Sort by End Date'),
913
#                  ('approved_members_num', 'Sort by Participants'),
922
                 # ('approved_members_num', 'Sort by Participants'),
914 923
                 ('state', 'Sort by Status'),
915
                 ('member_join_policy__description', 'Sort by Member Join Policy'),
916
                 ('member_leave_policy__description', 'Sort by Member Leave Policy'),
924
                 ('member_join_policy__description',
925
                  'Sort by Member Join Policy'),
926
                 ('member_leave_policy__description',
927
                  'Sort by Member Leave Policy'),
917 928
                 ('-name', 'Sort by Name'),
918 929
                 ('-issue_date', 'Sort by Issue date'),
919 930
                 ('-start_date', 'Sort by Start Date'),
920 931
                 ('-end_date', 'Sort by End Date'),
921
#                  ('-approved_members_num', 'Sort by Participants'),
932
                 # ('-approved_members_num', 'Sort by Participants'),
922 933
                 ('-state', 'Sort by Status'),
923
                 ('-member_join_policy__description', 'Sort by Member Join Policy'),
924
                 ('-member_leave_policy__description', 'Sort by Member Leave Policy')
925
        ),
934
                 ('-member_join_policy__description',
935
                  'Sort by Member Join Policy'),
936
                 ('-member_leave_policy__description',
937
                  'Sort by Member Leave Policy')
938
                 ),
926 939
        required=True
927 940
    )
928 941

  
942

  
929 943
class AddProjectMembersForm(forms.Form):
930 944
    q = forms.CharField(
931
        widget=forms.Textarea(attrs={
932
            'placeholder': astakos_messages.ADD_PROJECT_MEMBERS_Q_PLACEHOLDER}
933
            ),
945
        widget=forms.Textarea(
946
            attrs={
947
                'placeholder':
948
                astakos_messages.ADD_PROJECT_MEMBERS_Q_PLACEHOLDER}),
934 949
        label=_('Add members'),
935 950
        help_text=_(astakos_messages.ADD_PROJECT_MEMBERS_Q_HELP),
936 951
        required=True,)
......
966 981
        except:
967 982
            return ()
968 983

  
984

  
969 985
class ProjectMembersSortForm(forms.Form):
970 986
    sorting = forms.ChoiceField(
971 987
        label='Sort by',
972 988
        choices=(('person__email', 'User Id'),
973 989
                 ('person__first_name', 'Name'),
974 990
                 ('acceptance_date', 'Acceptance date')
975
        ),
991
                 ),
976 992
        required=True
977 993
    )
978 994

  
......
1009 1025
    def __init__(self, *args, **kwargs):
1010 1026
        session_key = kwargs.get('session_key', None)
1011 1027
        self.fields_list = [
1012
                'email',
1013
                'new_email_address',
1014
                'first_name',
1015
                'last_name',
1016
                'old_password',
1017
                'new_password1',
1018
                'new_password2',
1019
                'change_email',
1020
                'change_password',
1028
            'email',
1029
            'new_email_address',
1030
            'first_name',
1031
            'last_name',
1032
            'old_password',
1033
            'new_password1',
1034
            'new_password2',
1035
            'change_email',
1036
            'change_password',
1021 1037
        ]
1022 1038

  
1023 1039
        super(ExtendedProfileForm, self).__init__(*args, **kwargs)
......
1043 1059
        self.success_messages = []
1044 1060
        self.fields.keyOrder = self.fields_list
1045 1061

  
1046

  
1047 1062
    def _init_extra_form_fields(self):
1048 1063
        if self.email_change:
1049 1064
            self.fields.update(self.email_change_form.fields)
1050 1065
            self.fields['new_email_address'].required = False
1051
            self.fields['email'].help_text = _('Change the email associated with '
1052
                                               'your account. This email will '
1053
                                               'remain active until you verify '
1054
                                               'your new one.')
1066
            self.fields['email'].help_text = _(
1067
                'Change the email associated with '
1068
                'your account. This email will '
1069
                'remain active until you verify '
1070
                'your new one.')
1055 1071

  
1056 1072
        if self.password_change:
1057 1073
            self.fields.update(self.password_change_form.fields)
......
1070 1086

  
1071 1087
    def _init_extra_forms(self):
1072 1088
        self.email_change_form = EmailChangeForm(self.data)
1073
        self.password_change_form = ExtendedPasswordChangeForm(user=self.instance,
1074
                                   data=self.data, session_key=self.session_key)
1089
        self.password_change_form = ExtendedPasswordChangeForm(
1090
            user=self.instance,
1091
            data=self.data, session_key=self.session_key)
1075 1092
        self._init_extra_form_fields()
1076 1093

  
1077 1094
    def is_valid(self):
......
1099 1116
            self.password_change_form.save(*args, **kwargs)
1100 1117
            self.password_changed = True
1101 1118
        return super(ExtendedProfileForm, self).save(*args, **kwargs)
1102

  
b/snf-astakos-app/astakos/im/functions.py
218 218

  
219 219

  
220 220
def send_change_email(
221
    ec, request, email_template_name='registration/email_change_email.txt'):
221
    ec, request, email_template_name='registration/email_change_email.txt'
222
):
222 223
    url = ec.get_url()
223 224
    url = request.build_absolute_uri(url)
224
    c = {'url': url, 'site_name': settings.SITENAME, 'support': settings.CONTACT_EMAIL,
225
    c = {'url': url, 'site_name': settings.SITENAME,
226
         'support': settings.CONTACT_EMAIL,
225 227
         'ec': ec}
226 228
    message = render_to_string(email_template_name, c)
227 229
    from_email = settings.SERVER_EMAIL
......
725 727
        conflicting_project = Project.objects.get(q)
726 728
        if (conflicting_project != project):
727 729
            m = (_("cannot approve: project with name '%s' "
728
                   "already exists (id: %s)") % (
729
                    new_project_name, conflicting_project.id))
730
            raise PermissionDenied(m) # invalid argument
730
                   "already exists (id: %s)") %
731
                 (new_project_name, conflicting_project.id))
732
            raise PermissionDenied(m)  # invalid argument
731 733
    except Project.DoesNotExist:
732 734
        pass
733 735

  
b/snf-astakos-app/astakos/im/messages.py
35 35
import astakos.im.settings as astakos_settings
36 36

  
37 37

  
38
LOGGED_IN_WARNING                       =   'It seems that you are already logged in.'
39
ACCOUNT_ALREADY_VERIFIED                =   'This account is already verified.'
40
ACCOUNT_ALREADY_MODERATED               =   'This account is already moderated.'
41
ACCOUNT_ALREADY_ACTIVE                  =   'This account is already active.'
42
ACCOUNT_REJECTED                        =   'This account has been rejected.'
43
ACCOUNT_NOT_ACTIVE                      =   'User account is not active.'
44
ACCOUNT_NOT_MODERATED                   =   'User account is not moderated.'
45
ACCOUNT_NOT_VERIFIED                    =   'User account does not have a verified email address.'
46
ACCOUNT_RESEND_ACTIVATION               =   'It seems that an activation email has been sent to you, but you have not followed the activation link. <a href="%(send_activation_url)s">Resend activation email.</a>'
47
INACTIVE_ACCOUNT_CHANGE_EMAIL           =   ''.join([ACCOUNT_RESEND_ACTIVATION, ' Or <a href="%(signup_url)s">Send activation to a new email.</a>'])
38
LOGGED_IN_WARNING = 'It seems that you are already logged in.'
39
ACCOUNT_ALREADY_VERIFIED = 'This account is already verified.'
40
ACCOUNT_ALREADY_MODERATED = 'This account is already moderated.'
41
ACCOUNT_ALREADY_ACTIVE = 'This account is already active.'
42
ACCOUNT_REJECTED = 'This account has been rejected.'
43
ACCOUNT_NOT_ACTIVE = 'User account is not active.'
44
ACCOUNT_NOT_MODERATED = 'User account is not moderated.'
45
ACCOUNT_NOT_VERIFIED = 'User account does not have a verified email address.'
46
ACCOUNT_RESEND_ACTIVATION = (
47
    'It seems that an activation email has been sent to you, but you have '
48
    'not followed the activation link. '
49
    '<a href="%(send_activation_url)s">Resend activation email.</a>')
50
INACTIVE_ACCOUNT_CHANGE_EMAIL = ''.join(
51
    [ACCOUNT_RESEND_ACTIVATION,
52
     ' Or <a href="%(signup_url)s">Send activation to a new email.</a>'])
48 53

  
49
ACCOUNT_PENDING_ACTIVATION_HELP         =   'An activation email has been sent to you. Make sure you check your spam folder, too.'
54
ACCOUNT_PENDING_ACTIVATION_HELP = (
55
    'An activation email has been sent to you. Make sure you check your '
56
    'spam folder, too.')
50 57

  
51
ACCOUNT_ACTIVATED                       =   'Congratulations. Your account has' + \
52
                                            ' been activated. You are now logged in.'
53
ACCOUNT_DEACTIVATED                     =   'Your account is inactive'
54
PASSWORD_RESET_DONE                     =   'An email with details on how to change your password has been sent. Please check your Inbox.'
55
PASSWORD_RESET_CONFIRM_DONE             =   'Your password has changed successfully. You can now login using your new password.'
56
PASSWORD_CHANGED                        =   'Your new password was set successfully.'
58
ACCOUNT_ACTIVATED = 'Congratulations. Your account has' + \
59
    ' been activated. You are now logged in.'
60
ACCOUNT_DEACTIVATED = 'Your account is inactive'
61
PASSWORD_RESET_DONE = (
62
    'An email with details on how to change your password has been sent. '
63
    'Please check your Inbox.')
64
PASSWORD_RESET_CONFIRM_DONE = (
65
    'Your password has changed successfully. You '
66
    'can now login using your new password.')
67
PASSWORD_CHANGED = 'Your new password was set successfully.'
57 68

  
58
ACCOUNT_RESEND_ACTIVATION               =   'Resend activation email'
59
ACCOUNT_USER_ACTIVATION_PENDING         =   'You have not followed the activation link'
69
ACCOUNT_RESEND_ACTIVATION = 'Resend activation email'
70
ACCOUNT_USER_ACTIVATION_PENDING = 'You have not followed the activation link'
60 71

  
61
ACCOUNT_UNKNOWN                         =   'There is no such account.'
62
TOKEN_UNKNOWN                           =   'There is no user matching this authentication token.'
63
TOKEN_UPDATED                           =   'Your authentication token has been updated successfully.'
72
ACCOUNT_UNKNOWN = 'There is no such account.'
73
TOKEN_UNKNOWN = 'There is no user matching this authentication token.'
74
TOKEN_UPDATED = 'Your authentication token has been updated successfully.'
64 75

  
65
PROFILE_UPDATED                         =   'Your profile has been updated successfully.'
66
FEEDBACK_SENT                           =   'Thank you for contacting us. We will process your message carefully and get back to you.'
67
EMAIL_CHANGED                           =   'The email of your account changed successfully.'
68
EMAIL_CHANGE_REGISTERED                 =   'Your request for changing your email has been registered successfully. \
69
                                               A verification email will be sent to your new address.'
76
PROFILE_UPDATED = 'Your profile has been updated successfully.'
77
FEEDBACK_SENT = (
78
    'Thank you for contacting us. We will process your message carefully '
79
    'and get back to you.')
80
EMAIL_CHANGED = 'The email of your account changed successfully.'
81
EMAIL_CHANGE_REGISTERED = (
82
    'Your request for changing your email has been registered successfully. '
83
    'A verification email will be sent to your new address.')
70 84

  
71
OBJECT_CREATED                          =   'The %(verbose_name)s was created successfully.'
72
USER_MEMBERSHIP_REJECTED                =   'Request by %s to join the project has been rejected.'
73
BILLING_ERROR                           =   'Service response status: %(status)d'
85
OBJECT_CREATED = 'The %(verbose_name)s was created successfully.'
86
USER_MEMBERSHIP_REJECTED = (
87
    'Request by %s to join the project has been rejected.')
88
BILLING_ERROR = 'Service response status: %(status)d'
74 89

  
75
GENERIC_ERROR                           =   'Hmm... It seems something bad has happened, and we don\'t know the details right now. \
76
                                               Please contact the administrators by email for more details.'
90
GENERIC_ERROR = (
91
    'Hmm... It seems something bad has happened, and we don\'t know the '
92
    'details right now. Please contact the administrators by email for '
93
    'more details.')
77 94

  
78
MAX_INVITATION_NUMBER_REACHED   =           'You have reached the maximum amount of invitations for your account. No invitations left.'
79
GROUP_MAX_PARTICIPANT_NUMBER_REACHED    =   'This Group reached its maximum number of members. No other member can be added.'
80
PROJECT_MAX_PARTICIPANT_NUMBER_REACHED  =   'This Project reached its maximum number of members. No other member can be added.'
81
NO_APPROVAL_TERMS                       =   'There are no terms of service to approve.'
82
PENDING_EMAIL_CHANGE_REQUEST            =   'It seems there is already a pending request for an email change. ' + \
83
                                            'Submitting a new request to change your email will cancel all previous requests.'
84
OBJECT_CREATED_FAILED                   =   'The %(verbose_name)s creation failed: %(reason)s.'
85
GROUP_JOIN_FAILURE                      =   'Failed to join this Group.'
86
PROJECT_JOIN_FAILURE                    =   'Failed to join this Project.'
87
GROUPKIND_UNKNOWN                       =   'The kind of Project you specified does not exist.'
88
NOT_MEMBER                              =   'User is not a member of the Project.'
89
NOT_OWNER                               =   'User is not the Project\'s owner.'
90
OWNER_CANNOT_LEAVE_GROUP                =   'You are the owner of this Project. Owners can not leave their Projects.'
95
MAX_INVITATION_NUMBER_REACHED = (
96
    'You have reached the maximum amount of invitations for your account. '
97
    'No invitations left.')
98
GROUP_MAX_PARTICIPANT_NUMBER_REACHED = (
99
    'This Group reached its maximum number of members. No other member can '
100
    'be added.')
101
PROJECT_MAX_PARTICIPANT_NUMBER_REACHED = (
102
    'This Project reached its maximum number of members. No other member '
103
    'can be added.')
104
NO_APPROVAL_TERMS = 'There are no terms of service to approve.'
105
PENDING_EMAIL_CHANGE_REQUEST = (
106
    'It seems there is already a pending request for an email change. '
107
    'Submitting a new request to change your email will cancel all previous '
108
    'requests.')
109
OBJECT_CREATED_FAILED = 'The %(verbose_name)s creation failed: %(reason)s.'
110
GROUP_JOIN_FAILURE = 'Failed to join this Group.'
111
PROJECT_JOIN_FAILURE = 'Failed to join this Project.'
112
GROUPKIND_UNKNOWN = 'The kind of Project you specified does not exist.'
113
NOT_MEMBER = 'User is not a member of the Project.'
114
NOT_OWNER = 'User is not the Project\'s owner.'
115
OWNER_CANNOT_LEAVE_GROUP = (
116
    'You are the owner of this Project. Owners can not leave their Projects.')
91 117

  
92 118
# Field validation fields
93
REQUIRED_FIELD                          =   'This field is required.'
94
EMAIL_USED                              =   'There is already an account with this email address.'
95
SHIBBOLETH_EMAIL_USED                   =   'This email is already associated with another shibboleth account.'
96
SHIBBOLETH_INACTIVE_ACC                 =   'This email is already associated with an account that is not yet activated. \
97
                                               If that is your account, you need to activate it before being able to \
98
                                               associate it with this shibboleth account.'
99
SHIBBOLETH_MISSING_EPPN                 =   'Your request is missing a unique ' + \
100
                                            'token. This means your academic ' + \
101
                                            'institution does not yet allow its users to log ' + \
102
                                            'into %(domain)s with their academic ' + \
103
                                            'account. Please contact %(contact_email)s' + \
104
                                            ' for more information.'
105
SHIBBOLETH_MISSING_NAME                 =   'This request is missing the user name.'
119
REQUIRED_FIELD = 'This field is required.'
120
EMAIL_USED = 'There is already an account with this email address.'
121
SHIBBOLETH_EMAIL_USED = (
122
    'This email is already associated with another shibboleth account.')
123
SHIBBOLETH_INACTIVE_ACC = (
124
    'This email is already associated with an account that is not '
125
    'yet activated. '
126
    'If that is your account, you need to activate it before being able to '
127
    'associate it with this shibboleth account.')
128
SHIBBOLETH_MISSING_EPPN = (
129
    'Your request is missing a unique ' +
130
    'token. This means your academic ' +
131
    'institution does not yet allow its users to log ' +
132
    'into %(domain)s with their academic ' +
133
    'account. Please contact %(contact_email)s' +
134
    ' for more information.')
135
SHIBBOLETH_MISSING_NAME = 'This request is missing the user name.'
106 136

  
107
SIGN_TERMS                              =   'Please, you need to \'Agree with the terms\' before proceeding.'
108
CAPTCHA_VALIDATION_ERR                  =   'You have not entered the correct words. Please try again.'
109
SUSPENDED_LOCAL_ACC                     =   'This account does not have a local password. \
110
                                               Please try logging in using an external login provider (e.g.: twitter)'
111
EMAIL_UNKNOWN                           =   'This email address doesn\'t have an associated user account. \
112
                                               Please make sure you have registered, before proceeding.'
113
INVITATION_EMAIL_EXISTS                 =   'An invitation has already been sent to this email.'
114
INVITATION_CONSUMED_ERR                 =   'Invitation is used.'
115
UNKNOWN_USERS                           =   'Unknown users: %s'
116
UNIQUE_EMAIL_IS_ACTIVE_CONSTRAIN_ERR    =   'More than one account with the same email & \'is_active\' field. Error.'
117
INVALID_ACTIVATION_KEY                  =   'Invalid activation key.'
118
NEW_EMAIL_ADDR_RESERVED                 =   'The new email address you requested is already used by another account. Please provide a different one.'
119
EMAIL_RESERVED                          =   'Email: %(email)s is already reserved.'
120
NO_LOCAL_AUTH                           =   'Only external login providers are enabled for this acccount. You can not login with a local password.'
121
SWITCH_ACCOUNT_FAILURE                  =   'Account failed to switch. Invalid parameters.'
122
SWITCH_ACCOUNT_SUCCESS_WITH_PROVIDER    =   'Account failed to switch to %(provider)s.'
123
SWITCH_ACCOUNT_SUCCESS                  =   'Account successfully switched to %(provider)s.'
137
SIGN_TERMS = 'Please, you need to \'Agree with the terms\' before proceeding.'
138
CAPTCHA_VALIDATION_ERR = (
139
    'You have not entered the correct words. Please try again.')
140
SUSPENDED_LOCAL_ACC = (
141
    'This account does not have a local password. '
142
    'Please try logging in using an external login provider (e.g.: twitter)')
143
EMAIL_UNKNOWN = (
144
    'This email address doesn\'t have an associated user account. '
145
    'Please make sure you have registered, before proceeding.')
146
INVITATION_EMAIL_EXISTS = 'An invitation has already been sent to this email.'
147
INVITATION_CONSUMED_ERR = 'Invitation is used.'
148
UNKNOWN_USERS = 'Unknown users: %s'
149
UNIQUE_EMAIL_IS_ACTIVE_CONSTRAIN_ERR = (
150
    'More than one account with the same email & \'is_active\' field. Error.')
151
INVALID_ACTIVATION_KEY = 'Invalid activation key.'
152
NEW_EMAIL_ADDR_RESERVED = (
153
    'The new email address you requested is already used by another account. '
154
    'Please provide a different one.')
155
EMAIL_RESERVED = 'Email: %(email)s is already reserved.'
156
NO_LOCAL_AUTH = (
157
    'Only external login providers are enabled for this account. '
158
    'You can not login with a local password.')
159
SWITCH_ACCOUNT_FAILURE = 'Account failed to switch. Invalid parameters.'
160
SWITCH_ACCOUNT_SUCCESS_WITH_PROVIDER = (
161
    'Account failed to switch to %(provider)s.')
162
SWITCH_ACCOUNT_SUCCESS = 'Account successfully switched to %(provider)s.'
124 163

  
125 164
# Field help text
126
ADD_GROUP_MEMBERS_Q_HELP                =   'Add a comma separated list of user emails, eg. user1@user.com, user2@user.com'
127
ASTAKOSUSER_GROUPS_HELP                 =   'In addition to the permissions assigned manually, \
128
                                               this user will also get all permissions coming from his/her groups.'
165
ADD_GROUP_MEMBERS_Q_HELP = (
166
    'Add a comma separated list of user emails, eg. user1@user.com, '
167
    'user2@user.com')
168
ASTAKOSUSER_GROUPS_HELP = (
169
    'In addition to the permissions assigned manually, '
170
    'this user will also get all permissions coming from his/her groups.')
129 171

  
130
EMAIL_SEND_ERR                          =   'Failed to send %s.'
131
ADMIN_NOTIFICATION_SEND_ERR             =   EMAIL_SEND_ERR % 'admin notification'
132
VERIFICATION_SEND_ERR                   =   EMAIL_SEND_ERR % 'verification'
133
INVITATION_SEND_ERR                     =   EMAIL_SEND_ERR % 'invitation'
134
GREETING_SEND_ERR                       =   EMAIL_SEND_ERR % 'greeting'
135
FEEDBACK_SEND_ERR                       =   EMAIL_SEND_ERR % 'feedback'
136
CHANGE_EMAIL_SEND_ERR                   =   EMAIL_SEND_ERR % 'email change'
137
NOTIFICATION_SEND_ERR                   =   EMAIL_SEND_ERR % 'notification'
138
DETAILED_NOTIFICATION_SEND_ERR          =   'Failed to send %(subject)s notification to %(recipients)s.'
172
EMAIL_SEND_ERR = 'Failed to send %s.'
173
ADMIN_NOTIFICATION_SEND_ERR = EMAIL_SEND_ERR % 'admin notification'
174
VERIFICATION_SEND_ERR = EMAIL_SEND_ERR % 'verification'
175
INVITATION_SEND_ERR = EMAIL_SEND_ERR % 'invitation'
176
GREETING_SEND_ERR = EMAIL_SEND_ERR % 'greeting'
177
FEEDBACK_SEND_ERR = EMAIL_SEND_ERR % 'feedback'
178
CHANGE_EMAIL_SEND_ERR = EMAIL_SEND_ERR % 'email change'
179
NOTIFICATION_SEND_ERR = EMAIL_SEND_ERR % 'notification'
180
DETAILED_NOTIFICATION_SEND_ERR = (
181
    'Failed to send %(subject)s notification to %(recipients)s.')
139 182

  
140
MISSING_NEXT_PARAMETER                  =   'The next parameter is missing.'
183
MISSING_NEXT_PARAMETER = 'The next parameter is missing.'
141 184

  
142
INVITATION_SENT                         =   'Invitation sent to %(email)s.'
143
VERIFICATION_SENT                       =   'Your information has been submitted successfully. A verification email, with an activation link \
144
                                               has been sent to the email address you provided. Please follow the activation link on this \
145
                                               email to complete the registration process.'
146
VERIFICATION_FAILED                     =   'Email verification process failed.'
147
SWITCH_ACCOUNT_LINK_SENT                =   'This email is already associated with a local account, and a verification email has been sent \
148
                                             to %(email)s. To complete the association process, go back to your Inbox and follow the link \
149
                                             inside the verification email.'
150
NOTIFICATION_SENT                       =   'Your request for an account has been submitted successfully, and is now pending approval. \
151
                                               You will be notified by email in the next few days. \
152
                                               Thanks for your interest!'
153
ACTIVATION_SENT                         =   'An email containing your activation link has been sent to your email address.'
185
INVITATION_SENT = 'Invitation sent to %(email)s.'
186
VERIFICATION_SENT = (
187
    'Your information has been submitted successfully. A verification email, '
188
    'with an activation link has been sent to the email address you provided. '
189
    'Please follow the activation link on this email to complete the '
190
    'registration process.')
191
VERIFICATION_FAILED = 'Email verification process failed.'
192
SWITCH_ACCOUNT_LINK_SENT = (
193
    'This email is already associated with a local account, '
194
    'and a verification email has been sent to %(email)s. To complete '
195
    'the association process, go back to your Inbox and follow the link '
196
    'inside the verification email.')
197
NOTIFICATION_SENT = (
198
    'Your request for an account has been submitted successfully, and is '
199
    'now pending approval. You will be notified by email in the next few '
200
    'days. Thanks for your interest!')
201
ACTIVATION_SENT = (
202
    'An email containing your activation link has been sent to your '
203
    'email address.')
154 204

  
155
REGISTRATION_COMPLETED                  =   'Your registration completed successfully. You can now login to your new account!'
205
REGISTRATION_COMPLETED = (
206
    'Your registration completed successfully. You can now login to your '
207
    'new account!')
156 208

  
157
NO_RESPONSE                             =   'There is no response.'
158
NOT_ALLOWED_NEXT_PARAM                  =   'Not allowed next parameter.'
159
MISSING_KEY_PARAMETER                   =   'Missing key parameter.'
160
INVALID_KEY_PARAMETER                   =   'Invalid key.'
161
DOMAIN_VALUE_ERR                        =   'Enter a valid domain.'
162
QH_SYNC_ERROR                           =   'Failed to get synchronized with quotaholder.'
163
UNIQUE_PROJECT_NAME_CONSTRAIN_ERR       =   'The project name (as specified in its application\'s definition) must be unique among all active projects.'
164
INVALID_PROJECT                         =   'Project %(id)s is invalid.'
165
NOT_ALIVE_PROJECT                       =   'Project %(id)s is not alive.'
166
NOT_SUSPENDED_PROJECT                   =   'Project %(id)s is not suspended.'
167
NOT_ALLOWED                             =   'You do not have the permissions to perform this action.'
168
MEMBER_NUMBER_LIMIT_REACHED             =   'You have reached the maximum number of members for this Project.'
169
MEMBER_JOIN_POLICY_CLOSED               =   'The Project\'s member join policy is closed.'
170
MEMBER_LEAVE_POLICY_CLOSED              =   'The project\'s member leave policy is closed.'
171
NOT_MEMBERSHIP_REQUEST                  =   'This is not a valid membership request.'
172
NOT_ACCEPTED_MEMBERSHIP                 =   'This is not an accepted membership.'
173
MEMBERSHIP_REQUEST_EXISTS               =   'The membership request already exists.'
174
NO_APPLICANT                            =   'Project application requires at least one applicant. None found.'
175
INVALID_PROJECT_START_DATE              =   'Project start date should be equal or greater than the current date.'
176
INVALID_PROJECT_END_DATE                =   'Project end date should be equal or greater than than the current date.'
177
INCONSISTENT_PROJECT_DATES              =   'Project end date should be greater than the project start date.'
178
ADD_PROJECT_MEMBERS_Q_HELP              =   'Add a comma separated list of user emails, eg. user1@user.com, user2@user.com'
179
ADD_PROJECT_MEMBERS_Q_PLACEHOLDER       =   'user1@user.com, user2@user.com'
180
MISSING_IDENTIFIER                      =   'Missing identifier.'
181
UNKNOWN_USER_ID                         =   'There is no user identified by %s.'
182
UNKNOWN_PROJECT_APPLICATION_ID          =   'There is no project application identified by %s.'
183
UNKNOWN_PROJECT_ID                      =   'There is no project identified by %s.'
184
UNKNOWN_IDENTIFIER                      =   'Unknown identifier.'
185
PENDING_MEMBERSHIP_LEAVE                =   'Your request is pending moderation by the Project owner.'
186
USER_MEMBERSHIP_ACCEPTED                =   '%s has been accepted in the project.'
187
USER_MEMBERSHIP_REMOVED                 =   '%s has been removed from the project.'
188
USER_LEFT_PROJECT                       =   'You have left the project.'
189
USER_LEAVE_REQUEST_SUBMITTED            =   'Your request to leave the project has been submitted successfully.'
190
USER_JOIN_REQUEST_SUBMITTED             =   'Your request to join the project has been submitted successfully.'
191
USER_JOINED_PROJECT                     =   'You have joined the project.'
192
USER_REQUEST_CANCELLED                  =   'Your request to join the project has been cancelled.'
193
APPLICATION_CANNOT_APPROVE              =   "Cannot approve application %s in state '%s'"
194
APPLICATION_CANNOT_DENY                 =   "Cannot deny application %s in state '%s'"
195
APPLICATION_CANNOT_DISMISS              =   "Cannot dismiss application %s in state '%s'"
196
APPLICATION_CANNOT_CANCEL               =   "Cannot cancel application %s in state '%s'"
197
APPLICATION_CANCELLED                   =   "Your project application has been cancelled."
209
NO_RESPONSE = 'There is no response.'
210
NOT_ALLOWED_NEXT_PARAM = 'Not allowed next parameter.'
211
MISSING_KEY_PARAMETER = 'Missing key parameter.'
212
INVALID_KEY_PARAMETER = 'Invalid key.'
213
DOMAIN_VALUE_ERR = 'Enter a valid domain.'
214
QH_SYNC_ERROR = 'Failed to get synchronized with quotaholder.'
215
UNIQUE_PROJECT_NAME_CONSTRAIN_ERR = (
216
    'The project name (as specified in its application\'s definition) must '
217
    'be unique among all active projects.')
218
INVALID_PROJECT = 'Project %(id)s is invalid.'
219
NOT_ALIVE_PROJECT = 'Project %(id)s is not alive.'
220
NOT_SUSPENDED_PROJECT = 'Project %(id)s is not suspended.'
221
NOT_ALLOWED = 'You do not have the permissions to perform this action.'
222
MEMBER_NUMBER_LIMIT_REACHED = (
223
    'You have reached the maximum number of members for this Project.')
224
MEMBER_JOIN_POLICY_CLOSED = 'The Project\'s member join policy is closed.'
225
MEMBER_LEAVE_POLICY_CLOSED = 'The project\'s member leave policy is closed.'
226
NOT_MEMBERSHIP_REQUEST = 'This is not a valid membership request.'
227
NOT_ACCEPTED_MEMBERSHIP = 'This is not an accepted membership.'
228
MEMBERSHIP_REQUEST_EXISTS = 'The membership request already exists.'
229
NO_APPLICANT = (
230
    'Project application requires at least one applicant. None found.')
231
INVALID_PROJECT_START_DATE = (
232
    'Project start date should be equal or greater than the current date.')
233
INVALID_PROJECT_END_DATE = (
234
    'Project end date should be equal or greater than than the current date.')
235
INCONSISTENT_PROJECT_DATES = (
236
    'Project end date should be greater than the project start date.')
237
ADD_PROJECT_MEMBERS_Q_HELP = (
238
    'Add a comma separated list of user emails, eg. user1@user.com, '
239
    'user2@user.com')
240
ADD_PROJECT_MEMBERS_Q_PLACEHOLDER = 'user1@user.com, user2@user.com'
241
MISSING_IDENTIFIER = 'Missing identifier.'
242
UNKNOWN_USER_ID = 'There is no user identified by %s.'
243
UNKNOWN_PROJECT_APPLICATION_ID = (
244
    'There is no project application identified by %s.')
245
UNKNOWN_PROJECT_ID = 'There is no project identified by %s.'
246
UNKNOWN_IDENTIFIER = 'Unknown identifier.'
247
PENDING_MEMBERSHIP_LEAVE = (
248
    'Your request is pending moderation by the Project owner.')
249
USER_MEMBERSHIP_ACCEPTED = '%s has been accepted in the project.'
250
USER_MEMBERSHIP_REMOVED = '%s has been removed from the project.'
251
USER_LEFT_PROJECT = 'You have left the project.'
252
USER_LEAVE_REQUEST_SUBMITTED = (
253
    'Your request to leave the project has been submitted successfully.')
254
USER_JOIN_REQUEST_SUBMITTED = (
255
    'Your request to join the project has been submitted successfully.')
256
USER_JOINED_PROJECT = 'You have joined the project.'
257
USER_REQUEST_CANCELLED = 'Your request to join the project has been cancelled.'
258
APPLICATION_CANNOT_APPROVE = "Cannot approve application %s in state '%s'"
259
APPLICATION_CANNOT_DENY = "Cannot deny application %s in state '%s'"
260
APPLICATION_CANNOT_DISMISS = "Cannot dismiss application %s in state '%s'"
261
APPLICATION_CANNOT_CANCEL = "Cannot cancel application %s in state '%s'"
262
APPLICATION_CANCELLED = "Your project application has been cancelled."
198 263

  
199 264
REACHED_PENDING_APPLICATION_LIMIT = ("You have reached the maximum number "
200 265
                                     "of pending project applications: %s.")
......
212 277
     "Consider cancelling any unnecessary ones.")
213 278

  
214 279
# Auth providers messages
215
AUTH_PROVIDER_LOGIN_SUCCESS                  =   "Logged in successfully, using {method_prompt}."
216
AUTH_PROVIDER_LOGOUT_SUCCESS                 =   "Logged out successfully."
217
AUTH_PROVIDER_LOGOUT_SUCCESS_EXTRA           =   "You may still be logged in at {title} though. Consider logging out from there too."
218
AUTH_PROVIDER_NOT_ACTIVE                     =   "'{method_prompt}' is disabled."
219
AUTH_PROVIDER_ADD_DISABLED                   =   "{method_prompt} is disabled for your account."
220
AUTH_PROVIDER_NOT_ACTIVE_FOR_USER            =   "You cannot login using '{method_prompt}'."
221
AUTH_PROVIDER_NOT_ACTIVE_FOR_CREATE          =   "Sign up using '{method_prompt}' is disabled."
222
AUTH_PROVIDER_NOT_ACTIVE_FOR_ADD             =   "You cannot add {method_prompt}."
223
AUTH_PROVIDER_ADDED                          =   "{method_prompt} enabled for this account."
224
AUTH_PROVIDER_SWITCHED                       =   "{method_prompt} changed for this account."
225
AUTH_PROVIDER_REMOVED                        =   "{method_prompt} removed for this account."
226
AUTH_PROVIDER_ADD_FAILED                     =   "Failed to add {method_prompt}."
227
AUTH_PROVIDER_ADD_EXISTS                     =   "It seems that this '{method_prompt}' is already in use by another account."
228
AUTH_PROVIDER_LOGIN_TO_ADD                   =   "The new login method will be assigned once you login to your account."
229
AUTH_PROVIDER_INVALID_LOGIN                  =   "No account exists."
230
AUTH_PROVIDER_REQUIRED                       =   "{method_prompt} is required. Add one from your profile page."
231
AUTH_PROVIDER_CANNOT_CHANGE_PASSWORD         =   "Changing password is not supported."
232
AUTH_PROVIDER_SIGNUP_FROM_LOGIN              =   None
233
AUTH_PROVIDER_UNUSABLE_PASSWORD              =   '{method_prompt} is not enabled' \
234
                                                 ' for your account. You can access your account by logging in with' \
235
                                                 ' {available_methods_links}.'
236
AUTH_PROVIDER_LOGIN_DISABLED                 =   AUTH_PROVIDER_UNUSABLE_PASSWORD
237
AUTH_PROVIDER_SIGNUP_FROM_LOGIN              =   ''
238
AUTH_PROVIDER_AUTHENTICATION_FAILED          =   'Authentication with this account failed.'
280
AUTH_PROVIDER_LOGIN_SUCCESS = "Logged in successfully, using {method_prompt}."
281
AUTH_PROVIDER_LOGOUT_SUCCESS = "Logged out successfully."
282
AUTH_PROVIDER_LOGOUT_SUCCESS_EXTRA = (
283
    "You may still be logged in at {title} though. "
284
    "Consider logging out from there too.")
285
AUTH_PROVIDER_NOT_ACTIVE = "'{method_prompt}' is disabled."
286
AUTH_PROVIDER_ADD_DISABLED = "{method_prompt} is disabled for your account."
287
AUTH_PROVIDER_NOT_ACTIVE_FOR_USER = "You cannot login using '{method_prompt}'."
288
AUTH_PROVIDER_NOT_ACTIVE_FOR_CREATE = (
289
    "Sign up using '{method_prompt}' is disabled.")
290
AUTH_PROVIDER_NOT_ACTIVE_FOR_ADD = "You cannot add {method_prompt}."
291
AUTH_PROVIDER_ADDED = "{method_prompt} enabled for this account."
292
AUTH_PROVIDER_SWITCHED = "{method_prompt} changed for this account."
293
AUTH_PROVIDER_REMOVED = "{method_prompt} removed for this account."
294
AUTH_PROVIDER_ADD_FAILED = "Failed to add {method_prompt}."
295
AUTH_PROVIDER_ADD_EXISTS = (
296
    "It seems that this '{method_prompt}' is already in use by "
297
    "another account.")
298
AUTH_PROVIDER_LOGIN_TO_ADD = (
299
    "The new login method will be assigned once you login to your account.")
300
AUTH_PROVIDER_INVALID_LOGIN = "No account exists."
301
AUTH_PROVIDER_REQUIRED = (
302
    "{method_prompt} is required. Add one from your profile page.")
303
AUTH_PROVIDER_CANNOT_CHANGE_PASSWORD = "Changing password is not supported."
304
AUTH_PROVIDER_SIGNUP_FROM_LOGIN = None
305
AUTH_PROVIDER_UNUSABLE_PASSWORD = (
306
    '{method_prompt} is not enabled'
307
    ' for your account. You can access your account by logging in with'
308
    ' {available_methods_links}.')
309
AUTH_PROVIDER_LOGIN_DISABLED = AUTH_PROVIDER_UNUSABLE_PASSWORD
310
AUTH_PROVIDER_SIGNUP_FROM_LOGIN = ''
311
AUTH_PROVIDER_AUTHENTICATION_FAILED = (
312
    'Authentication with this account failed.')
239 313

  
240 314

  
241
AUTH_PROVIDER_PENDING_REGISTRATION =  '''A pending registration exists for
315
AUTH_PROVIDER_PENDING_REGISTRATION = '''A pending registration exists for
242 316
{title} account {username}. The email used for the registration is
243 317
{user_email}. If you decide to procceed with the signup process once again,
244 318
all pending registrations will be deleted.'''
245 319

  
246
AUTH_PROVIDER_PENDING_RESEND_ACTIVATION      =   '<a href="{resend_activation_url}">Click here to resend activation email.</a>'
247
AUTH_PROVIDER_PENDING_MODERATION             =   'Your account request is pending moderation.'
248
AUTH_PROVIDER_PENDING_ACTIVATION             =   'Your account request is pending activation.'
249
AUTH_PROVIDER_ACCOUNT_INACTIVE               =   'Your account is disabled.'
320
AUTH_PROVIDER_PENDING_RESEND_ACTIVATION = (
321
    '<a href="{resend_activation_url}">Click here to resend activation '
322
    'email.</a>')
323
AUTH_PROVIDER_PENDING_MODERATION = (
324
    'Your account request is pending moderation.')
325
AUTH_PROVIDER_PENDING_ACTIVATION = (
326
    'Your account request is pending activation.')
327
AUTH_PROVIDER_ACCOUNT_INACTIVE = 'Your account is disabled.'
250 328

  
251
AUTH_PROVIDER_ADD_TO_EXISTING_ACCOUNT        =   "You can add {method_prompt} to your existing account from your " \
252
                                                 " <a href='{profile_url}'>profile page</a>"
329
AUTH_PROVIDER_ADD_TO_EXISTING_ACCOUNT = (
330
    "You can add {method_prompt} to your existing account from your "
331
    " <a href='{profile_url}'>profile page</a>")
253 332

  
254 333
# Email subjects
255 334
_SITENAME = astakos_settings.SITENAME
b/snf-astakos-app/astakos/im/models.py
148 148
            else:
149 149
                metadata[component.name] = d
150 150

  
151

  
152 151
        def component_by_order(s):
153 152
            return s[1].get('order')
154 153

  
......
276 275
            return '%ss' % self.display_name
277 276
        return self.display_name
278 277

  
278

  
279 279
def get_resource_names():
280 280
    _RESOURCE_NAMES = []
281 281
    resources = Resource.objects.select_related('service').all()
......
320 320
        Returns a uuid to username mapping for the uuids appearing in l.
321 321
        If l is None returns the mapping for all existing users.
322 322
        """
323
        q = self.filter(uuid__in=l) if l != None else self
323
        q = self.filter(uuid__in=l) if l is not None else self
324 324
        return dict(q.values_list('uuid', 'username'))
325 325

  
326 326
    def displayname_catalog(self, l=None):
......
331 331
        if l is not None:
332 332
            lmap = dict((x.lower(), x) for x in l)
333 333
            q = self.filter(username__in=lmap.keys())
334
            values = ((lmap[n], u) for n, u in q.values_list('username', 'uuid'))
334
            values = ((lmap[n], u)
335
                      for n, u in q.values_list('username', 'uuid'))
335 336
        else:
336 337
            q = self
337 338
            values = self.values_list('username', 'uuid')
338 339
        return dict(values)
339 340

  
340 341

  
341

  
342 342
class AstakosUser(User):
343 343
    """
344 344
    Extends ``django.contrib.auth.models.User`` by defining additional fields.
345 345
    """
346
    affiliation = models.CharField(_('Affiliation'), max_length=255, blank=True,
347
                                   null=True)
346
    affiliation = models.CharField(_('Affiliation'), max_length=255,
347
                                   blank=True, null=True)
348 348

  
349 349
    #for invitations
350 350
    user_level = astakos_settings.DEFAULT_USER_LEVEL
351 351
    level = models.IntegerField(_('Inviter level'), default=user_level)
352 352
    invitations = models.IntegerField(
353
        _('Invitations left'), default=astakos_settings.INVITATIONS_PER_LEVEL.get(user_level, 0))
354

  
355
    auth_token = models.CharField(_('Authentication Token'),
356
                                  max_length=64,
357
                                  unique=True,
358
                                  null=True,
359
                                  blank=True,
360
                                  help_text = _('Renew your authentication '
361
                                                'token. Make sure to set the new '
362
                                                'token in any client you may be '
363
                                                'using, to preserve its '
364
                                                'functionality.'))
353
        _('Invitations left'),
354
        default=astakos_settings.INVITATIONS_PER_LEVEL.get(user_level, 0))
355

  
356
    auth_token = models.CharField(
357
        _('Authentication Token'),
358
        max_length=64,
359
        unique=True,
360
        null=True,
361
        blank=True,
362
        help_text=_('Renew your authentication '
363
                    'token. Make sure to set the new '
364
                    'token in any client you may be '
365
                    'using, to preserve its '
366
                    'functionality.'))
365 367
    auth_token_created = models.DateTimeField(_('Token creation date'),
366 368
                                              null=True)
367 369
    auth_token_expires = models.DateTimeField(
......
428 430
        Resource, null=True, through='AstakosUserQuota')
429 431

  
430 432
    disturbed_quota = models.BooleanField(_('Needs quotaholder syncing'),
431
                                           default=False, db_index=True)
433
                                          default=False, db_index=True)
432 434

  
433 435
    objects = AstakosUserManager()
434 436
    forupdate = ForUpdateManager()
......
463 465
        if self.has_perm(pname):
464 466
            return
465 467
        p, created = Permission.objects.get_or_create(
466
                                    codename=pname,
467
                                    name=pname.capitalize(),
468
                                    content_type=get_content_type())
468
            codename=pname,
469
            name=pname.capitalize(),
470
            content_type=get_content_type())
469 471
        self.user_permissions.add(p)
470 472

  
471 473
    def remove_permission(self, pname):
......
545 547
        self.auth_token = new_token
546 548
        self.auth_token_created = datetime.now()
547 549
        self.auth_token_expires = self.auth_token_created + \
548
                                  timedelta(hours=astakos_settings.AUTH_TOKEN_DURATION)
550
            timedelta(hours=astakos_settings.AUTH_TOKEN_DURATION)
549 551
        if flush_sessions:
550 552
            self.flush_sessions(current_key)
551 553
        msg = 'Token renewed for %s' % self.log_display
......
605 607
                msg += " (manually accepted)"
606 608
            else:
607 609
                msg += " (accepted policy: %s)" % \
608
                        self.accepted_policy
610
                    self.accepted_policy
609 611
        return msg
610 612

  
611 613
    @property
......
730 732

  
731 733
    def get_activation_url(self, nxt=False):
732 734
        url = "%s?auth=%s" % (reverse('astakos.im.views.activate'),
733
                                 quote(self.verification_code))
735
                              quote(self.verification_code))
734 736
        if nxt:
735 737
            url += "&next=%s" % quote(nxt)
736 738
        return url
737 739

  
738 740
    def get_password_reset_url(self, token_generator=default_token_generator):
739 741
        return reverse('astakos.im.views.target.local.password_reset_confirm',
740
                          kwargs={'uidb36':int_to_base36(self.id),
741
                                  'token':token_generator.make_token(self)})
742
                       kwargs={'uidb36': int_to_base36(self.id),
743
                               'token': token_generator.make_token(self)})
742 744

  
743 745
    def get_inactive_message(self, provider_module, identifier=None):
744 746
        provider = self.get_auth_provider(provider_module, identifier)
......
758 760
            message = msg_pending
759 761
            url = self.get_resend_activation_url()
760 762
            msg_extra = msg_pending_help + \
761
                        u' ' + \
762
                        '<a href="%s">%s?</a>' % (url, msg_resend)
763
                u' ' + \
764
                '<a href="%s">%s?</a>' % (url, msg_resend)
763 765
        else:
764 766
            if not self.moderated:
765 767
                message = msg_pending_mod
......
930 932
    """
931 933
    Available user authentication methods.
932 934
    """
933
    affiliation = models.CharField(_('Affiliation'), max_length=255, blank=True,
934
                                   null=True, default=None)
935
    affiliation = models.CharField(_('Affiliation'), max_length=255,
936
                                   blank=True, null=True, default=None)
935 937
    user = models.ForeignKey(AstakosUser, related_name='auth_providers')
936 938
    module = models.CharField(_('Provider'), max_length=255, blank=False,
937
                                default='local')
939
                              default='local')
938 940
    identifier = models.CharField(_('Third-party identifier'),
939
                                              max_length=255, null=True,
940
                                              blank=True)
941
                                  max_length=255, null=True,
942
                                  blank=True)
941 943
    active = models.BooleanField(default=True)
942 944
    auth_backend = models.CharField(_('Backend'), max_length=255, blank=False,
943
                                   default='astakos')
945
                                    default='astakos')
944 946
    info_data = models.TextField(default="", null=True, blank=True)
945 947
    created = models.DateTimeField('Creation date', auto_now_add=True)
946 948

  
......
959 961
        except Exception, e:
960 962
            self.info = {}
961 963

  
962
        for key,value in self.info.iteritems():
964
        for key, value in self.info.iteritems():
963 965
            setattr(self, 'info_%s' % key, value)
964 966

  
965 967
    @property
......
977 979

  
978 980
        extra_data['instance'] = self
979 981
        return auth.get_provider(self.module, self.user,
980
                                           self.identifier, **extra_data)
982
                                 self.identifier, **extra_data)
981 983

  
982 984
    def __repr__(self):
983
        return '<AstakosUserAuthProvider %s:%s>' % (self.module, self.identifier)
985
        return '<AstakosUserAuthProvider %s:%s>' % (
986
            self.module, self.identifier)
984 987

  
985 988
    def __unicode__(self):
986 989
        if self.identifier:
......
1055 1058
    code = models.BigIntegerField(_('Invitation code'), db_index=True)
1056 1059
    is_consumed = models.BooleanField(_('Consumed?'), default=False)
1057 1060
    created = models.DateTimeField(_('Creation date'), auto_now_add=True)
1058
    consumed = models.DateTimeField(_('Consumption date'), null=True, blank=True)
1061
    consumed = models.DateTimeField(_('Consumption date'),
1062
                                    null=True, blank=True)
1059 1063

  
1060 1064
    def __init__(self, *args, **kwargs):
1061 1065
        super(Invitation, self).__init__(*args, **kwargs)
......
1099 1103
                raise EmailChange.DoesNotExist
1100 1104
            # is there an active user with this address?
1101 1105
            try:
1102
                AstakosUser.objects.get(email__iexact=email_change.new_email_address)
1106
                AstakosUser.objects.get(
1107
                    email__iexact=email_change.new_email_address)
1103 1108
            except AstakosUser.DoesNotExist:
1104 1109
                pass
1105 1110
            else:
......
1135 1140

  
1136 1141
    def get_url(self):
1137 1142
        return reverse('email_change_confirm',
1138
                      kwargs={'activation_key': self.activation_key})
1143
                       kwargs={'activation_key': self.activation_key})
1139 1144

  
1140 1145
    def activation_key_expired(self):
1141
        expiration_date = timedelta(days=astakos_settings.EMAILCHANGE_ACTIVATION_DAYS)
1146
        expiration_date = timedelta(
1147
            days=astakos_settings.EMAILCHANGE_ACTIVATION_DAYS)
1142 1148
        return self.requested_at + expiration_date < datetime.now()
1143 1149

  
1144 1150

  
......
1173 1179
    """
1174 1180
    Model for registring successful third party user authentications
1175 1181
    """
1176
    third_party_identifier = models.CharField(_('Third-party identifier'), max_length=255, null=True, blank=True)
1182
    third_party_identifier = models.CharField(
1183
        _('Third-party identifier'), max_length=255, null=True, blank=True)
1177 1184
    provider = models.CharField(_('Provider'), max_length=255, blank=True)
1178 1185
    email = models.EmailField(_('e-mail address'), blank=True, null=True)
1179 1186
    first_name = models.CharField(_('first name'), max_length=30, blank=True,
......
1182 1189
                                 null=True)
1183 1190
    affiliation = models.CharField('Affiliation', max_length=255, blank=True,
1184 1191
                                   null=True)
1185
    username = models.CharField(_('username'), max_length=30, unique=True,
1186
                                help_text=_("Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"))
1192
    username = models.CharField(
1193
        _('username'), max_length=30, unique=True,
1194
        help_text=_("Required. 30 characters or fewer. "
1195
                    "Letters, numbers and @/./+/-/_ characters"))
1187 1196
    token = models.CharField(_('Token'), max_length=255, null=True, blank=True)
1188 1197
    created = models.DateTimeField(auto_now_add=True, null=True, blank=True)
1189 1198
    info = models.TextField(default="", null=True, blank=True)
......
1211 1220

  
1212 1221
    @property
1213 1222
    def realname(self):
1214
        return '%s %s' %(self.first_name, self.last_name)
1223
        return '%s %s' % (self.first_name, self.last_name)
1215 1224

  
1216 1225
    @realname.setter
1217 1226
    def realname(self, value):
......
1226 1235
        if not self.id:
1227 1236
            # set username
1228 1237
            while not self.username:
1229
                username =  uuid.uuid4().hex[:30]
1238
                username = uuid.uuid4().hex[:30]
1230 1239
                try:
1231
                    AstakosUser.objects.get(username = username)
1240
                    AstakosUser.objects.get(username=username)
1232 1241
                except AstakosUser.DoesNotExist, e:
1233 1242
                    self.username = username
1234 1243
        super(PendingThirdPartyUser, self).save(**kwargs)
......
1239 1248
        self.token = default_token_generator.make_token(self)
1240 1249

  
1241 1250
    def existing_user(self):
1242
        return AstakosUser.objects.filter(auth_providers__module=self.provider,
1243
                                         auth_providers__identifier=self.third_party_identifier)
1251
        return AstakosUser.objects.filter(
1252
            auth_providers__module=self.provider,
1253
            auth_providers__identifier=self.third_party_identifier)
1244 1254

  
1245 1255
    def get_provider(self, user):
1246 1256
        params = {
......
1250 1260
        return auth.get_provider(self.provider, user,
1251 1261
                                 self.third_party_identifier, **params)
1252 1262

  
1263

  
1253 1264
class SessionCatalog(models.Model):
1254 1265
    session_key = models.CharField(_('session key'), max_length=40)
1255 1266
    user = models.ForeignKey(AstakosUser, related_name='sessions', null=True)
......
1274 1285
    def search_by_name(self, *search_strings):
1275 1286
        projects = Project.objects.search_by_name(*search_strings)
1276 1287
        chains = [p.id for p in projects]
1277
        apps  = ProjectApplication.objects.search_by_name(*search_strings)
1288
        apps = ProjectApplication.objects.search_by_name(*search_strings)
1278 1289
        apps = (app for app in apps if app.is_latest())
1279 1290
        app_chains = [app.chain for app in apps if app.chain not in chains]
1280 1291
        return chains + app_chains
......
1309 1320

  
1310 1321

  
1311 1322
class Chain(models.Model):
1312
    chain  =   models.AutoField(primary_key=True)
1323
    chain = models.AutoField(primary_key=True)
1313 1324

  
1314 1325
    def __str__(self):
1315 1326
        return "%s" % (self.chain,)
1316 1327

  
1317 1328
    objects = ChainManager()
1318 1329

  
1319
    PENDING            = 0
1320
    DENIED             = 3
1321
    DISMISSED          = 4
1322
    CANCELLED          = 5
1330
    PENDING = 0
1331
    DENIED = 3
1332
    DISMISSED = 4
1333
    CANCELLED = 5
1323 1334

  
1324
    APPROVED           = 10
1325
    APPROVED_PENDING   = 11
1326
    SUSPENDED          = 12
1327
    SUSPENDED_PENDING  = 13
1328
    TERMINATED         = 14
1335
    APPROVED = 10
1336
    APPROVED_PENDING = 11
1337
    SUSPENDED = 12
1338
    SUSPENDED_PENDING = 13
1339
    TERMINATED = 14
1329 1340
    TERMINATED_PENDING = 15
1330 1341

  
1331 1342
    PENDING_STATES = [PENDING,
......
1353 1364
                   TERMINATED]
1354 1365

  
1355 1366
    STATE_DISPLAY = {
1356
        PENDING            : _("Pending"),
1357
        DENIED             : _("Denied"),
1358
        DISMISSED          : _("Dismissed"),
1359
        CANCELLED          : _("Cancelled"),
1360
        APPROVED           : _("Active"),
1361
        APPROVED_PENDING   : _("Active - Pending"),
1362
        SUSPENDED          : _("Suspended"),
1363
        SUSPENDED_PENDING  : _("Suspended - Pending"),
1364
        TERMINATED         : _("Terminated"),
1365
        TERMINATED_PENDING : _("Terminated - Pending"),
1366
        }
1367

  
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff