Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / forms.py @ c3132b4c

History | View | Annotate | Download (39.6 kB)

1 aba1e498 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 18ffbee1 Sofia Papagiannaki
#
3 64cd4730 Antony Chazapis
# Redistribution and use in source and binary forms, with or
4 64cd4730 Antony Chazapis
# without modification, are permitted provided that the following
5 64cd4730 Antony Chazapis
# conditions are met:
6 18ffbee1 Sofia Papagiannaki
#
7 64cd4730 Antony Chazapis
#   1. Redistributions of source code must retain the above
8 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
9 64cd4730 Antony Chazapis
#      disclaimer.
10 18ffbee1 Sofia Papagiannaki
#
11 64cd4730 Antony Chazapis
#   2. Redistributions in binary form must reproduce the above
12 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
13 64cd4730 Antony Chazapis
#      disclaimer in the documentation and/or other materials
14 64cd4730 Antony Chazapis
#      provided with the distribution.
15 18ffbee1 Sofia Papagiannaki
#
16 64cd4730 Antony Chazapis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 64cd4730 Antony Chazapis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 64cd4730 Antony Chazapis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 64cd4730 Antony Chazapis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 64cd4730 Antony Chazapis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 64cd4730 Antony Chazapis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 64cd4730 Antony Chazapis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 64cd4730 Antony Chazapis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 64cd4730 Antony Chazapis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 64cd4730 Antony Chazapis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 64cd4730 Antony Chazapis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 64cd4730 Antony Chazapis
# POSSIBILITY OF SUCH DAMAGE.
28 18ffbee1 Sofia Papagiannaki
#
29 64cd4730 Antony Chazapis
# The views and conclusions contained in the software and
30 64cd4730 Antony Chazapis
# documentation are those of the authors and should not be
31 64cd4730 Antony Chazapis
# interpreted as representing official policies, either expressed
32 64cd4730 Antony Chazapis
# or implied, of GRNET S.A.
33 8f378756 Sofia Papagiannaki
from urlparse import urljoin
34 caf70869 Sofia Papagiannaki
from random import random
35 69b26576 Sofia Papagiannaki
from datetime import datetime, timedelta
36 64cd4730 Antony Chazapis
37 64cd4730 Antony Chazapis
from django import forms
38 64cd4730 Antony Chazapis
from django.utils.translation import ugettext as _
39 e1a80257 Sofia Papagiannaki
from django.contrib.auth.forms import (
40 e1a80257 Sofia Papagiannaki
    UserCreationForm, AuthenticationForm,
41 e1a80257 Sofia Papagiannaki
    PasswordResetForm, PasswordChangeForm,
42 73fbaec4 Sofia Papagiannaki
    SetPasswordForm)
43 f9224cc0 Sofia Papagiannaki
from django.core.mail import send_mail, get_connection
44 e2125441 Sofia Papagiannaki
from django.contrib.auth.tokens import default_token_generator
45 e2125441 Sofia Papagiannaki
from django.template import Context, loader
46 e2125441 Sofia Papagiannaki
from django.utils.http import int_to_base36
47 374611bc Sofia Papagiannaki
from django.core.urlresolvers import reverse
48 18ffbee1 Sofia Papagiannaki
from django.utils.safestring import mark_safe
49 49790d9d Sofia Papagiannaki
from django.utils.encoding import smart_str
50 1cbce16f Sofia Papagiannaki
from django.conf import settings
51 678b2236 Sofia Papagiannaki
from django.forms.models import fields_for_model
52 d2633501 Kostas Papadimitriou
from django.db import transaction
53 caf70869 Sofia Papagiannaki
from django.utils.encoding import smart_unicode
54 caf70869 Sofia Papagiannaki
from django.core import validators
55 e1a80257 Sofia Papagiannaki
from django.contrib.auth.models import AnonymousUser
56 e47fb17a Sofia Papagiannaki
from django.core.exceptions import PermissionDenied
57 5ed6816e Sofia Papagiannaki
58 678b2236 Sofia Papagiannaki
from astakos.im.models import (
59 73fbaec4 Sofia Papagiannaki
    AstakosUser, EmailChange, Invitation,
60 e1a80257 Sofia Papagiannaki
    Resource, PendingThirdPartyUser, get_latest_terms, RESOURCE_SEPARATOR,
61 e47fb17a Sofia Papagiannaki
    ProjectApplication, Project)
62 c0b26605 Sofia Papagiannaki
from astakos.im.settings import (
63 c0b26605 Sofia Papagiannaki
    INVITATIONS_PER_LEVEL, BASEURL, SITENAME, RECAPTCHA_PRIVATE_KEY,
64 c0b26605 Sofia Papagiannaki
    RECAPTCHA_ENABLED, DEFAULT_CONTACT_EMAIL, LOGGING_LEVEL,
65 2e90e3ec Kostas Papadimitriou
    PASSWORD_RESET_EMAIL_SUBJECT, NEWPASSWD_INVALIDATE_TOKEN,
66 272cf735 Sofia Papagiannaki
    MODERATION_ENABLED, PROJECT_MEMBER_JOIN_POLICIES,
67 ec2e67f4 Kostas Papadimitriou
    PROJECT_MEMBER_LEAVE_POLICIES, EMAILCHANGE_ENABLED,
68 ec2e67f4 Kostas Papadimitriou
    RESOURCES_PRESENTATION_DATA)
69 45f8d9ff Sofia Papagiannaki
from astakos.im.widgets import DummyWidget, RecaptchaWidget
70 e47fb17a Sofia Papagiannaki
from astakos.im.functions import (
71 ff67242a Giorgos Korfiatis
    send_change_email, submit_application, accept_membership_checks)
72 270dd48d Sofia Papagiannaki
73 43332a76 Kostas Papadimitriou
from astakos.im.util import reserved_email, reserved_verified_email, \
74 43332a76 Kostas Papadimitriou
                            get_query, model_to_dict
75 c4b1a172 Kostas Papadimitriou
from astakos.im import auth_providers
76 64cd4730 Antony Chazapis
77 ae497612 Olga Brani
import astakos.im.messages as astakos_messages
78 64cd4730 Antony Chazapis
79 3bf924ec Sofia Papagiannaki
import logging
80 49790d9d Sofia Papagiannaki
import hashlib
81 db7fecd9 Sofia Papagiannaki
import recaptcha.client.captcha as captcha
82 caf70869 Sofia Papagiannaki
import re
83 64cd4730 Antony Chazapis
84 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
85 e015e9e6 Sofia Papagiannaki
86 caf70869 Sofia Papagiannaki
DOMAIN_VALUE_REGEX = re.compile(
87 892410d3 Sofia Papagiannaki
    r'^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$',
88 73fbaec4 Sofia Papagiannaki
    re.IGNORECASE)
89 d2633501 Kostas Papadimitriou
90 caf70869 Sofia Papagiannaki
class StoreUserMixin(object):
91 e5966bd9 Kostas Papadimitriou
92 d2633501 Kostas Papadimitriou
    def store_user(self, user, request):
93 43332a76 Kostas Papadimitriou
        """
94 43332a76 Kostas Papadimitriou
        WARNING: this should be wrapped inside a transactional view/method.
95 43332a76 Kostas Papadimitriou
        """
96 d2633501 Kostas Papadimitriou
        user.save()
97 d2633501 Kostas Papadimitriou
        self.post_store_user(user, request)
98 d2633501 Kostas Papadimitriou
        return user
99 d2633501 Kostas Papadimitriou
100 d2633501 Kostas Papadimitriou
    def post_store_user(self, user, request):
101 d2633501 Kostas Papadimitriou
        """
102 d2633501 Kostas Papadimitriou
        Interface method for descendant backends to be able to do stuff within
103 d2633501 Kostas Papadimitriou
        the transaction enabled by store_user.
104 d2633501 Kostas Papadimitriou
        """
105 d2633501 Kostas Papadimitriou
        pass
106 d2633501 Kostas Papadimitriou
107 d2633501 Kostas Papadimitriou
108 d2633501 Kostas Papadimitriou
class LocalUserCreationForm(UserCreationForm, StoreUserMixin):
109 890b0eaf Sofia Papagiannaki
    """
110 890b0eaf Sofia Papagiannaki
    Extends the built in UserCreationForm in several ways:
111 18ffbee1 Sofia Papagiannaki

112 e47fb17a Sofia Papagiannaki
    * Adds email, first_name, last_name, recaptcha_challenge_field,
113 e47fb17a Sofia Papagiannaki
    * recaptcha_response_field field.
114 5ed6816e Sofia Papagiannaki
    * The username field isn't visible and it is assigned a generated id.
115 18ffbee1 Sofia Papagiannaki
    * User created is not active.
116 890b0eaf Sofia Papagiannaki
    """
117 db7fecd9 Sofia Papagiannaki
    recaptcha_challenge_field = forms.CharField(widget=DummyWidget)
118 5ce3ce4f Sofia Papagiannaki
    recaptcha_response_field = forms.CharField(
119 5ce3ce4f Sofia Papagiannaki
        widget=RecaptchaWidget, label='')
120 18ffbee1 Sofia Papagiannaki
121 794852f2 Sofia Papagiannaki
    class Meta:
122 794852f2 Sofia Papagiannaki
        model = AstakosUser
123 5ce3ce4f Sofia Papagiannaki
        fields = ("email", "first_name", "last_name",
124 5ce3ce4f Sofia Papagiannaki
                  "has_signed_terms", "has_signed_terms")
125 18ffbee1 Sofia Papagiannaki
126 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
127 64cd4730 Antony Chazapis
        """
128 890b0eaf Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
129 64cd4730 Antony Chazapis
        """
130 bf0c6de5 Sofia Papagiannaki
        request = kwargs.pop('request', None)
131 672d445a Sofia Papagiannaki
        if request:
132 672d445a Sofia Papagiannaki
            self.ip = request.META.get('REMOTE_ADDR',
133 672d445a Sofia Papagiannaki
                                       request.META.get('HTTP_X_REAL_IP', None))
134 ab8bfb29 Kostas Papadimitriou
135 15efc749 Sofia Papagiannaki
        super(LocalUserCreationForm, self).__init__(*args, **kwargs)
136 890b0eaf Sofia Papagiannaki
        self.fields.keyOrder = ['email', 'first_name', 'last_name',
137 d8f63346 Sofia Papagiannaki
                                'password1', 'password2']
138 1b3398a0 Olga Brani
139 53bf2659 Sofia Papagiannaki
        if RECAPTCHA_ENABLED:
140 53bf2659 Sofia Papagiannaki
            self.fields.keyOrder.extend(['recaptcha_challenge_field',
141 5ce3ce4f Sofia Papagiannaki
                                         'recaptcha_response_field', ])
