Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (37.9 kB)

1 1808f7bc Giorgos Korfiatis
# Copyright 2011, 2012, 2013 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 caf70869 Sofia Papagiannaki
from random import random
34 3e0a032d Sofia Papagiannaki
from datetime import datetime
35 64cd4730 Antony Chazapis
36 64cd4730 Antony Chazapis
from django import forms
37 64cd4730 Antony Chazapis
from django.utils.translation import ugettext as _
38 3e0a032d Sofia Papagiannaki
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, \
39 3e0a032d Sofia Papagiannaki
    PasswordResetForm, PasswordChangeForm, SetPasswordForm
40 f9224cc0 Sofia Papagiannaki
from django.core.mail import send_mail, get_connection
41 e2125441 Sofia Papagiannaki
from django.contrib.auth.tokens import default_token_generator
42 374611bc Sofia Papagiannaki
from django.core.urlresolvers import reverse
43 18ffbee1 Sofia Papagiannaki
from django.utils.safestring import mark_safe
44 49790d9d Sofia Papagiannaki
from django.utils.encoding import smart_str
45 d2633501 Kostas Papadimitriou
from django.db import transaction
46 caf70869 Sofia Papagiannaki
from django.core import validators
47 5ed6816e Sofia Papagiannaki
48 3e87075a Giorgos Korfiatis
from synnefo.util import units
49 734107ef Kostas Papadimitriou
from synnefo_branding.utils import render_to_string
50 d2c9adac Christos Stavrakakis
from synnefo.lib import join_urls
51 3e0a032d Sofia Papagiannaki
from astakos.im.models import AstakosUser, EmailChange, Invitation, Resource, \
52 3e0a032d Sofia Papagiannaki
    PendingThirdPartyUser, get_latest_terms, ProjectApplication, Project
53 75380308 Kostas Papadimitriou
from astakos.im import presentation
54 45f8d9ff Sofia Papagiannaki
from astakos.im.widgets import DummyWidget, RecaptchaWidget
55 3e0a032d Sofia Papagiannaki
from astakos.im.functions import send_change_email, submit_application, \
56 f12bcb3d Giorgos Korfiatis
    accept_membership_project_checks, ProjectError
57 270dd48d Sofia Papagiannaki
58 3e0a032d Sofia Papagiannaki
from astakos.im.util import reserved_verified_email, model_to_dict
59 c4b1a172 Kostas Papadimitriou
from astakos.im import auth_providers
60 8998f09a Sofia Papagiannaki
from astakos.im import settings
61 1808f7bc Giorgos Korfiatis
from astakos.im import auth
62 64cd4730 Antony Chazapis
63 ae497612 Olga Brani
import astakos.im.messages as astakos_messages
64 64cd4730 Antony Chazapis
65 3bf924ec Sofia Papagiannaki
import logging
66 49790d9d Sofia Papagiannaki
import hashlib
67 db7fecd9 Sofia Papagiannaki
import recaptcha.client.captcha as captcha
68 caf70869 Sofia Papagiannaki
import re
69 64cd4730 Antony Chazapis
70 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
71 e015e9e6 Sofia Papagiannaki
72 caf70869 Sofia Papagiannaki
DOMAIN_VALUE_REGEX = re.compile(
73 892410d3 Sofia Papagiannaki
    r'^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$',
74 73fbaec4 Sofia Papagiannaki
    re.IGNORECASE)
75 d2633501 Kostas Papadimitriou
76 e7cb4085 Kostas Papadimitriou
77 1808f7bc Giorgos Korfiatis
class LocalUserCreationForm(UserCreationForm):
78 890b0eaf Sofia Papagiannaki
    """
79 890b0eaf Sofia Papagiannaki
    Extends the built in UserCreationForm in several ways:
80 18ffbee1 Sofia Papagiannaki

81 e47fb17a Sofia Papagiannaki
    * Adds email, first_name, last_name, recaptcha_challenge_field,
82 e47fb17a Sofia Papagiannaki
    * recaptcha_response_field field.
83 5ed6816e Sofia Papagiannaki
    * The username field isn't visible and it is assigned a generated id.
84 18ffbee1 Sofia Papagiannaki
    * User created is not active.
85 890b0eaf Sofia Papagiannaki
    """
