Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (38 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 17ad5d37 Kostas Papadimitriou
    PROJECT_MEMBER_LEAVE_POLICIES, EMAILCHANGE_ENABLED)
68 45f8d9ff Sofia Papagiannaki
from astakos.im.widgets import DummyWidget, RecaptchaWidget
69 e47fb17a Sofia Papagiannaki
from astakos.im.functions import (
70 ff67242a Giorgos Korfiatis
    send_change_email, submit_application, accept_membership_checks)
71 270dd48d Sofia Papagiannaki
72 43332a76 Kostas Papadimitriou
from astakos.im.util import reserved_email, reserved_verified_email, \
73 43332a76 Kostas Papadimitriou
                            get_query, model_to_dict
74 c4b1a172 Kostas Papadimitriou
from astakos.im import auth_providers
75 64cd4730 Antony Chazapis
76 ae497612 Olga Brani
import astakos.im.messages as astakos_messages
77 64cd4730 Antony Chazapis
78 3bf924ec Sofia Papagiannaki
import logging
79 49790d9d Sofia Papagiannaki
import hashlib
80 db7fecd9 Sofia Papagiannaki
import recaptcha.client.captcha as captcha
81 caf70869 Sofia Papagiannaki
import re
82 64cd4730 Antony Chazapis
83 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
84 e015e9e6 Sofia Papagiannaki
85 caf70869 Sofia Papagiannaki
DOMAIN_VALUE_REGEX = re.compile(
86 892410d3 Sofia Papagiannaki
    r'^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$',
87 73fbaec4 Sofia Papagiannaki
    re.IGNORECASE)
88 d2633501 Kostas Papadimitriou
89 caf70869 Sofia Papagiannaki
class StoreUserMixin(object):
90 e5966bd9 Kostas Papadimitriou
91 d2633501 Kostas Papadimitriou
    def store_user(self, user, request):
92 43332a76 Kostas Papadimitriou
        """
93 43332a76 Kostas Papadimitriou
        WARNING: this should be wrapped inside a transactional view/method.
94 43332a76 Kostas Papadimitriou
        """
95 d2633501 Kostas Papadimitriou
        user.save()
96 d2633501 Kostas Papadimitriou
        self.post_store_user(user, request)
97 d2633501 Kostas Papadimitriou
        return user
98 d2633501 Kostas Papadimitriou
99 d2633501 Kostas Papadimitriou
    def post_store_user(self, user, request):
100 d2633501 Kostas Papadimitriou
        """
101 d2633501 Kostas Papadimitriou
        Interface method for descendant backends to be able to do stuff within
102 d2633501 Kostas Papadimitriou
        the transaction enabled by store_user.
103 d2633501 Kostas Papadimitriou
        """
104 d2633501 Kostas Papadimitriou
        pass
105 d2633501 Kostas Papadimitriou
106 d2633501 Kostas Papadimitriou
107 d2633501 Kostas Papadimitriou
class LocalUserCreationForm(UserCreationForm, StoreUserMixin):
108 890b0eaf Sofia Papagiannaki
    """
109 890b0eaf Sofia Papagiannaki
    Extends the built in UserCreationForm in several ways:
110 18ffbee1 Sofia Papagiannaki

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

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

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