142 1b3398a0 Olga Brani
        if get_latest_terms():
143 1b3398a0 Olga Brani
            self.fields.keyOrder.append('has_signed_terms')
144 18ffbee1 Sofia Papagiannaki
145 18ffbee1 Sofia Papagiannaki
        if 'has_signed_terms' in self.fields:
146 18ffbee1 Sofia Papagiannaki
            # Overriding field label since we need to apply a link
147 18ffbee1 Sofia Papagiannaki
            # to the terms within the label
148 18ffbee1 Sofia Papagiannaki
            terms_link_html = '<a href="%s" target="_blank">%s</a>' \
149 5ce3ce4f Sofia Papagiannaki
                % (reverse('latest_terms'), _("the terms"))
150 18ffbee1 Sofia Papagiannaki
            self.fields['has_signed_terms'].label = \
151 5ce3ce4f Sofia Papagiannaki
                mark_safe("I agree with %s" % terms_link_html)
152 18ffbee1 Sofia Papagiannaki
153 af4eb974 Sofia Papagiannaki
    def clean_email(self):
154 e5966bd9 Kostas Papadimitriou
        email = self.cleaned_data['email']
155 881c856c Sofia Papagiannaki
        if not email:
156 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.REQUIRED_FIELD))
157 43332a76 Kostas Papadimitriou
        if reserved_verified_email(email):
158 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.EMAIL_USED))
159 0a569195 Sofia Papagiannaki
        return email
160 18ffbee1 Sofia Papagiannaki
161 270dd48d Sofia Papagiannaki
    def clean_has_signed_terms(self):
162 270dd48d Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
163 270dd48d Sofia Papagiannaki
        if not has_signed_terms:
164 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
165 270dd48d Sofia Papagiannaki
        return has_signed_terms
166 18ffbee1 Sofia Papagiannaki
167 db7fecd9 Sofia Papagiannaki
    def clean_recaptcha_response_field(self):
168 db7fecd9 Sofia Papagiannaki
        if 'recaptcha_challenge_field' in self.cleaned_data:
169 db7fecd9 Sofia Papagiannaki
            self.validate_captcha()
170 db7fecd9 Sofia Papagiannaki
        return self.cleaned_data['recaptcha_response_field']
171 db7fecd9 Sofia Papagiannaki
172 db7fecd9 Sofia Papagiannaki
    def clean_recaptcha_challenge_field(self):
173 db7fecd9 Sofia Papagiannaki
        if 'recaptcha_response_field' in self.cleaned_data:
174 db7fecd9 Sofia Papagiannaki
            self.validate_captcha()
175 db7fecd9 Sofia Papagiannaki
        return self.cleaned_data['recaptcha_challenge_field']
176 db7fecd9 Sofia Papagiannaki
177 db7fecd9 Sofia Papagiannaki
    def validate_captcha(self):
178 db7fecd9 Sofia Papagiannaki
        rcf = self.cleaned_data['recaptcha_challenge_field']
179 db7fecd9 Sofia Papagiannaki
        rrf = self.cleaned_data['recaptcha_response_field']
180 db7fecd9 Sofia Papagiannaki
        check = captcha.submit(rcf, rrf, RECAPTCHA_PRIVATE_KEY, self.ip)
181 db7fecd9 Sofia Papagiannaki
        if not check.is_valid:
182 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.CAPTCHA_VALIDATION_ERR))
183 18ffbee1 Sofia Papagiannaki
184 d2633501 Kostas Papadimitriou
    def post_store_user(self, user, request):
185 d2633501 Kostas Papadimitriou
        """
186 d2633501 Kostas Papadimitriou
        Interface method for descendant backends to be able to do stuff within
187 d2633501 Kostas Papadimitriou
        the transaction enabled by store_user.
188 d2633501 Kostas Papadimitriou
        """
189 d2633501 Kostas Papadimitriou
        user.add_auth_provider('local', auth_backend='astakos')
190 d2633501 Kostas Papadimitriou
        user.set_password(self.cleaned_data['password1'])
191 d2633501 Kostas Papadimitriou
192 890b0eaf Sofia Papagiannaki
    def save(self, commit=True):
193 64cd4730 Antony Chazapis
        """
194 890b0eaf Sofia Papagiannaki
        Saves the email, first_name and last_name properties, after the normal
195 890b0eaf Sofia Papagiannaki
        save behavior is complete.
196 890b0eaf Sofia Papagiannaki
        """
197 15efc749 Sofia Papagiannaki
        user = super(LocalUserCreationForm, self).save(commit=False)
198 d2633501 Kostas Papadimitriou
        user.renew_token()
199 9fb8e808 Sofia Papagiannaki
        if commit:
200 9fb8e808 Sofia Papagiannaki
            user.save()
201 aab4d540 Sofia Papagiannaki
            logger.log(LOGGING_LEVEL, 'Created user %s' % user.email)
202 890b0eaf Sofia Papagiannaki
        return user
203 64cd4730 Antony Chazapis
204 5ce3ce4f Sofia Papagiannaki
205 15efc749 Sofia Papagiannaki
class InvitedLocalUserCreationForm(LocalUserCreationForm):
206 890b0eaf Sofia Papagiannaki
    """
207 062c970c Sofia Papagiannaki
    Extends the LocalUserCreationForm: email is readonly.
208 890b0eaf Sofia Papagiannaki
    """
209 794852f2 Sofia Papagiannaki
    class Meta:
210 794852f2 Sofia Papagiannaki
        model = AstakosUser
211 270dd48d Sofia Papagiannaki
        fields = ("email", "first_name", "last_name", "has_signed_terms")
212 18ffbee1 Sofia Papagiannaki
213 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
214 64cd4730 Antony Chazapis
        """
215 3bf924ec Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
216 64cd4730 Antony Chazapis
        """
217 15efc749 Sofia Papagiannaki
        super(InvitedLocalUserCreationForm, self).__init__(*args, **kwargs)
218 18ffbee1 Sofia Papagiannaki
219 64cd4730 Antony Chazapis
        #set readonly form fields
220 062c970c Sofia Papagiannaki
        ro = ('email', 'username',)
221 4e30244e Sofia Papagiannaki
        for f in ro:
222 4e30244e Sofia Papagiannaki
            self.fields[f].widget.attrs['readonly'] = True
223 ab8bfb29 Kostas Papadimitriou
224 9fb8e808 Sofia Papagiannaki
    def save(self, commit=True):
225 15efc749 Sofia Papagiannaki
        user = super(InvitedLocalUserCreationForm, self).save(commit=False)
226 74836e50 Sofia Papagiannaki
        user.set_invitations_level()
227 8316698a Sofia Papagiannaki
        user.email_verified = True
228 9fb8e808 Sofia Papagiannaki
        if commit:
229 9fb8e808 Sofia Papagiannaki
            user.save()
230 9fb8e808 Sofia Papagiannaki
        return user
231 5ed6816e Sofia Papagiannaki
232 d2633501 Kostas Papadimitriou
233 d2633501 Kostas Papadimitriou
class ThirdPartyUserCreationForm(forms.ModelForm, StoreUserMixin):
234 6c8a3f7c Sofia Papagiannaki
    id = forms.CharField(
235 6c8a3f7c Sofia Papagiannaki
        widget=forms.HiddenInput(),
236 6c8a3f7c Sofia Papagiannaki
        label='',
237 6c8a3f7c Sofia Papagiannaki
        required=False
238 6c8a3f7c Sofia Papagiannaki
    )
239 ef20ea07 Sofia Papagiannaki
    third_party_identifier = forms.CharField(
240 ef20ea07 Sofia Papagiannaki
        widget=forms.HiddenInput(),
241 ef20ea07 Sofia Papagiannaki
        label=''
242 ef20ea07 Sofia Papagiannaki
    )
243 1177e91b Olga Brani
    email = forms.EmailField(
244 1177e91b Olga Brani
        label='Contact email',
245 d6ea9b3d Olga Brani
        help_text = 'This is needed for contact purposes. ' \
246 d6ea9b3d Olga Brani
        'It doesn&#39;t need to be the same with the one you ' \
247 d6ea9b3d Olga Brani
        'provided to login previously. '
248 1177e91b Olga Brani
    )
249 43332a76 Kostas Papadimitriou
250 8f5a3a06 Sofia Papagiannaki
    class Meta:
251 8f5a3a06 Sofia Papagiannaki
        model = AstakosUser
252 a1d151a8 Kostas Papadimitriou
        fields = ['id', 'email', 'third_party_identifier',
253 a1d151a8 Kostas Papadimitriou
                  'first_name', 'last_name', 'has_signed_terms']
254 ab8bfb29 Kostas Papadimitriou
255 8f5a3a06 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
256 8f5a3a06 Sofia Papagiannaki
        """
257 8f5a3a06 Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
258 8f5a3a06 Sofia Papagiannaki
        """
259 0a569195 Sofia Papagiannaki
        self.request = kwargs.get('request', None)
260 0a569195 Sofia Papagiannaki
        if self.request:
261 0a569195 Sofia Papagiannaki
            kwargs.pop('request')
262 2e90e3ec Kostas Papadimitriou
263 8f5a3a06 Sofia Papagiannaki
        super(ThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
264 2e90e3ec Kostas Papadimitriou
265 4a13d054 Kostas Papadimitriou
        if not get_latest_terms():
266 4a13d054 Kostas Papadimitriou
            del self.fields['has_signed_terms']
267 4a13d054 Kostas Papadimitriou
268 18ffbee1 Sofia Papagiannaki
        if 'has_signed_terms' in self.fields:
269 18ffbee1 Sofia Papagiannaki
            # Overriding field label since we need to apply a link
270 18ffbee1 Sofia Papagiannaki
            # to the terms within the label
271 18ffbee1 Sofia Papagiannaki
            terms_link_html = '<a href="%s" target="_blank">%s</a>' \
272 5ce3ce4f Sofia Papagiannaki
                % (reverse('latest_terms'), _("the terms"))
273 18ffbee1 Sofia Papagiannaki
            self.fields['has_signed_terms'].label = \
274 18ffbee1 Sofia Papagiannaki
                    mark_safe("I agree with %s" % terms_link_html)
275 2e90e3ec Kostas Papadimitriou
276 18ffbee1 Sofia Papagiannaki
    def clean_email(self):
277 e5966bd9 Kostas Papadimitriou
        email = self.cleaned_data['email']
278 18ffbee1 Sofia Papagiannaki
        if not email:
279 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.REQUIRED_FIELD))
280 43332a76 Kostas Papadimitriou
        if reserved_verified_email(email):