86 db7fecd9 Sofia Papagiannaki
    recaptcha_challenge_field = forms.CharField(widget=DummyWidget)
87 5ce3ce4f Sofia Papagiannaki
    recaptcha_response_field = forms.CharField(
88 5ce3ce4f Sofia Papagiannaki
        widget=RecaptchaWidget, label='')
89 18ffbee1 Sofia Papagiannaki
90 794852f2 Sofia Papagiannaki
    class Meta:
91 794852f2 Sofia Papagiannaki
        model = AstakosUser
92 5ce3ce4f Sofia Papagiannaki
        fields = ("email", "first_name", "last_name",
93 5ce3ce4f Sofia Papagiannaki
                  "has_signed_terms", "has_signed_terms")
94 18ffbee1 Sofia Papagiannaki
95 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
96 64cd4730 Antony Chazapis
        """
97 890b0eaf Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
98 64cd4730 Antony Chazapis
        """
99 bf0c6de5 Sofia Papagiannaki
        request = kwargs.pop('request', None)
100 e7cb4085 Kostas Papadimitriou
        provider = kwargs.pop('provider', 'local')
101 e7cb4085 Kostas Papadimitriou
102 e7cb4085 Kostas Papadimitriou
        # we only use LocalUserCreationForm for local provider
103 e7cb4085 Kostas Papadimitriou
        if not provider == 'local':
104 e7cb4085 Kostas Papadimitriou
            raise Exception('Invalid provider')
105 e7cb4085 Kostas Papadimitriou
106 e7726e14 Kostas Papadimitriou
        self.ip = None
107 672d445a Sofia Papagiannaki
        if request:
108 672d445a Sofia Papagiannaki
            self.ip = request.META.get('REMOTE_ADDR',
109 e7cb4085 Kostas Papadimitriou
                                       request.META.get('HTTP_X_REAL_IP',
110 e7cb4085 Kostas Papadimitriou
                                                        None))
111 ab8bfb29 Kostas Papadimitriou
112 15efc749 Sofia Papagiannaki
        super(LocalUserCreationForm, self).__init__(*args, **kwargs)
113 890b0eaf Sofia Papagiannaki
        self.fields.keyOrder = ['email', 'first_name', 'last_name',
114 d8f63346 Sofia Papagiannaki
                                'password1', 'password2']
115 1b3398a0 Olga Brani
116 8998f09a Sofia Papagiannaki
        if settings.RECAPTCHA_ENABLED:
117 53bf2659 Sofia Papagiannaki
            self.fields.keyOrder.extend(['recaptcha_challenge_field',
118 5ce3ce4f Sofia Papagiannaki
                                         'recaptcha_response_field', ])
119 1b3398a0 Olga Brani
        if get_latest_terms():
120 1b3398a0 Olga Brani
            self.fields.keyOrder.append('has_signed_terms')
121 18ffbee1 Sofia Papagiannaki
122 18ffbee1 Sofia Papagiannaki
        if 'has_signed_terms' in self.fields:
123 18ffbee1 Sofia Papagiannaki
            # Overriding field label since we need to apply a link
124 18ffbee1 Sofia Papagiannaki
            # to the terms within the label
125 18ffbee1 Sofia Papagiannaki
            terms_link_html = '<a href="%s" target="_blank">%s</a>' \
126 5ce3ce4f Sofia Papagiannaki
                % (reverse('latest_terms'), _("the terms"))
127 18ffbee1 Sofia Papagiannaki
            self.fields['has_signed_terms'].label = \
128 5ce3ce4f Sofia Papagiannaki
                mark_safe("I agree with %s" % terms_link_html)
129 18ffbee1 Sofia Papagiannaki
130 af4eb974 Sofia Papagiannaki
    def clean_email(self):
131 e5966bd9 Kostas Papadimitriou
        email = self.cleaned_data['email']