281 564a2292 Kostas Papadimitriou
            provider = auth_providers.get_provider(self.request.REQUEST.get('provider', 'local'))
282 564a2292 Kostas Papadimitriou
            extra_message = _(astakos_messages.EXISTING_EMAIL_THIRD_PARTY_NOTIFICATION) % \
283 564a2292 Kostas Papadimitriou
                    (provider.get_title_display, reverse('edit_profile'))
284 564a2292 Kostas Papadimitriou
285 564a2292 Kostas Papadimitriou
            raise forms.ValidationError(_(astakos_messages.EMAIL_USED) + ' ' + \
286 564a2292 Kostas Papadimitriou
                                        extra_message)
287 0a569195 Sofia Papagiannaki
        return email
288 ab8bfb29 Kostas Papadimitriou
289 18ffbee1 Sofia Papagiannaki
    def clean_has_signed_terms(self):
290 18ffbee1 Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
291 18ffbee1 Sofia Papagiannaki
        if not has_signed_terms:
292 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
293 18ffbee1 Sofia Papagiannaki
        return has_signed_terms
294 ab8bfb29 Kostas Papadimitriou
295 d2633501 Kostas Papadimitriou
    def post_store_user(self, user, request):
296 d2633501 Kostas Papadimitriou
        pending = PendingThirdPartyUser.objects.get(
297 d2633501 Kostas Papadimitriou
                                token=request.POST.get('third_party_token'),
298 d2633501 Kostas Papadimitriou
                                third_party_identifier= \
299 43332a76 Kostas Papadimitriou
                            self.cleaned_data.get('third_party_identifier'))
300 d2633501 Kostas Papadimitriou
        return user.add_pending_auth_provider(pending)
301 d2633501 Kostas Papadimitriou
302 8f5a3a06 Sofia Papagiannaki
    def save(self, commit=True):
303 8f5a3a06 Sofia Papagiannaki
        user = super(ThirdPartyUserCreationForm, self).save(commit=False)
304 8f5a3a06 Sofia Papagiannaki
        user.set_unusable_password()
305 d2633501 Kostas Papadimitriou
        user.renew_token()
306 8f5a3a06 Sofia Papagiannaki
        if commit:
307 8f5a3a06 Sofia Papagiannaki
            user.save()
308 aab4d540 Sofia Papagiannaki
            logger.log(LOGGING_LEVEL, 'Created user %s' % user.email)
309 8f5a3a06 Sofia Papagiannaki
        return user
310 8f5a3a06 Sofia Papagiannaki
311 5ce3ce4f Sofia Papagiannaki
312 8f5a3a06 Sofia Papagiannaki
class InvitedThirdPartyUserCreationForm(ThirdPartyUserCreationForm):
313 4e30244e Sofia Papagiannaki
    """
314 062c970c Sofia Papagiannaki
    Extends the ThirdPartyUserCreationForm: email is readonly.
315 4e30244e Sofia Papagiannaki
    """
316 8f5a3a06 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
317 4e30244e Sofia Papagiannaki
        """
318 4e30244e Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
319 4e30244e Sofia Papagiannaki
        """
320 5ce3ce4f Sofia Papagiannaki
        super(
321 5ce3ce4f Sofia Papagiannaki
            InvitedThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
322 4e30244e Sofia Papagiannaki
323 8f5a3a06 Sofia Papagiannaki
        #set readonly form fields
324 062c970c Sofia Papagiannaki
        ro = ('email',)
325 4e30244e Sofia Papagiannaki
        for f in ro:
326 4e30244e Sofia Papagiannaki
            self.fields[f].widget.attrs['readonly'] = True
327 ab8bfb29 Kostas Papadimitriou
328 4e30244e Sofia Papagiannaki
    def save(self, commit=True):
329 4e30244e Sofia Papagiannaki
        user = super(InvitedThirdPartyUserCreationForm, self).save(commit=False)
330 d2633501 Kostas Papadimitriou
        user.set_invitation_level()
331 4e30244e Sofia Papagiannaki
        user.email_verified = True
332 4e30244e Sofia Papagiannaki
        if commit:
333 4e30244e Sofia Papagiannaki
            user.save()
334 4e30244e Sofia Papagiannaki
        return user
335 8f5a3a06 Sofia Papagiannaki
336 5ce3ce4f Sofia Papagiannaki
337 18ffbee1 Sofia Papagiannaki
class ShibbolethUserCreationForm(ThirdPartyUserCreationForm):
338 5ce3ce4f Sofia Papagiannaki
    additional_email = forms.CharField(
339 5ce3ce4f Sofia Papagiannaki
        widget=forms.HiddenInput(), label='', required=False)
340 ab8bfb29 Kostas Papadimitriou
341 ca828a10 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
342 ca828a10 Sofia Papagiannaki
        super(ShibbolethUserCreationForm, self).__init__(*args, **kwargs)
343 ca828a10 Sofia Papagiannaki
        # copy email value to additional_mail in case user will change it
344 ca828a10 Sofia Papagiannaki
        name = 'email'
345 ca828a10 Sofia Papagiannaki
        field = self.fields[name]
346 ca828a10 Sofia Papagiannaki
        self.initial['additional_email'] = self.initial.get(name, field.initial)
347 ef20ea07 Sofia Papagiannaki
        self.initial['email'] = None
348 d2633501 Kostas Papadimitriou
349 4e30244e Sofia Papagiannaki
350 9a06d96f Olga Brani
class InvitedShibbolethUserCreationForm(ShibbolethUserCreationForm,
351 9a06d96f Olga Brani
                                        InvitedThirdPartyUserCreationForm):
352 4e30244e Sofia Papagiannaki
    pass
353 ab8bfb29 Kostas Papadimitriou
354 5ce3ce4f Sofia Papagiannaki
355 5ed6816e Sofia Papagiannaki
class LoginForm(AuthenticationForm):
356 5ed6816e Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
357 672d445a Sofia Papagiannaki
    recaptcha_challenge_field = forms.CharField(widget=DummyWidget)
358 5ce3ce4f Sofia Papagiannaki
    recaptcha_response_field = forms.CharField(
359 5ce3ce4f Sofia Papagiannaki
        widget=RecaptchaWidget, label='')
360 ab8bfb29 Kostas Papadimitriou
361 672d445a Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
362 672d445a Sofia Papagiannaki
        was_limited = kwargs.get('was_limited', False)
363 672d445a Sofia Papagiannaki
        request = kwargs.get('request', None)
364 672d445a Sofia Papagiannaki
        if request:
365 672d445a Sofia Papagiannaki
            self.ip = request.META.get('REMOTE_ADDR',
366 672d445a Sofia Papagiannaki
                                       request.META.get('HTTP_X_REAL_IP', None))
367 ab8bfb29 Kostas Papadimitriou
368 672d445a Sofia Papagiannaki
        t = ('request', 'was_limited')
369 672d445a Sofia Papagiannaki
        for elem in t:
370 672d445a Sofia Papagiannaki
            if elem in kwargs.keys():
371 672d445a Sofia Papagiannaki
                kwargs.pop(elem)
372 672d445a Sofia Papagiannaki
        super(LoginForm, self).__init__(*args, **kwargs)
373 ab8bfb29 Kostas Papadimitriou
374 672d445a Sofia Papagiannaki
        self.fields.keyOrder = ['username', 'password']
375 672d445a Sofia Papagiannaki
        if was_limited and RECAPTCHA_ENABLED:
376 672d445a Sofia Papagiannaki
            self.fields.keyOrder.extend(['recaptcha_challenge_field',
377 5ce3ce4f Sofia Papagiannaki
                                         'recaptcha_response_field', ])
378 9a06d96f Olga Brani
379 9a06d96f Olga Brani
    def clean_username(self):
380 4bdd7e3d Kostas Papadimitriou
        return self.cleaned_data['username'].lower()
381 ab8bfb29 Kostas Papadimitriou
382 672d445a Sofia Papagiannaki
    def clean_recaptcha_response_field(self):
383 672d445a Sofia Papagiannaki
        if 'recaptcha_challenge_field' in self.cleaned_data:
384 672d445a Sofia Papagiannaki
            self.validate_captcha()
385 672d445a Sofia Papagiannaki
        return self.cleaned_data['recaptcha_response_field']
386 672d445a Sofia Papagiannaki
387 672d445a Sofia Papagiannaki
    def clean_recaptcha_challenge_field(self):
388 672d445a Sofia Papagiannaki
        if 'recaptcha_response_field' in self.cleaned_data:
389 672d445a Sofia Papagiannaki
            self.validate_captcha()
390 672d445a Sofia Papagiannaki
        return self.cleaned_data['recaptcha_challenge_field']
391 672d445a Sofia Papagiannaki
392 672d445a Sofia Papagiannaki
    def validate_captcha(self):
393 672d445a Sofia Papagiannaki
        rcf = self.cleaned_data['recaptcha_challenge_field']
394 672d445a Sofia Papagiannaki
        rrf = self.cleaned_data['recaptcha_response_field']
395 672d445a Sofia Papagiannaki
        check = captcha.submit(rcf, rrf, RECAPTCHA_PRIVATE_KEY, self.ip)
396 672d445a Sofia Papagiannaki
        if not check.is_valid:
397 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.CAPTCHA_VALIDATION_ERR))
398 2e90e3ec Kostas Papadimitriou
399 eedb3923 Sofia Papagiannaki
    def clean(self):
400 1f3b4b39 Sofia Papagiannaki
        """
401 1f3b4b39 Sofia Papagiannaki
        Override default behavior in order to check user's activation later
402 1f3b4b39 Sofia Papagiannaki
        """
403 c4b1a172 Kostas Papadimitriou
        username = self.cleaned_data.get('username')
404 c4b1a172 Kostas Papadimitriou
405 bea8a810 Kostas Papadimitriou
        if username:
406 bea8a810 Kostas Papadimitriou
            try:
407 bea8a810 Kostas Papadimitriou
                user = AstakosUser.objects.get_by_identifier(username)
408 bea8a810 Kostas Papadimitriou
                if not user.has_auth_provider('local'):
409 bea8a810 Kostas Papadimitriou
                    provider = auth_providers.get_provider('local')
410 bea8a810 Kostas Papadimitriou
                    raise forms.ValidationError(
411 bea8a810 Kostas Papadimitriou
                        _(provider.get_message('NOT_ACTIVE_FOR_USER')))
412 bea8a810 Kostas Papadimitriou
            except AstakosUser.DoesNotExist:
413 bea8a810 Kostas Papadimitriou
                pass
414 c4b1a172 Kostas Papadimitriou
415 1f3b4b39 Sofia Papagiannaki
        try:
416 1f3b4b39 Sofia Papagiannaki
            super(LoginForm, self).clean()
417 1f3b4b39 Sofia Papagiannaki
        except forms.ValidationError, e:
418 c4b1a172 Kostas Papadimitriou
            if self.user_cache is None:
419 c4b1a172 Kostas Papadimitriou
                raise
420 c4b1a172 Kostas Papadimitriou
            if not self.user_cache.is_active:
421 c4b1a172 Kostas Papadimitriou
                raise forms.ValidationError(self.user_cache.get_inactive_message())
422 1f3b4b39 Sofia Papagiannaki
            if self.request:
423 1f3b4b39 Sofia Papagiannaki
                if not self.request.session.test_cookie_worked():
424 1f3b4b39 Sofia Papagiannaki
                    raise
425 eedb3923 Sofia Papagiannaki
        return self.cleaned_data
426 64cd4730 Antony Chazapis
427 5ce3ce4f Sofia Papagiannaki
428 890b0eaf Sofia Papagiannaki
class ProfileForm(forms.ModelForm):
429 890b0eaf Sofia Papagiannaki
    """
430 890b0eaf Sofia Papagiannaki
    Subclass of ``ModelForm`` for permiting user to edit his/her profile.
431 9a06d96f Olga Brani
    Most of the fields are readonly since the user is not allowed to change
432 9a06d96f Olga Brani
    them.
433 18ffbee1 Sofia Papagiannaki

434 9a06d96f Olga Brani
    The class defines a save method which sets ``is_verified`` to True so as the
435 9a06d96f Olga Brani
    user during the next login will not to be redirected to profile page.
436 890b0eaf Sofia Papagiannaki
    """
437 f911f6d3 Kostas Papadimitriou
    email = forms.EmailField(label='E-mail address', help_text='E-mail address')
438 c301698f Sofia Papagiannaki
    renew = forms.BooleanField(label='Renew token', required=False)
439 ccaadd41 Sofia Papagiannaki
    uuid = forms.CharField(label='User id', required=False)
440 18ffbee1 Sofia Papagiannaki
441 890b0eaf Sofia Papagiannaki
    class Meta:
442 890b0eaf Sofia Papagiannaki
        model = AstakosUser
443 5ce3ce4f Sofia Papagiannaki
        fields = ('email', 'first_name', 'last_name', 'auth_token',
444 ccaadd41 Sofia Papagiannaki
                  'auth_token_expires', 'uuid')
445 18ffbee1 Sofia Papagiannaki
446 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
447 bf0c6de5 Sofia Papagiannaki
        self.session_key = kwargs.pop('session_key', None)
448 890b0eaf Sofia Papagiannaki
        super(ProfileForm, self).__init__(*args, **kwargs)
449 890b0eaf Sofia Papagiannaki
        instance = getattr(self, 'instance', None)
450 ccaadd41 Sofia Papagiannaki
        ro_fields = ('email', 'auth_token', 'auth_token_expires', 'uuid')
451 890b0eaf Sofia Papagiannaki
        if instance and instance.id:
452 890b0eaf Sofia Papagiannaki
            for field in ro_fields:
453 890b0eaf Sofia Papagiannaki
                self.fields[field].widget.attrs['readonly'] = True
454 18ffbee1 Sofia Papagiannaki
455 890b0eaf Sofia Papagiannaki
    def save(self, commit=True):
456 890b0eaf Sofia Papagiannaki
        user = super(ProfileForm, self).save(commit=False)
457 890b0eaf Sofia Papagiannaki
        user.is_verified = True
458 c301698f Sofia Papagiannaki
        if self.cleaned_data.get('renew'):
459 bf0c6de5 Sofia Papagiannaki
            user.renew_token(
460 bf0c6de5 Sofia Papagiannaki
                flush_sessions=True,
461 bf0c6de5 Sofia Papagiannaki
                current_key=self.session_key
462 bf0c6de5 Sofia Papagiannaki
            )
463 890b0eaf Sofia Papagiannaki
        if commit:
464 890b0eaf Sofia Papagiannaki
            user.save()
465 890b0eaf Sofia Papagiannaki
        return user
466 64cd4730 Antony Chazapis
467 5ce3ce4f Sofia Papagiannaki
468 f7400729 Kostas Papadimitriou
469 890b0eaf Sofia Papagiannaki
class FeedbackForm(forms.Form):
470 890b0eaf Sofia Papagiannaki
    """
471 890b0eaf Sofia Papagiannaki
    Form for writing feedback.
472 890b0eaf Sofia Papagiannaki
    """
473 0a569195 Sofia Papagiannaki
    feedback_msg = forms.CharField(widget=forms.Textarea, label=u'Message')
474 8f5a3a06 Sofia Papagiannaki
    feedback_data = forms.CharField(widget=forms.HiddenInput(), label='',
475 8f5a3a06 Sofia Papagiannaki
                                    required=False)
476 5ed6816e Sofia Papagiannaki
477 5ce3ce4f Sofia Papagiannaki
478 5ed6816e Sofia Papagiannaki
class SendInvitationForm(forms.Form):
479 5ed6816e Sofia Papagiannaki
    """
480 5ed6816e Sofia Papagiannaki
    Form for sending an invitations
481 5ed6816e Sofia Papagiannaki
    """
482 18ffbee1 Sofia Papagiannaki
483 5ce3ce4f Sofia Papagiannaki
    email = forms.EmailField(required=True, label='Email address')
484 5ce3ce4f Sofia Papagiannaki
    first_name = forms.EmailField(label='First name')
485 5ce3ce4f Sofia Papagiannaki
    last_name = forms.EmailField(label='Last name')
486 5ce3ce4f Sofia Papagiannaki
487 e2125441 Sofia Papagiannaki
488 e2125441 Sofia Papagiannaki
class ExtendedPasswordResetForm(PasswordResetForm):
489 e2125441 Sofia Papagiannaki
    """
490 dd5f8f4d Kostas Papadimitriou
    Extends PasswordResetForm by overriding
491 18ffbee1 Sofia Papagiannaki

492 dd5f8f4d Kostas Papadimitriou
    save method: to pass a custom from_email in send_mail.
493 dd5f8f4d Kostas Papadimitriou
    clean_email: to handle local auth provider checks
494 e2125441 Sofia Papagiannaki
    """
495 23c271b3 Sofia Papagiannaki
    def clean_email(self):
496 23c271b3 Sofia Papagiannaki
        email = super(ExtendedPasswordResetForm, self).clean_email()
497 23c271b3 Sofia Papagiannaki
        try:
498 dd5f8f4d Kostas Papadimitriou
            user = AstakosUser.objects.get_by_identifier(email)
499 dd5f8f4d Kostas Papadimitriou
500 dd5f8f4d Kostas Papadimitriou
            if not user.is_active:
501 dd5f8f4d Kostas Papadimitriou
                raise forms.ValidationError(_(astakos_messages.ACCOUNT_INACTIVE))
502 dd5f8f4d Kostas Papadimitriou
503 23c271b3 Sofia Papagiannaki
            if not user.has_usable_password():
504 260f1021 Kostas Papadimitriou
                provider = auth_providers.get_provider('local')
505 260f1021 Kostas Papadimitriou
                available_providers = user.auth_providers.all()
506 260f1021 Kostas Papadimitriou
                available_providers = ",".join(p.settings.get_title_display for p in \
507 260f1021 Kostas Papadimitriou
                                                   available_providers)
508 260f1021 Kostas Papadimitriou
                message = astakos_messages.UNUSABLE_PASSWORD % \
509 260f1021 Kostas Papadimitriou
                    (provider.get_method_prompt_display, available_providers)
510 260f1021 Kostas Papadimitriou
                raise forms.ValidationError(message)
511 d2633501 Kostas Papadimitriou
512 d2633501 Kostas Papadimitriou
            if not user.can_change_password():
513 dd5f8f4d Kostas Papadimitriou
                raise forms.ValidationError(_(astakos_messages.AUTH_PROVIDER_CANNOT_CHANGE_PASSWORD))
514 23c271b3 Sofia Papagiannaki
        except AstakosUser.DoesNotExist, e:
515 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.EMAIL_UNKNOWN))
516 23c271b3 Sofia Papagiannaki
        return email
517 ab8bfb29 Kostas Papadimitriou
518 5ce3ce4f Sofia Papagiannaki
    def save(
519 5ce3ce4f Sofia Papagiannaki
        self, domain_override=None, email_template_name='registration/password_reset_email.html',
520 5ce3ce4f Sofia Papagiannaki
            use_https=False, token_generator=default_token_generator, request=None):
521 e2125441 Sofia Papagiannaki
        """
522 e2125441 Sofia Papagiannaki
        Generates a one-use only link for resetting password and sends to the user.
523 e2125441 Sofia Papagiannaki
        """
524 e2125441 Sofia Papagiannaki
        for user in self.users_cache:
525 d2633501 Kostas Papadimitriou
            url = user.astakosuser.get_password_reset_url(token_generator)
526 a53b19da Sofia Papagiannaki
            url = urljoin(BASEURL, url)
527 e2125441 Sofia Papagiannaki
            t = loader.get_template(email_template_name)
528 e2125441 Sofia Papagiannaki
            c = {
529 e2125441 Sofia Papagiannaki
                'email': user.email,
530 8f378756 Sofia Papagiannaki
                'url': url,
531 374611bc Sofia Papagiannaki
                'site_name': SITENAME,
532 e2125441 Sofia Papagiannaki
                'user': user,
533 a53b19da Sofia Papagiannaki
                'baseurl': BASEURL,
534 09122dd8 Sofia Papagiannaki
                'support': DEFAULT_CONTACT_EMAIL
535 e2125441 Sofia Papagiannaki
            }
536 1cbce16f Sofia Papagiannaki
            from_email = settings.SERVER_EMAIL
537 1fcf4a99 Kostas Papadimitriou
            send_mail(_(PASSWORD_RESET_EMAIL_SUBJECT),
538 f9224cc0 Sofia Papagiannaki
                      t.render(Context(c)),
539 f9224cc0 Sofia Papagiannaki
                      from_email,
540 f9224cc0 Sofia Papagiannaki
                      [user.email],
541 28f4439f Sofia Papagiannaki
                      connection=get_connection())
542 5ce3ce4f Sofia Papagiannaki
543 270dd48d Sofia Papagiannaki
544 49790d9d Sofia Papagiannaki
class EmailChangeForm(forms.ModelForm):
545 34a76cdb Kostas Papadimitriou
546 49790d9d Sofia Papagiannaki
    class Meta:
547 49790d9d Sofia Papagiannaki
        model = EmailChange