132 881c856c Sofia Papagiannaki
        if not email:
133 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.REQUIRED_FIELD))
134 43332a76 Kostas Papadimitriou
        if reserved_verified_email(email):
135 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.EMAIL_USED))
136 0a569195 Sofia Papagiannaki
        return email
137 18ffbee1 Sofia Papagiannaki
138 270dd48d Sofia Papagiannaki
    def clean_has_signed_terms(self):
139 270dd48d Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
140 270dd48d Sofia Papagiannaki
        if not has_signed_terms:
141 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
142 270dd48d Sofia Papagiannaki
        return has_signed_terms
143 18ffbee1 Sofia Papagiannaki
144 db7fecd9 Sofia Papagiannaki
    def clean_recaptcha_response_field(self):
145 db7fecd9 Sofia Papagiannaki
        if 'recaptcha_challenge_field' in self.cleaned_data:
146 db7fecd9 Sofia Papagiannaki
            self.validate_captcha()
147 db7fecd9 Sofia Papagiannaki
        return self.cleaned_data['recaptcha_response_field']
148 db7fecd9 Sofia Papagiannaki
149 db7fecd9 Sofia Papagiannaki
    def clean_recaptcha_challenge_field(self):
150 db7fecd9 Sofia Papagiannaki
        if 'recaptcha_response_field' in self.cleaned_data:
151 db7fecd9 Sofia Papagiannaki
            self.validate_captcha()
152 db7fecd9 Sofia Papagiannaki
        return self.cleaned_data['recaptcha_challenge_field']
153 db7fecd9 Sofia Papagiannaki
154 db7fecd9 Sofia Papagiannaki
    def validate_captcha(self):
155 db7fecd9 Sofia Papagiannaki
        rcf = self.cleaned_data['recaptcha_challenge_field']
156 db7fecd9 Sofia Papagiannaki
        rrf = self.cleaned_data['recaptcha_response_field']
157 8998f09a Sofia Papagiannaki
        check = captcha.submit(
158 8998f09a Sofia Papagiannaki
            rcf, rrf, settings.RECAPTCHA_PRIVATE_KEY, self.ip)
159 db7fecd9 Sofia Papagiannaki
        if not check.is_valid:
160 8998f09a Sofia Papagiannaki
            raise forms.ValidationError(_(
161 8998f09a Sofia Papagiannaki
                astakos_messages.CAPTCHA_VALIDATION_ERR))
162 18ffbee1 Sofia Papagiannaki
163 1808f7bc Giorgos Korfiatis
    def create_user(self):
164 1808f7bc Giorgos Korfiatis
        try:
165 1808f7bc Giorgos Korfiatis
            data = self.cleaned_data
166 1808f7bc Giorgos Korfiatis
        except AttributeError:
167 1808f7bc Giorgos Korfiatis
            self.is_valid()
168 1808f7bc Giorgos Korfiatis
            data = self.cleaned_data
169 1808f7bc Giorgos Korfiatis
170 1808f7bc Giorgos Korfiatis
        user = auth.make_local_user(
171 1808f7bc Giorgos Korfiatis
            email=data['email'], password=data['password1'],
172 1808f7bc Giorgos Korfiatis
            first_name=data['first_name'], last_name=data['last_name'],
173 1808f7bc Giorgos Korfiatis
            has_signed_terms=True)
174 890b0eaf Sofia Papagiannaki
        return user
175 64cd4730 Antony Chazapis
176 5ce3ce4f Sofia Papagiannaki
177 1808f7bc Giorgos Korfiatis
class ThirdPartyUserCreationForm(forms.ModelForm):
178 1177e91b Olga Brani
    email = forms.EmailField(
179 1177e91b Olga Brani
        label='Contact email',
180 e7cb4085 Kostas Papadimitriou
        help_text='This is needed for contact purposes. '
181 e7cb4085 Kostas Papadimitriou
        'It doesn&#39;t need to be the same with the one you '
182 d6ea9b3d Olga Brani
        'provided to login previously. '
183 1177e91b Olga Brani
    )