548 49790d9d Sofia Papagiannaki
        fields = ('new_email_address',)
549 ab8bfb29 Kostas Papadimitriou
550 49790d9d Sofia Papagiannaki
    def clean_new_email_address(self):
551 49790d9d Sofia Papagiannaki
        addr = self.cleaned_data['new_email_address']
552 43332a76 Kostas Papadimitriou
        if reserved_verified_email(addr):
553 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.EMAIL_USED))
554 49790d9d Sofia Papagiannaki
        return addr
555 ab8bfb29 Kostas Papadimitriou
556 3fbf7863 Kostas Papadimitriou
    def save(self, request, email_template_name='registration/email_change_email.txt', commit=True):
557 49790d9d Sofia Papagiannaki
        ec = super(EmailChangeForm, self).save(commit=False)
558 49790d9d Sofia Papagiannaki
        ec.user = request.user
559 3fbf7863 Kostas Papadimitriou
        # delete pending email changes
560 3fbf7863 Kostas Papadimitriou
        request.user.emailchanges.all().delete()
561 3fbf7863 Kostas Papadimitriou
562 5ce3ce4f Sofia Papagiannaki
        activation_key = hashlib.sha1(
563 5ce3ce4f Sofia Papagiannaki
            str(random()) + smart_str(ec.new_email_address))
564 5ce3ce4f Sofia Papagiannaki
        ec.activation_key = activation_key.hexdigest()
565 49790d9d Sofia Papagiannaki
        if commit:
566 49790d9d Sofia Papagiannaki
            ec.save()
567 49790d9d Sofia Papagiannaki
        send_change_email(ec, request, email_template_name=email_template_name)
568 49790d9d Sofia Papagiannaki
569 5ce3ce4f Sofia Papagiannaki
570 270dd48d Sofia Papagiannaki
class SignApprovalTermsForm(forms.ModelForm):
571 34a76cdb Kostas Papadimitriou
572 270dd48d Sofia Papagiannaki
    class Meta:
573 270dd48d Sofia Papagiannaki
        model = AstakosUser
574 270dd48d Sofia Papagiannaki
        fields = ("has_signed_terms",)
575 18ffbee1 Sofia Papagiannaki
576 270dd48d Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
577 270dd48d Sofia Papagiannaki
        super(SignApprovalTermsForm, self).__init__(*args, **kwargs)
578 18ffbee1 Sofia Papagiannaki
579 270dd48d Sofia Papagiannaki
    def clean_has_signed_terms(self):
580 270dd48d Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
581 270dd48d Sofia Papagiannaki
        if not has_signed_terms:
582 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
583 270dd48d Sofia Papagiannaki
        return has_signed_terms
584 8f5a3a06 Sofia Papagiannaki
585 5ce3ce4f Sofia Papagiannaki
586 8f5a3a06 Sofia Papagiannaki
class InvitationForm(forms.ModelForm):
587 34a76cdb Kostas Papadimitriou
588 8f5a3a06 Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
589 ab8bfb29 Kostas Papadimitriou
590 18ffbee1 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
591 18ffbee1 Sofia Papagiannaki
        super(InvitationForm, self).__init__(*args, **kwargs)
592 ab8bfb29 Kostas Papadimitriou
593 8f5a3a06 Sofia Papagiannaki
    class Meta:
594 8f5a3a06 Sofia Papagiannaki
        model = Invitation
595 8f5a3a06 Sofia Papagiannaki
        fields = ('username', 'realname')
596 ab8bfb29 Kostas Papadimitriou
597 8f5a3a06 Sofia Papagiannaki
    def clean_username(self):
598 8f5a3a06 Sofia Papagiannaki
        username = self.cleaned_data['username']
599 8f5a3a06 Sofia Papagiannaki
        try:
600 5ce3ce4f Sofia Papagiannaki
            Invitation.objects.get(username=username)
601 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.INVITATION_EMAIL_EXISTS))
602 8f5a3a06 Sofia Papagiannaki
        except Invitation.DoesNotExist:
603 8f5a3a06 Sofia Papagiannaki
            pass
604 18ffbee1 Sofia Papagiannaki
        return username
605 1039bab1 Sofia Papagiannaki
606 5ce3ce4f Sofia Papagiannaki
607 1039bab1 Sofia Papagiannaki
class ExtendedPasswordChangeForm(PasswordChangeForm):
608 1039bab1 Sofia Papagiannaki
    """
609 1039bab1 Sofia Papagiannaki
    Extends PasswordChangeForm by enabling user
610 1039bab1 Sofia Papagiannaki
    to optionally renew also the token.
611 1039bab1 Sofia Papagiannaki
    """
612 ee210d1d Sofia Papagiannaki
    if not NEWPASSWD_INVALIDATE_TOKEN:
613 48e9f076 Sofia Papagiannaki
        renew = forms.BooleanField(label='Renew token', required=False,
614 48e9f076 Sofia Papagiannaki
                                   initial=True,
615 48e9f076 Sofia Papagiannaki
                                   help_text='Unsetting this may result in security risk.')
616 ab8bfb29 Kostas Papadimitriou
617 1039bab1 Sofia Papagiannaki
    def __init__(self, user, *args, **kwargs):
618 bf0c6de5 Sofia Papagiannaki
        self.session_key = kwargs.pop('session_key', None)
619 1039bab1 Sofia Papagiannaki
        super(ExtendedPasswordChangeForm, self).__init__(user, *args, **kwargs)
620 ab8bfb29 Kostas Papadimitriou
621 1039bab1 Sofia Papagiannaki
    def save(self, commit=True):
622 bf0c6de5 Sofia Papagiannaki
        try:
623 bf0c6de5 Sofia Papagiannaki
            if NEWPASSWD_INVALIDATE_TOKEN or self.cleaned_data.get('renew'):
624 bf0c6de5 Sofia Papagiannaki
                self.user.renew_token()
625 bf0c6de5 Sofia Papagiannaki
            self.user.flush_sessions(current_key=self.session_key)
626 bf0c6de5 Sofia Papagiannaki
        except AttributeError:
627 bf0c6de5 Sofia Papagiannaki
            # if user model does has not such methods
628 bf0c6de5 Sofia Papagiannaki
            pass
629 53161dd8 Sofia Papagiannaki
        return super(ExtendedPasswordChangeForm, self).save(commit=commit)
630 48e9f076 Sofia Papagiannaki
631 48e9f076 Sofia Papagiannaki
class ExtendedSetPasswordForm(SetPasswordForm):
632 48e9f076 Sofia Papagiannaki
    """
633 48e9f076 Sofia Papagiannaki
    Extends SetPasswordForm by enabling user
634 48e9f076 Sofia Papagiannaki
    to optionally renew also the token.
635 48e9f076 Sofia Papagiannaki
    """
636 ee210d1d Sofia Papagiannaki
    if not NEWPASSWD_INVALIDATE_TOKEN:
637 bf0c6de5 Sofia Papagiannaki
        renew = forms.BooleanField(
638 bf0c6de5 Sofia Papagiannaki
            label='Renew token',
639 bf0c6de5 Sofia Papagiannaki
            required=False,
640 bf0c6de5 Sofia Papagiannaki
            initial=True,
641 47b77c8b Sofia Papagiannaki
            help_text='Unsetting this may result in security risk.')
642 2e90e3ec Kostas Papadimitriou
643 48e9f076 Sofia Papagiannaki
    def __init__(self, user, *args, **kwargs):
644 48e9f076 Sofia Papagiannaki
        super(ExtendedSetPasswordForm, self).__init__(user, *args, **kwargs)
645 d2633501 Kostas Papadimitriou
646 d2633501 Kostas Papadimitriou
    @transaction.commit_on_success()
647 48e9f076 Sofia Papagiannaki
    def save(self, commit=True):
648 bf0c6de5 Sofia Papagiannaki
        try:
649 bf0c6de5 Sofia Papagiannaki
            self.user = AstakosUser.objects.get(id=self.user.id)
650 bf0c6de5 Sofia Papagiannaki
            if NEWPASSWD_INVALIDATE_TOKEN or self.cleaned_data.get('renew'):
651 53161dd8 Sofia Papagiannaki
                self.user.renew_token()
652 d2633501 Kostas Papadimitriou
            #self.user.flush_sessions()
653 d2633501 Kostas Papadimitriou
            if not self.user.has_auth_provider('local'):
654 d2633501 Kostas Papadimitriou
                self.user.add_auth_provider('local', auth_backend='astakos')
655 d2633501 Kostas Papadimitriou
656 bf0c6de5 Sofia Papagiannaki
        except BaseException, e:
657 bf0c6de5 Sofia Papagiannaki
            logger.exception(e)
658 53161dd8 Sofia Papagiannaki
        return super(ExtendedSetPasswordForm, self).save(commit=commit)
659 e1a80257 Sofia Papagiannaki
660 e1a80257 Sofia Papagiannaki
661 67980f56 Georgios D. Tsoukalas
662 67980f56 Georgios D. Tsoukalas
663 67980f56 Georgios D. Tsoukalas
app_name_label       =  "Project name"
664 67980f56 Georgios D. Tsoukalas
app_name_placeholder = _("myproject.mylab.ntua.gr")
665 67980f56 Georgios D. Tsoukalas
app_name_validator   =  validators.RegexValidator(
666 67980f56 Georgios D. Tsoukalas
                            DOMAIN_VALUE_REGEX,
667 67980f56 Georgios D. Tsoukalas
                            _(astakos_messages.DOMAIN_VALUE_ERR),
668 67980f56 Georgios D. Tsoukalas
                            'invalid')
669 67980f56 Georgios D. Tsoukalas
app_name_help        =  _("""
670 67980f56 Georgios D. Tsoukalas
        The Project's name should be in a domain format.
671 67980f56 Georgios D. Tsoukalas
        The domain shouldn't neccessarily exist in the real
672 67980f56 Georgios D. Tsoukalas
        world but is helpful to imply a structure.
673 67980f56 Georgios D. Tsoukalas
        e.g.: myproject.mylab.ntua.gr or
674 67980f56 Georgios D. Tsoukalas
        myservice.myteam.myorganization""")
675 67980f56 Georgios D. Tsoukalas
app_name_widget      =  forms.TextInput(
676 67980f56 Georgios D. Tsoukalas
                            attrs={'placeholder': app_name_placeholder})
677 67980f56 Georgios D. Tsoukalas
678 67980f56 Georgios D. Tsoukalas
679 67980f56 Georgios D. Tsoukalas
app_home_label       =  "Homepage URL"
680 3ff82dca Olga Brani
app_home_placeholder =  'myinstitution.org/myproject/'
681 67980f56 Georgios D. Tsoukalas
app_home_help        =  _("""
682 67980f56 Georgios D. Tsoukalas
        URL pointing at your project's site.
683 3ff82dca Olga Brani
        e.g.: myinstitution.org/myproject/.
684 67980f56 Georgios D. Tsoukalas
        Leave blank if there is no website.""")
685 67980f56 Georgios D. Tsoukalas
app_home_widget      =  forms.TextInput(
686 67980f56 Georgios D. Tsoukalas
                            attrs={'placeholder': app_home_placeholder})
687 67980f56 Georgios D. Tsoukalas
688 67980f56 Georgios D. Tsoukalas
app_desc_label       =  _("Description")
689 67980f56 Georgios D. Tsoukalas
app_desc_help        =  _("""
690 c53afd76 Georgios D. Tsoukalas
        Please provide a short but descriptive abstract of your
691 c53afd76 Georgios D. Tsoukalas
        Project, so that anyone searching can quickly understand
692 67980f56 Georgios D. Tsoukalas
        what this Project is about.""")
693 67980f56 Georgios D. Tsoukalas
694 67980f56 Georgios D. Tsoukalas
app_comment_label    =  _("Comments for review (private)")
695 67980f56 Georgios D. Tsoukalas
app_comment_help     =  _("""
696 67980f56 Georgios D. Tsoukalas
        Write down any comments you may have for the reviewer
697 67980f56 Georgios D. Tsoukalas
        of this application (e.g. background and rationale to
698 67980f56 Georgios D. Tsoukalas
        support your request).
699 67980f56 Georgios D. Tsoukalas
        The comments are strictly for the review process
700 c53afd76 Georgios D. Tsoukalas
        and will not be made public.""")
701 67980f56 Georgios D. Tsoukalas
702 67980f56 Georgios D. Tsoukalas
app_start_date_label =  _("Start date")
703 67980f56 Georgios D. Tsoukalas
app_start_date_help  =  _("""
704 67980f56 Georgios D. Tsoukalas
        Provide a date when your need your project to be created,
705 67980f56 Georgios D. Tsoukalas
        and members to be able to join and get resources.
706 67980f56 Georgios D. Tsoukalas
        This date is only a hint to help prioritize reviews.""")
707 67980f56 Georgios D. Tsoukalas
708 67980f56 Georgios D. Tsoukalas
app_end_date_label   =  _("Termination date")
709 67980f56 Georgios D. Tsoukalas
app_end_date_help    =  _("""
710 67980f56 Georgios D. Tsoukalas
        At this date, the project will be automatically terminated
711 c53afd76 Georgios D. Tsoukalas
        and its resource grants revoked from all members. If you are
712 c53afd76 Georgios D. Tsoukalas
        not certain, it is best to start with a conservative estimation.
713 67980f56 Georgios D. Tsoukalas
        You can always re-apply for an extension, if you need.""")
714 67980f56 Georgios D. Tsoukalas
715 67980f56 Georgios D. Tsoukalas
join_policy_label    =  _("Joining policy")
716 b87429e1 Olga Brani
app_member_join_policy_help    =  _("""
717 c53afd76 Georgios D. Tsoukalas
        Select how new members are accepted into the project.""")
718 67980f56 Georgios D. Tsoukalas
leave_policy_label   =  _("Leaving policy")
719 b87429e1 Olga Brani
app_member_leave_policy_help    =  _("""
720 c53afd76 Georgios D. Tsoukalas
        Select how new members can leave the project.""")
721 67980f56 Georgios D. Tsoukalas
722 67980f56 Georgios D. Tsoukalas
max_members_label    =  _("Maximum member count")
723 67980f56 Georgios D. Tsoukalas
max_members_help     =  _("""
724 67980f56 Georgios D. Tsoukalas
        Specify the maximum number of members this project may have,
725 67980f56 Georgios D. Tsoukalas
        including the owner. Beyond this number, no new members
726 67980f56 Georgios D. Tsoukalas
        may join the project and be granted the project resources.
727 c53afd76 Georgios D. Tsoukalas
        If you are not certain, it is best to start with a conservative
728 c53afd76 Georgios D. Tsoukalas
        limit. You can always request a raise when you need it.""")
729 67980f56 Georgios D. Tsoukalas
730 67980f56 Georgios D. Tsoukalas
join_policies = PROJECT_MEMBER_JOIN_POLICIES.iteritems()
731 67980f56 Georgios D. Tsoukalas
leave_policies = PROJECT_MEMBER_LEAVE_POLICIES.iteritems()
732 67980f56 Georgios D. Tsoukalas
733 e1a80257 Sofia Papagiannaki
class ProjectApplicationForm(forms.ModelForm):
734 67980f56 Georgios D. Tsoukalas
735 e1a80257 Sofia Papagiannaki
    name = forms.CharField(
736 67980f56 Georgios D. Tsoukalas
        label     = app_name_label,
737 67980f56 Georgios D. Tsoukalas
        help_text = app_name_help,
738 67980f56 Georgios D. Tsoukalas
        widget    = app_name_widget,
739 67980f56 Georgios D. Tsoukalas
        validators = [app_name_validator])
740 67980f56 Georgios D. Tsoukalas
741 52784759 Olga Brani
    homepage = forms.URLField(
742 67980f56 Georgios D. Tsoukalas
        label     = app_home_label,
743 80da92f0 Kostas Papadimitriou
        help_text = app_home_help,
744 67980f56 Georgios D. Tsoukalas
        widget    = app_home_widget,
745 67980f56 Georgios D. Tsoukalas
        required  = False)
746 67980f56 Georgios D. Tsoukalas
747 67980f56 Georgios D. Tsoukalas
    description = forms.CharField(
748 67980f56 Georgios D. Tsoukalas
        label     = app_desc_label,
749 67980f56 Georgios D. Tsoukalas
        help_text = app_desc_help,
750 67980f56 Georgios D. Tsoukalas
        widget    = forms.Textarea,
751 67980f56 Georgios D. Tsoukalas
        required  = False)
752 67980f56 Georgios D. Tsoukalas
753 67980f56 Georgios D. Tsoukalas
    comments = forms.CharField(
754 67980f56 Georgios D. Tsoukalas
        label     = app_comment_label,
755 67980f56 Georgios D. Tsoukalas
        help_text = app_comment_help,
756 67980f56 Georgios D. Tsoukalas
        widget    = forms.Textarea,
757 67980f56 Georgios D. Tsoukalas
        required  = False)
758 67980f56 Georgios D. Tsoukalas
759 67980f56 Georgios D. Tsoukalas
    start_date = forms.DateTimeField(
760 67980f56 Georgios D. Tsoukalas
        label     = app_start_date_label,
761 67980f56 Georgios D. Tsoukalas
        help_text = app_start_date_help,
762 67980f56 Georgios D. Tsoukalas
        required  = False)
763 67980f56 Georgios D. Tsoukalas
764 67980f56 Georgios D. Tsoukalas
    end_date = forms.DateTimeField(
765 67980f56 Georgios D. Tsoukalas
        label     = app_end_date_label,
766 67980f56 Georgios D. Tsoukalas
        help_text = app_end_date_help)
767 67980f56 Georgios D. Tsoukalas
768 80da92f0 Kostas Papadimitriou
    member_join_policy  = forms.TypedChoiceField(
769 67980f56 Georgios D. Tsoukalas
        label     = join_policy_label,
770 b87429e1 Olga Brani
        help_text = app_member_join_policy_help,
771 80da92f0 Kostas Papadimitriou
        initial   = 2,
772 80da92f0 Kostas Papadimitriou
        coerce    = int,
773 67980f56 Georgios D. Tsoukalas
        choices   = join_policies)
774 dd5f8f4d Kostas Papadimitriou
775 80da92f0 Kostas Papadimitriou
    member_leave_policy = forms.TypedChoiceField(
776 67980f56 Georgios D. Tsoukalas
        label     = leave_policy_label,
777 b87429e1 Olga Brani
        help_text = app_member_leave_policy_help,
778 80da92f0 Kostas Papadimitriou
        coerce    = int,
779 67980f56 Georgios D. Tsoukalas
        choices   = leave_policies)
780 67980f56 Georgios D. Tsoukalas
781 67980f56 Georgios D. Tsoukalas
    limit_on_members_number = forms.IntegerField(
782 67980f56 Georgios D. Tsoukalas
        label     = max_members_label,
783 67980f56 Georgios D. Tsoukalas
        help_text = max_members_help,
784 e01dcd43 Sofia Papagiannaki
        min_value = 0,
785 67980f56 Georgios D. Tsoukalas
        required  = False)
786 dd5f8f4d Kostas Papadimitriou
787 e1a80257 Sofia Papagiannaki
    class Meta:
788 73fbaec4 Sofia Papagiannaki
        model = ProjectApplication
789 c82bd52b Kostas Papadimitriou
        fields = ( 'name', 'homepage', 'description',
790 c82bd52b Kostas Papadimitriou
                    'start_date', 'end_date', 'comments',
791 c82bd52b Kostas Papadimitriou
                    'member_join_policy', 'member_leave_policy',
792 c82bd52b Kostas Papadimitriou
                    'limit_on_members_number')
793 c82bd52b Kostas Papadimitriou
794 40b52116 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
795 2ef98527 Sofia Papagiannaki
        instance = kwargs.get('instance')
796 2ef98527 Sofia Papagiannaki
        self.precursor_application = instance
797 40b52116 Sofia Papagiannaki
        super(ProjectApplicationForm, self).__init__(*args, **kwargs)
798 f568d0f4 Sofia Papagiannaki
        # in case of new application remove closed join policy
799 2ef98527 Sofia Papagiannaki
        if not instance:
800 2ef98527 Sofia Papagiannaki
            policies = PROJECT_MEMBER_JOIN_POLICIES.copy()
801 2ef98527 Sofia Papagiannaki
            policies.pop('3')
802 2ef98527 Sofia Papagiannaki
            self.fields['member_join_policy'].choices = policies.iteritems()
803 dd5f8f4d Kostas Papadimitriou
804 69b26576 Sofia Papagiannaki
    def clean_start_date(self):
805 69b26576 Sofia Papagiannaki
        start_date = self.cleaned_data.get('start_date')
806 f568d0f4 Sofia Papagiannaki
        if not self.precursor_application:
807 8172d87d Sofia Papagiannaki
            today = datetime.now()
808 8172d87d Sofia Papagiannaki
            today = datetime(today.year, today.month, today.day)
809 01223f04 Sofia Papagiannaki
            if start_date and (start_date - today).days < 0:
810 f568d0f4 Sofia Papagiannaki
                raise forms.ValidationError(
811 69b26576 Sofia Papagiannaki
                _(astakos_messages.INVALID_PROJECT_START_DATE))
812 69b26576 Sofia Papagiannaki
        return start_date
813 69b26576 Sofia Papagiannaki
814 69b26576 Sofia Papagiannaki
    def clean_end_date(self):
815 69b26576 Sofia Papagiannaki
        start_date = self.cleaned_data.get('start_date')
816 69b26576 Sofia Papagiannaki
        end_date = self.cleaned_data.get('end_date')
817 8172d87d Sofia Papagiannaki
        today = datetime.now()
818 8172d87d Sofia Papagiannaki
        today = datetime(today.year, today.month, today.day)
819 01223f04 Sofia Papagiannaki
        if end_date and (end_date - today).days < 0:
820 69b26576 Sofia Papagiannaki
            raise forms.ValidationError(
821 69b26576 Sofia Papagiannaki
                _(astakos_messages.INVALID_PROJECT_END_DATE))
822 f03b9ba6 Sofia Papagiannaki
        if start_date and (end_date - start_date).days <= 0:
823 69b26576 Sofia Papagiannaki
            raise forms.ValidationError(
824 69b26576 Sofia Papagiannaki
                _(astakos_messages.INCONSISTENT_PROJECT_DATES))
825 69b26576 Sofia Papagiannaki
        return end_date
826 69b26576 Sofia Papagiannaki
827 e1a80257 Sofia Papagiannaki
    def clean(self):
828 185b2190 Sofia Papagiannaki
        userid = self.data.get('user', None)
829 e1a80257 Sofia Papagiannaki
        self.user = None
830 e1a80257 Sofia Papagiannaki
        if userid:
831 e1a80257 Sofia Papagiannaki
            try:
832 e1a80257 Sofia Papagiannaki
                self.user = AstakosUser.objects.get(id=userid)
833 e1a80257 Sofia Papagiannaki
            except AstakosUser.DoesNotExist:
834 e1a80257 Sofia Papagiannaki
                pass
835 e1a80257 Sofia Papagiannaki
        if not self.user:
836 e1a80257 Sofia Papagiannaki
            raise forms.ValidationError(_(astakos_messages.NO_APPLICANT))
837 e1a80257 Sofia Papagiannaki
        super(ProjectApplicationForm, self).clean()
838 e1a80257 Sofia Papagiannaki
        return self.cleaned_data
839 dd5f8f4d Kostas Papadimitriou
840 f3342849 Sofia Papagiannaki
    @property
841 f3342849 Sofia Papagiannaki
    def resource_policies(self):
842 e1a80257 Sofia Papagiannaki
        policies = []
843 e1a80257 Sofia Papagiannaki
        append = policies.append
844 f3342849 Sofia Papagiannaki
        for name, value in self.data.iteritems():
845 f3342849 Sofia Papagiannaki
            if not value:
846 f3342849 Sofia Papagiannaki
                continue
847 56eb807c Sofia Papagiannaki
            uplimit = value
848 56eb807c Sofia Papagiannaki
            if name.endswith('_uplimit'):
849 56eb807c Sofia Papagiannaki
                subs = name.split('_uplimit')
850 e1a80257 Sofia Papagiannaki
                prefix, suffix = subs
851 e1a80257 Sofia Papagiannaki
                s, sep, r = prefix.partition(RESOURCE_SEPARATOR)
852 e1a80257 Sofia Papagiannaki
                resource = Resource.objects.get(service__name=s, name=r)
853 e1a80257 Sofia Papagiannaki
854 e1a80257 Sofia Papagiannaki
                # keep only resource limits for selected resource groups
855 30dd9e0e Olga Brani
                if self.data.get(
856 30dd9e0e Olga Brani
                    'is_selected_%s' % resource.group, "0"
857 30dd9e0e Olga Brani
                 ) == "1":
858 6556e514 Sofia Papagiannaki
                    d = model_to_dict(resource)
859 30dd9e0e Olga Brani
                    if uplimit:
860 6556e514 Sofia Papagiannaki
                        d.update(dict(service=s, resource=r, uplimit=uplimit))
861 30dd9e0e Olga Brani
                    else:
862 6556e514 Sofia Papagiannaki
                        d.update(dict(service=s, resource=r, uplimit=None))
863 6556e514 Sofia Papagiannaki
                    append(d)
864 dd5f8f4d Kostas Papadimitriou
865 ec2e67f4 Kostas Papadimitriou
        ordered_keys = RESOURCES_PRESENTATION_DATA['resources_order']
866 ec2e67f4 Kostas Papadimitriou
        policies = sorted(policies, key=lambda r:ordered_keys.index(r['str_repr']))
867 e1a80257 Sofia Papagiannaki
        return policies
868 dd5f8f4d Kostas Papadimitriou
869 e1a80257 Sofia Papagiannaki
    def save(self, commit=True):
870 15ca2bea Giorgos Korfiatis
        data = dict(self.cleaned_data)
871 69c822cc Giorgos Korfiatis
        data['precursor_application'] = self.instance.id
872 69c822cc Giorgos Korfiatis
        data['owner'] = self.user
873 69c822cc Giorgos Korfiatis
        data['resource_policies'] = self.resource_policies
874 ee4aa6eb Giorgos Korfiatis
        submit_application(data, request_user=self.user)
875 8327782d Sofia Papagiannaki
876 8327782d Sofia Papagiannaki
class ProjectSortForm(forms.Form):
877 8327782d Sofia Papagiannaki
    sorting = forms.ChoiceField(
878 8327782d Sofia Papagiannaki
        label='Sort by',
879 73fbaec4 Sofia Papagiannaki
        choices=(('name', 'Sort by Name'),
880 8327782d Sofia Papagiannaki
                 ('issue_date', 'Sort by Issue date'),
881 73fbaec4 Sofia Papagiannaki
                 ('start_date', 'Sort by Start Date'),
882 73fbaec4 Sofia Papagiannaki
                 ('end_date', 'Sort by End Date'),
883 8327782d Sofia Papagiannaki
#                  ('approved_members_num', 'Sort by Participants'),
884 d6a162d3 Sofia Papagiannaki
                 ('state', 'Sort by Status'),
885 73fbaec4 Sofia Papagiannaki
                 ('member_join_policy__description', 'Sort by Member Join Policy'),
886 7592e3e2 Sofia Papagiannaki
                 ('member_leave_policy__description', 'Sort by Member Leave Policy'),
887 7592e3e2 Sofia Papagiannaki
                 ('-name', 'Sort by Name'),
888 7592e3e2 Sofia Papagiannaki
                 ('-issue_date', 'Sort by Issue date'),
889 7592e3e2 Sofia Papagiannaki
                 ('-start_date', 'Sort by Start Date'),
890 7592e3e2 Sofia Papagiannaki
                 ('-end_date', 'Sort by End Date'),
891 7592e3e2 Sofia Papagiannaki
#                  ('-approved_members_num', 'Sort by Participants'),
892 7592e3e2 Sofia Papagiannaki
                 ('-state', 'Sort by Status'),
893 7592e3e2 Sofia Papagiannaki
                 ('-member_join_policy__description', 'Sort by Member Join Policy'),
894 7592e3e2 Sofia Papagiannaki
                 ('-member_leave_policy__description', 'Sort by Member Leave Policy')
895 8327782d Sofia Papagiannaki
        ),
896 8327782d Sofia Papagiannaki
        required=True
897 ccab6eb5 Sofia Papagiannaki
    )
898 ccab6eb5 Sofia Papagiannaki
899 ccab6eb5 Sofia Papagiannaki
class AddProjectMembersForm(forms.Form):
900 ccab6eb5 Sofia Papagiannaki
    q = forms.CharField(
901 ccab6eb5 Sofia Papagiannaki
        max_length=800, widget=forms.Textarea, label=_('Add members'),
902 e47fb17a Sofia Papagiannaki
        help_text=_(astakos_messages.ADD_PROJECT_MEMBERS_Q_HELP), required=True)
903 ccab6eb5 Sofia Papagiannaki
904 e47fb17a Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
905 ff67242a Giorgos Korfiatis
        chain_id = kwargs.pop('chain_id', None)
906 ff67242a Giorgos Korfiatis
        if chain_id:
907 ff67242a Giorgos Korfiatis
            self.project = Project.objects.get(id=chain_id)
908 e47fb17a Sofia Papagiannaki
        self.request_user = kwargs.pop('request_user', None)
909 e47fb17a Sofia Papagiannaki
        super(AddProjectMembersForm, self).__init__(*args, **kwargs)
910 43332a76 Kostas Papadimitriou
911 ccab6eb5 Sofia Papagiannaki
    def clean(self):
912 e47fb17a Sofia Papagiannaki
        try:
913 ff67242a Giorgos Korfiatis
            accept_membership_checks(self.project, self.request_user)
914 e47fb17a Sofia Papagiannaki
        except PermissionDenied, e:
915 e47fb17a Sofia Papagiannaki
            raise forms.ValidationError(e)
916 e47fb17a Sofia Papagiannaki
917 ccab6eb5 Sofia Papagiannaki
        q = self.cleaned_data.get('q') or ''
918 ccab6eb5 Sofia Papagiannaki
        users = q.split(',')
919 ccab6eb5 Sofia Papagiannaki
        users = list(u.strip() for u in users if u)
920 97e93991 Kostas Papadimitriou
        db_entries = AstakosUser.objects.verified().filter(email__in=users)
921 ccab6eb5 Sofia Papagiannaki
        unknown = list(set(users) - set(u.email for u in db_entries))
922 ccab6eb5 Sofia Papagiannaki
        if unknown:
923 e47fb17a Sofia Papagiannaki
            raise forms.ValidationError(
924 e47fb17a Sofia Papagiannaki
                _(astakos_messages.UNKNOWN_USERS) % ','.join(unknown))
925 ccab6eb5 Sofia Papagiannaki
        self.valid_users = db_entries
926 ccab6eb5 Sofia Papagiannaki
        return self.cleaned_data
927 ccab6eb5 Sofia Papagiannaki
928 ccab6eb5 Sofia Papagiannaki
    def get_valid_users(self):
929 ccab6eb5 Sofia Papagiannaki
        """Should be called after form cleaning"""
930 ccab6eb5 Sofia Papagiannaki
        try:
931 ccab6eb5 Sofia Papagiannaki
            return self.valid_users
932 ccab6eb5 Sofia Papagiannaki
        except:
933 bfe23b13 Sofia Papagiannaki
            return ()