184 43332a76 Kostas Papadimitriou
185 8f5a3a06 Sofia Papagiannaki
    class Meta:
186 8f5a3a06 Sofia Papagiannaki
        model = AstakosUser
187 e7cb4085 Kostas Papadimitriou
        fields = ['email', 'first_name', 'last_name', 'has_signed_terms']
188 ab8bfb29 Kostas Papadimitriou
189 8f5a3a06 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
190 8f5a3a06 Sofia Papagiannaki
        """
191 8f5a3a06 Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
192 8f5a3a06 Sofia Papagiannaki
        """
193 e7cb4085 Kostas Papadimitriou
194 e7cb4085 Kostas Papadimitriou
        self.provider = kwargs.pop('provider', None)
195 139eae46 Kostas Papadimitriou
        self.request = kwargs.pop('request', None)
196 e7cb4085 Kostas Papadimitriou
        if not self.provider or self.provider == 'local':
197 e7cb4085 Kostas Papadimitriou
            raise Exception('Invalid provider, %r' % self.provider)
198 e7cb4085 Kostas Papadimitriou
199 e7cb4085 Kostas Papadimitriou
        # ThirdPartyUserCreationForm should always get instantiated with
200 e7cb4085 Kostas Papadimitriou
        # a third_party_token value
201 e7cb4085 Kostas Papadimitriou
        self.third_party_token = kwargs.pop('third_party_token', None)
202 e7cb4085 Kostas Papadimitriou
        if not self.third_party_token:
203 e7cb4085 Kostas Papadimitriou
            raise Exception('ThirdPartyUserCreationForm'
204 e7cb4085 Kostas Papadimitriou
                            ' requires third_party_token')
205 2e90e3ec Kostas Papadimitriou
206 8f5a3a06 Sofia Papagiannaki
        super(ThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
207 2e90e3ec Kostas Papadimitriou
208 4a13d054 Kostas Papadimitriou
        if not get_latest_terms():
209 4a13d054 Kostas Papadimitriou
            del self.fields['has_signed_terms']
210 4a13d054 Kostas Papadimitriou
211 18ffbee1 Sofia Papagiannaki
        if 'has_signed_terms' in self.fields:
212 18ffbee1 Sofia Papagiannaki
            # Overriding field label since we need to apply a link
213 18ffbee1 Sofia Papagiannaki
            # to the terms within the label
214 18ffbee1 Sofia Papagiannaki
            terms_link_html = '<a href="%s" target="_blank">%s</a>' \
215 5ce3ce4f Sofia Papagiannaki
                % (reverse('latest_terms'), _("the terms"))
216 18ffbee1 Sofia Papagiannaki
            self.fields['has_signed_terms'].label = \
217 9d20fe23 Kostas Papadimitriou
                mark_safe("I agree with %s" % terms_link_html)
218 2e90e3ec Kostas Papadimitriou
219 18ffbee1 Sofia Papagiannaki
    def clean_email(self):
220 e5966bd9 Kostas Papadimitriou
        email = self.cleaned_data['email']
221 18ffbee1 Sofia Papagiannaki
        if not email:
222 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.REQUIRED_FIELD))
223 43332a76 Kostas Papadimitriou
        if reserved_verified_email(email):
224 e7cb4085 Kostas Papadimitriou
            provider_id = self.provider
225 9d20fe23 Kostas Papadimitriou
            provider = auth_providers.get_provider(provider_id)
226 9d20fe23 Kostas Papadimitriou
            extra_message = provider.get_add_to_existing_account_msg
227 564a2292 Kostas Papadimitriou
228 e7cb4085 Kostas Papadimitriou
            raise forms.ValidationError(mark_safe(
229 e7cb4085 Kostas Papadimitriou
                _(astakos_messages.EMAIL_USED) + ' ' + extra_message))
230 0a569195 Sofia Papagiannaki
        return email
231 ab8bfb29 Kostas Papadimitriou
232 18ffbee1 Sofia Papagiannaki
    def clean_has_signed_terms(self):
233 18ffbee1 Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
234 18ffbee1 Sofia Papagiannaki
        if not has_signed_terms:
235 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
236 18ffbee1 Sofia Papagiannaki
        return has_signed_terms
237 ab8bfb29 Kostas Papadimitriou
238 e7cb4085 Kostas Papadimitriou
    def _get_pending_user(self):
239 e7cb4085 Kostas Papadimitriou
        return PendingThirdPartyUser.objects.get(token=self.third_party_token)
240 e7cb4085 Kostas Papadimitriou
241 1808f7bc Giorgos Korfiatis
    def create_user(self):
242 1808f7bc Giorgos Korfiatis
        try:
243 1808f7bc Giorgos Korfiatis
            data = self.cleaned_data
244 1808f7bc Giorgos Korfiatis
        except AttributeError:
245 1808f7bc Giorgos Korfiatis
            self.is_valid()
246 1808f7bc Giorgos Korfiatis
            data = self.cleaned_data
247 1808f7bc Giorgos Korfiatis
248 1808f7bc Giorgos Korfiatis
        user = auth.make_user(
249 1808f7bc Giorgos Korfiatis
            email=data["email"],
250 1808f7bc Giorgos Korfiatis
            first_name=data["first_name"], last_name=data["last_name"],
251 1808f7bc Giorgos Korfiatis
            has_signed_terms=True)
252 e7cb4085 Kostas Papadimitriou
        pending = self._get_pending_user()
253 9d20fe23 Kostas Papadimitriou
        provider = pending.get_provider(user)
254 9d20fe23 Kostas Papadimitriou
        provider.add_to_user()
255 9d20fe23 Kostas Papadimitriou
        pending.delete()
256 8f5a3a06 Sofia Papagiannaki
        return user
257 8f5a3a06 Sofia Papagiannaki
258 5ce3ce4f Sofia Papagiannaki
259 5ed6816e Sofia Papagiannaki
class LoginForm(AuthenticationForm):
260 5ed6816e Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
261 672d445a Sofia Papagiannaki
    recaptcha_challenge_field = forms.CharField(widget=DummyWidget)
262 5ce3ce4f Sofia Papagiannaki
    recaptcha_response_field = forms.CharField(
263 5ce3ce4f Sofia Papagiannaki
        widget=RecaptchaWidget, label='')
264 ab8bfb29 Kostas Papadimitriou
265 672d445a Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
266 672d445a Sofia Papagiannaki
        was_limited = kwargs.get('was_limited', False)
267 672d445a Sofia Papagiannaki
        request = kwargs.get('request', None)
268 672d445a Sofia Papagiannaki
        if request:
269 8fb8d0cf Giorgos Korfiatis
            self.ip = request.META.get(
270 8fb8d0cf Giorgos Korfiatis
                'REMOTE_ADDR',
271 8fb8d0cf Giorgos Korfiatis
                request.META.get('HTTP_X_REAL_IP', None))
272 ab8bfb29 Kostas Papadimitriou
273 672d445a Sofia Papagiannaki
        t = ('request', 'was_limited')
274 672d445a Sofia Papagiannaki
        for elem in t:
275 672d445a Sofia Papagiannaki
            if elem in kwargs.keys():
276 672d445a Sofia Papagiannaki
                kwargs.pop(elem)
277 672d445a Sofia Papagiannaki
        super(LoginForm, self).__init__(*args, **kwargs)
278 ab8bfb29 Kostas Papadimitriou
279 672d445a Sofia Papagiannaki
        self.fields.keyOrder = ['username', 'password']
280 8998f09a Sofia Papagiannaki
        if was_limited and settings.RECAPTCHA_ENABLED:
281 672d445a Sofia Papagiannaki
            self.fields.keyOrder.extend(['recaptcha_challenge_field',
282 5ce3ce4f Sofia Papagiannaki
                                         'recaptcha_response_field', ])
283 9a06d96f Olga Brani
284 9a06d96f Olga Brani
    def clean_username(self):
285 4bdd7e3d Kostas Papadimitriou
        return self.cleaned_data['username'].lower()
286 ab8bfb29 Kostas Papadimitriou
287 672d445a Sofia Papagiannaki
    def clean_recaptcha_response_field(self):
288 672d445a Sofia Papagiannaki
        if 'recaptcha_challenge_field' in self.cleaned_data:
289 672d445a Sofia Papagiannaki
            self.validate_captcha()
290 672d445a Sofia Papagiannaki
        return self.cleaned_data['recaptcha_response_field']
291 672d445a Sofia Papagiannaki
292 672d445a Sofia Papagiannaki
    def clean_recaptcha_challenge_field(self):
293 672d445a Sofia Papagiannaki
        if 'recaptcha_response_field' in self.cleaned_data:
294 672d445a Sofia Papagiannaki
            self.validate_captcha()
295 672d445a Sofia Papagiannaki
        return self.cleaned_data['recaptcha_challenge_field']
296 672d445a Sofia Papagiannaki
297 672d445a Sofia Papagiannaki
    def validate_captcha(self):
298 672d445a Sofia Papagiannaki
        rcf = self.cleaned_data['recaptcha_challenge_field']
299 672d445a Sofia Papagiannaki
        rrf = self.cleaned_data['recaptcha_response_field']
300 8998f09a Sofia Papagiannaki
        check = captcha.submit(
301 8998f09a Sofia Papagiannaki
            rcf, rrf, settings.RECAPTCHA_PRIVATE_KEY, self.ip)
302 672d445a Sofia Papagiannaki
        if not check.is_valid:
303 8998f09a Sofia Papagiannaki
            raise forms.ValidationError(_(
304 8998f09a Sofia Papagiannaki
                astakos_messages.CAPTCHA_VALIDATION_ERR))
305 2e90e3ec Kostas Papadimitriou
306 eedb3923 Sofia Papagiannaki
    def clean(self):
307 1f3b4b39 Sofia Papagiannaki
        """
308 1f3b4b39 Sofia Papagiannaki
        Override default behavior in order to check user's activation later
309 1f3b4b39 Sofia Papagiannaki
        """
310 c4b1a172 Kostas Papadimitriou
        username = self.cleaned_data.get('username')
311 c4b1a172 Kostas Papadimitriou
312 bea8a810 Kostas Papadimitriou
        if username:
313 bea8a810 Kostas Papadimitriou
            try:
314 bea8a810 Kostas Papadimitriou
                user = AstakosUser.objects.get_by_identifier(username)
315 bea8a810 Kostas Papadimitriou
                if not user.has_auth_provider('local'):
316 9d20fe23 Kostas Papadimitriou
                    provider = auth_providers.get_provider('local', user)
317 e7cb4085 Kostas Papadimitriou
                    msg = provider.get_login_disabled_msg
318 e7cb4085 Kostas Papadimitriou
                    raise forms.ValidationError(mark_safe(msg))
319 bea8a810 Kostas Papadimitriou
            except AstakosUser.DoesNotExist:
320 bea8a810 Kostas Papadimitriou
                pass
321 c4b1a172 Kostas Papadimitriou
322 1f3b4b39 Sofia Papagiannaki
        try:
323 1f3b4b39 Sofia Papagiannaki
            super(LoginForm, self).clean()
324 51db2da2 Giorgos Korfiatis
        except forms.ValidationError:
325 c4b1a172 Kostas Papadimitriou
            if self.user_cache is None:
326 c4b1a172 Kostas Papadimitriou
                raise
327 c4b1a172 Kostas Papadimitriou
            if not self.user_cache.is_active:
328 9d20fe23 Kostas Papadimitriou
                msg = self.user_cache.get_inactive_message('local')
329 9d20fe23 Kostas Papadimitriou
                raise forms.ValidationError(msg)
330 1f3b4b39 Sofia Papagiannaki
            if self.request:
331 1f3b4b39 Sofia Papagiannaki
                if not self.request.session.test_cookie_worked():
332 1f3b4b39 Sofia Papagiannaki
                    raise
333 eedb3923 Sofia Papagiannaki
        return self.cleaned_data