934 bfe23b13 Sofia Papagiannaki
935 bfe23b13 Sofia Papagiannaki
class ProjectMembersSortForm(forms.Form):
936 bfe23b13 Sofia Papagiannaki
    sorting = forms.ChoiceField(
937 bfe23b13 Sofia Papagiannaki
        label='Sort by',
938 bfe23b13 Sofia Papagiannaki
        choices=(('person__email', 'User Id'),
939 bfe23b13 Sofia Papagiannaki
                 ('person__first_name', 'Name'),
940 bfe23b13 Sofia Papagiannaki
                 ('acceptance_date', 'Acceptance date')
941 bfe23b13 Sofia Papagiannaki
        ),
942 bfe23b13 Sofia Papagiannaki
        required=True
943 bfe23b13 Sofia Papagiannaki
    )
944 bfe23b13 Sofia Papagiannaki
945 f7400729 Kostas Papadimitriou
946 6dadd24a Sofia Papagiannaki
class ProjectSearchForm(forms.Form):
947 85d444db Sofia Papagiannaki
    q = forms.CharField(max_length=200, label='Search project', required=False)
948 5550bcfb Kostas Papadimitriou
949 f7400729 Kostas Papadimitriou
950 f7400729 Kostas Papadimitriou
class ExtendedProfileForm(ProfileForm):
951 f7400729 Kostas Papadimitriou
    """
952 f7400729 Kostas Papadimitriou
    Profile form that combines `email change` and `password change` user
953 f7400729 Kostas Papadimitriou
    actions by propagating submited data to internal EmailChangeForm
954 f7400729 Kostas Papadimitriou
    and ExtendedPasswordChangeForm objects.
955 f7400729 Kostas Papadimitriou
    """
956 f7400729 Kostas Papadimitriou
957 f7400729 Kostas Papadimitriou
    password_change_form = None
958 f7400729 Kostas Papadimitriou
    email_change_form = None
959 17ad5d37 Kostas Papadimitriou
960 3fbf7863 Kostas Papadimitriou
    password_change = False
961 17ad5d37 Kostas Papadimitriou
    email_change = False
962 17ad5d37 Kostas Papadimitriou
963 f7400729 Kostas Papadimitriou
    extra_forms_fields = {
964 f7400729 Kostas Papadimitriou
        'email': ['new_email_address'],
965 f7400729 Kostas Papadimitriou
        'password': ['old_password', 'new_password1', 'new_password2']
966 f7400729 Kostas Papadimitriou
    }
967 f7400729 Kostas Papadimitriou
968 d0632ab1 Olga Brani
    fields = ('email')
969 f7400729 Kostas Papadimitriou
    change_password = forms.BooleanField(initial=False, required=False)
970 f7400729 Kostas Papadimitriou
    change_email = forms.BooleanField(initial=False, required=False)
971 c55e39e7 Kostas Papadimitriou
972 2da6f56b Kostas Papadimitriou
    email_changed = False
973 2da6f56b Kostas Papadimitriou
    password_changed = False
974 f7400729 Kostas Papadimitriou
975 f7400729 Kostas Papadimitriou
    def __init__(self, *args, **kwargs):
976 95cb469b Kostas Papadimitriou
        session_key = kwargs.get('session_key', None)
977 c55e39e7 Kostas Papadimitriou
        self.fields_list = [
978 c55e39e7 Kostas Papadimitriou
                'email',
979 c55e39e7 Kostas Papadimitriou
                'new_email_address',
980 c55e39e7 Kostas Papadimitriou
                'first_name',
981 c55e39e7 Kostas Papadimitriou
                'last_name',
982 c55e39e7 Kostas Papadimitriou
                'auth_token',
983 c55e39e7 Kostas Papadimitriou
                'auth_token_expires',
984 c55e39e7 Kostas Papadimitriou
                'old_password',
985 c55e39e7 Kostas Papadimitriou
                'new_password1',
986 c55e39e7 Kostas Papadimitriou
                'new_password2',
987 c55e39e7 Kostas Papadimitriou
                'change_email',
988 c55e39e7 Kostas Papadimitriou
                'change_password',
989 ccaadd41 Sofia Papagiannaki
                'uuid'
990 c55e39e7 Kostas Papadimitriou
        ]
991 c55e39e7 Kostas Papadimitriou
992 f7400729 Kostas Papadimitriou
        super(ExtendedProfileForm, self).__init__(*args, **kwargs)
993 95cb469b Kostas Papadimitriou
        self.session_key = session_key
994 3fbf7863 Kostas Papadimitriou
        if self.instance.can_change_password():
995 3fbf7863 Kostas Papadimitriou
            self.password_change = True
996 3fbf7863 Kostas Papadimitriou
        else:
997 2b7a87d7 Olga Brani
            self.fields_list.remove('old_password')
998 2b7a87d7 Olga Brani
            self.fields_list.remove('new_password1')
999 2b7a87d7 Olga Brani
            self.fields_list.remove('new_password2')
1000 2b7a87d7 Olga Brani
            self.fields_list.remove('change_password')
1001 3fbf7863 Kostas Papadimitriou
            del self.fields['change_password']
1002 3fbf7863 Kostas Papadimitriou
1003 c55e39e7 Kostas Papadimitriou
1004 649f2d36 Kostas Papadimitriou
        if EMAILCHANGE_ENABLED and self.instance.can_change_email():
1005 17ad5d37 Kostas Papadimitriou
            self.email_change = True
1006 17ad5d37 Kostas Papadimitriou
        else:
1007 d0632ab1 Olga Brani
            self.fields_list.remove('new_email_address')
1008 2b7a87d7 Olga Brani
            self.fields_list.remove('change_email')
1009 17ad5d37 Kostas Papadimitriou
            del self.fields['change_email']
1010 17ad5d37 Kostas Papadimitriou
1011 f7400729 Kostas Papadimitriou
        self._init_extra_forms()
1012 f7400729 Kostas Papadimitriou
        self.save_extra_forms = []
1013 f7400729 Kostas Papadimitriou
        self.success_messages = []
1014 d0632ab1 Olga Brani
        self.fields.keyOrder = self.fields_list
1015 c55e39e7 Kostas Papadimitriou
1016 c55e39e7 Kostas Papadimitriou
1017 f7400729 Kostas Papadimitriou
    def _init_extra_form_fields(self):
1018 17ad5d37 Kostas Papadimitriou
        if self.email_change:
1019 17ad5d37 Kostas Papadimitriou
            self.fields.update(self.email_change_form.fields)
1020 17ad5d37 Kostas Papadimitriou
            self.fields['new_email_address'].required = False
1021 f911f6d3 Kostas Papadimitriou
            self.fields['email'].help_text = _('Request email change')
1022 3fbf7863 Kostas Papadimitriou
1023 3fbf7863 Kostas Papadimitriou
        if self.password_change:
1024 3fbf7863 Kostas Papadimitriou
            self.fields.update(self.password_change_form.fields)
1025 3fbf7863 Kostas Papadimitriou
            self.fields['old_password'].required = False
1026 003d8fcf Olga Brani
            self.fields['old_password'].label = _('Password')
1027 f911f6d3 Kostas Papadimitriou
            self.fields['old_password'].help_text = _('Change your local '
1028 f911f6d3 Kostas Papadimitriou
                                                      'password')
1029 861458fd Kostas Papadimitriou
            self.fields['old_password'].initial = 'password'
1030 3fbf7863 Kostas Papadimitriou
            self.fields['new_password1'].required = False
1031 3fbf7863 Kostas Papadimitriou
            self.fields['new_password2'].required = False
1032 f7400729 Kostas Papadimitriou
1033 f7400729 Kostas Papadimitriou
    def _update_extra_form_errors(self):
1034 f7400729 Kostas Papadimitriou
        if self.cleaned_data.get('change_password'):
1035 f7400729 Kostas Papadimitriou
            self.errors.update(self.password_change_form.errors)
1036 f7400729 Kostas Papadimitriou
        if self.cleaned_data.get('change_email'):
1037 f7400729 Kostas Papadimitriou
            self.errors.update(self.email_change_form.errors)
1038 f7400729 Kostas Papadimitriou
1039 f7400729 Kostas Papadimitriou
    def _init_extra_forms(self):
1040 f7400729 Kostas Papadimitriou
        self.email_change_form = EmailChangeForm(self.data)
1041 f7400729 Kostas Papadimitriou
        self.password_change_form = ExtendedPasswordChangeForm(user=self.instance,
1042 95cb469b Kostas Papadimitriou
                                   data=self.data, session_key=self.session_key)
1043 f7400729 Kostas Papadimitriou
        self._init_extra_form_fields()
1044 f7400729 Kostas Papadimitriou
1045 f7400729 Kostas Papadimitriou
    def is_valid(self):
1046 f7400729 Kostas Papadimitriou
        password, email = True, True
1047 f7400729 Kostas Papadimitriou
        profile = super(ExtendedProfileForm, self).is_valid()
1048 3fbf7863 Kostas Papadimitriou
        if profile and self.cleaned_data.get('change_password', None):
1049 e9e692be Kostas Papadimitriou
1050 f7400729 Kostas Papadimitriou
            password = self.password_change_form.is_valid()
1051 3fbf7863 Kostas Papadimitriou
            self.save_extra_forms.append('password')
1052 f7400729 Kostas Papadimitriou
        if profile and self.cleaned_data.get('change_email'):
1053 7b4ca7fe Olga Brani
            self.fields['new_email_address'].required = True
1054 f7400729 Kostas Papadimitriou
            email = self.email_change_form.is_valid()
1055 3fbf7863 Kostas Papadimitriou
            self.save_extra_forms.append('email')
1056 f7400729 Kostas Papadimitriou
1057 f7400729 Kostas Papadimitriou
        if not password or not email:
1058 f7400729 Kostas Papadimitriou
            self._update_extra_form_errors()
1059 f7400729 Kostas Papadimitriou
1060 f7400729 Kostas Papadimitriou
        return all([profile, password, email])
1061 f7400729 Kostas Papadimitriou
1062 3fbf7863 Kostas Papadimitriou
    def save(self, request, *args, **kwargs):
1063 f7400729 Kostas Papadimitriou
        if 'email' in self.save_extra_forms:
1064 3fbf7863 Kostas Papadimitriou
            self.email_change_form.save(request, *args, **kwargs)
1065 2da6f56b Kostas Papadimitriou
            self.email_changed = True
1066 f7400729 Kostas Papadimitriou
        if 'password' in self.save_extra_forms:
1067 f7400729 Kostas Papadimitriou
            self.password_change_form.save(*args, **kwargs)
1068 2da6f56b Kostas Papadimitriou
            self.password_changed = True
1069 f7400729 Kostas Papadimitriou
        return super(ExtendedProfileForm, self).save(*args, **kwargs)