334 64cd4730 Antony Chazapis
335 5ce3ce4f Sofia Papagiannaki
336 890b0eaf Sofia Papagiannaki
class ProfileForm(forms.ModelForm):
337 890b0eaf Sofia Papagiannaki
    """
338 890b0eaf Sofia Papagiannaki
    Subclass of ``ModelForm`` for permiting user to edit his/her profile.
339 9a06d96f Olga Brani
    Most of the fields are readonly since the user is not allowed to change
340 9a06d96f Olga Brani
    them.
341 18ffbee1 Sofia Papagiannaki

342 8fb8d0cf Giorgos Korfiatis
    The class defines a save method which sets ``is_verified`` to True so as
343 8fb8d0cf Giorgos Korfiatis
    the user during the next login will not to be redirected to profile page.
344 890b0eaf Sofia Papagiannaki
    """
345 8fb8d0cf Giorgos Korfiatis
    email = forms.EmailField(label='E-mail address',
346 8fb8d0cf Giorgos Korfiatis
                             help_text='E-mail address')
347 c301698f Sofia Papagiannaki
    renew = forms.BooleanField(label='Renew token', required=False)
348 18ffbee1 Sofia Papagiannaki
349 890b0eaf Sofia Papagiannaki
    class Meta:
350 890b0eaf Sofia Papagiannaki
        model = AstakosUser
351 bebd2649 Kostas Papadimitriou
        fields = ('email', 'first_name', 'last_name')
352 18ffbee1 Sofia Papagiannaki
353 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
354 bf0c6de5 Sofia Papagiannaki
        self.session_key = kwargs.pop('session_key', None)
355 890b0eaf Sofia Papagiannaki
        super(ProfileForm, self).__init__(*args, **kwargs)
356 890b0eaf Sofia Papagiannaki
        instance = getattr(self, 'instance', None)
357 bebd2649 Kostas Papadimitriou
        ro_fields = ('email',)
358 890b0eaf Sofia Papagiannaki
        if instance and instance.id:
359 890b0eaf Sofia Papagiannaki
            for field in ro_fields:
360 890b0eaf Sofia Papagiannaki
                self.fields[field].widget.attrs['readonly'] = True
361 18ffbee1 Sofia Papagiannaki
362 98b84806 Kostas Papadimitriou
    def clean_email(self):
363 98b84806 Kostas Papadimitriou
        return self.instance.email
364 98b84806 Kostas Papadimitriou
365 0eb1f53a Ilias Tsitsimpis
    def save(self, commit=True, **kwargs):
366 0eb1f53a Ilias Tsitsimpis
        user = super(ProfileForm, self).save(commit=False, **kwargs)
367 890b0eaf Sofia Papagiannaki
        user.is_verified = True
368 c301698f Sofia Papagiannaki
        if self.cleaned_data.get('renew'):
369 bf0c6de5 Sofia Papagiannaki
            user.renew_token(
370 bf0c6de5 Sofia Papagiannaki
                flush_sessions=True,
371 bf0c6de5 Sofia Papagiannaki
                current_key=self.session_key
372 bf0c6de5 Sofia Papagiannaki
            )
373 890b0eaf Sofia Papagiannaki
        if commit:
374 0eb1f53a Ilias Tsitsimpis
            user.save(**kwargs)
375 890b0eaf Sofia Papagiannaki
        return user
376 64cd4730 Antony Chazapis
377 5ce3ce4f Sofia Papagiannaki
378 890b0eaf Sofia Papagiannaki
class FeedbackForm(forms.Form):
379 890b0eaf Sofia Papagiannaki
    """
380 890b0eaf Sofia Papagiannaki
    Form for writing feedback.
381 890b0eaf Sofia Papagiannaki
    """
382 0a569195 Sofia Papagiannaki
    feedback_msg = forms.CharField(widget=forms.Textarea, label=u'Message')
383 8f5a3a06 Sofia Papagiannaki
    feedback_data = forms.CharField(widget=forms.HiddenInput(), label='',
384 8f5a3a06 Sofia Papagiannaki
                                    required=False)
385 5ed6816e Sofia Papagiannaki
386 5ce3ce4f Sofia Papagiannaki
387 5ed6816e Sofia Papagiannaki
class SendInvitationForm(forms.Form):
388 5ed6816e Sofia Papagiannaki
    """
389 5ed6816e Sofia Papagiannaki
    Form for sending an invitations
390 5ed6816e Sofia Papagiannaki
    """
391 18ffbee1 Sofia Papagiannaki
392 5ce3ce4f Sofia Papagiannaki
    email = forms.EmailField(required=True, label='Email address')
393 5ce3ce4f Sofia Papagiannaki
    first_name = forms.EmailField(label='First name')
394 5ce3ce4f Sofia Papagiannaki
    last_name = forms.EmailField(label='Last name')
395 5ce3ce4f Sofia Papagiannaki
396 e2125441 Sofia Papagiannaki
397 e2125441 Sofia Papagiannaki
class ExtendedPasswordResetForm(PasswordResetForm):
398 e2125441 Sofia Papagiannaki
    """
399 dd5f8f4d Kostas Papadimitriou
    Extends PasswordResetForm by overriding
400 18ffbee1 Sofia Papagiannaki

401 dd5f8f4d Kostas Papadimitriou
    save method: to pass a custom from_email in send_mail.
402 dd5f8f4d Kostas Papadimitriou
    clean_email: to handle local auth provider checks
403 e2125441 Sofia Papagiannaki
    """
404 23c271b3 Sofia Papagiannaki
    def clean_email(self):
405 9d20fe23 Kostas Papadimitriou
        # we override the default django auth clean_email to provide more
406 9d20fe23 Kostas Papadimitriou
        # detailed messages in case of inactive users
407 9d20fe23 Kostas Papadimitriou
        email = self.cleaned_data['email']
408 23c271b3 Sofia Papagiannaki
        try:
409 dd5f8f4d Kostas Papadimitriou
            user = AstakosUser.objects.get_by_identifier(email)
410 9d20fe23 Kostas Papadimitriou
            self.users_cache = [user]
411 dd5f8f4d Kostas Papadimitriou
            if not user.is_active:
412 e7cb4085 Kostas Papadimitriou
                msg = mark_safe(user.get_inactive_message('local'))
413 e7cb4085 Kostas Papadimitriou
                raise forms.ValidationError(msg)
414 dd5f8f4d Kostas Papadimitriou
415 9d20fe23 Kostas Papadimitriou
            provider = auth_providers.get_provider('local', user)
416 23c271b3 Sofia Papagiannaki
            if not user.has_usable_password():
417 9d20fe23 Kostas Papadimitriou
                msg = provider.get_unusable_password_msg
418 e7cb4085 Kostas Papadimitriou
                raise forms.ValidationError(mark_safe(msg))
419 d2633501 Kostas Papadimitriou
420 d2633501 Kostas Papadimitriou
            if not user.can_change_password():
421 9d20fe23 Kostas Papadimitriou
                msg = provider.get_cannot_change_password_msg
422 e7cb4085 Kostas Papadimitriou
                raise forms.ValidationError(mark_safe(msg))
423 9d20fe23 Kostas Papadimitriou
424 9d20fe23 Kostas Papadimitriou
        except AstakosUser.DoesNotExist:
425 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.EMAIL_UNKNOWN))
426 23c271b3 Sofia Papagiannaki
        return email
427 ab8bfb29 Kostas Papadimitriou
428 8fb8d0cf Giorgos Korfiatis
    def save(self, domain_override=None,
429 8fb8d0cf Giorgos Korfiatis
             email_template_name='registration/password_reset_email.html',
430 8fb8d0cf Giorgos Korfiatis
             use_https=False, token_generator=default_token_generator,
431 0eb1f53a Ilias Tsitsimpis
             request=None, **kwargs):
432 e2125441 Sofia Papagiannaki
        """
433 8fb8d0cf Giorgos Korfiatis
        Generates a one-use only link for resetting password and sends to the
434 8fb8d0cf Giorgos Korfiatis
        user.
435 0a70d2c5 Christos Stavrakakis

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