Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / forms.py @ 5ae8216a

History | View | Annotate | Download (39 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 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 64cd4730 Antony Chazapis
62 ae497612 Olga Brani
import astakos.im.messages as astakos_messages
63 64cd4730 Antony Chazapis
64 3bf924ec Sofia Papagiannaki
import logging
65 49790d9d Sofia Papagiannaki
import hashlib
66 db7fecd9 Sofia Papagiannaki
import recaptcha.client.captcha as captcha
67 caf70869 Sofia Papagiannaki
import re
68 64cd4730 Antony Chazapis
69 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
70 e015e9e6 Sofia Papagiannaki
71 caf70869 Sofia Papagiannaki
DOMAIN_VALUE_REGEX = re.compile(
72 892410d3 Sofia Papagiannaki
    r'^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$',
73 73fbaec4 Sofia Papagiannaki
    re.IGNORECASE)
74 d2633501 Kostas Papadimitriou
75 e7cb4085 Kostas Papadimitriou
76 caf70869 Sofia Papagiannaki
class StoreUserMixin(object):
77 e5966bd9 Kostas Papadimitriou
78 e7cb4085 Kostas Papadimitriou
    def store_user(self, user, request=None):
79 43332a76 Kostas Papadimitriou
        """
80 43332a76 Kostas Papadimitriou
        WARNING: this should be wrapped inside a transactional view/method.
81 43332a76 Kostas Papadimitriou
        """
82 d2633501 Kostas Papadimitriou
        user.save()
83 d2633501 Kostas Papadimitriou
        self.post_store_user(user, request)
84 d2633501 Kostas Papadimitriou
        return user
85 d2633501 Kostas Papadimitriou
86 d2633501 Kostas Papadimitriou
    def post_store_user(self, user, request):
87 d2633501 Kostas Papadimitriou
        """
88 d2633501 Kostas Papadimitriou
        Interface method for descendant backends to be able to do stuff within
89 d2633501 Kostas Papadimitriou
        the transaction enabled by store_user.
90 d2633501 Kostas Papadimitriou
        """
91 d2633501 Kostas Papadimitriou
        pass
92 d2633501 Kostas Papadimitriou
93 d2633501 Kostas Papadimitriou
94 d2633501 Kostas Papadimitriou
class LocalUserCreationForm(UserCreationForm, StoreUserMixin):
95 890b0eaf Sofia Papagiannaki
    """
96 890b0eaf Sofia Papagiannaki
    Extends the built in UserCreationForm in several ways:
97 18ffbee1 Sofia Papagiannaki

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

369 8fb8d0cf Giorgos Korfiatis
    The class defines a save method which sets ``is_verified`` to True so as
370 8fb8d0cf Giorgos Korfiatis
    the user during the next login will not to be redirected to profile page.
371 890b0eaf Sofia Papagiannaki
    """
372 8fb8d0cf Giorgos Korfiatis
    email = forms.EmailField(label='E-mail address',
373 8fb8d0cf Giorgos Korfiatis
                             help_text='E-mail address')
374 c301698f Sofia Papagiannaki
    renew = forms.BooleanField(label='Renew token', required=False)
375 18ffbee1 Sofia Papagiannaki
376 890b0eaf Sofia Papagiannaki
    class Meta:
377 890b0eaf Sofia Papagiannaki
        model = AstakosUser
378 bebd2649 Kostas Papadimitriou
        fields = ('email', 'first_name', 'last_name')
379 18ffbee1 Sofia Papagiannaki
380 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
381 bf0c6de5 Sofia Papagiannaki
        self.session_key = kwargs.pop('session_key', None)
382 890b0eaf Sofia Papagiannaki
        super(ProfileForm, self).__init__(*args, **kwargs)
383 890b0eaf Sofia Papagiannaki
        instance = getattr(self, 'instance', None)
384 bebd2649 Kostas Papadimitriou
        ro_fields = ('email',)
385 890b0eaf Sofia Papagiannaki
        if instance and instance.id:
386 890b0eaf Sofia Papagiannaki
            for field in ro_fields:
387 890b0eaf Sofia Papagiannaki
                self.fields[field].widget.attrs['readonly'] = True
388 18ffbee1 Sofia Papagiannaki
389 98b84806 Kostas Papadimitriou
    def clean_email(self):
390 98b84806 Kostas Papadimitriou
        return self.instance.email
391 98b84806 Kostas Papadimitriou
392 0eb1f53a Ilias Tsitsimpis
    def save(self, commit=True, **kwargs):
393 0eb1f53a Ilias Tsitsimpis
        user = super(ProfileForm, self).save(commit=False, **kwargs)
394 890b0eaf Sofia Papagiannaki
        user.is_verified = True
395 c301698f Sofia Papagiannaki
        if self.cleaned_data.get('renew'):
396 bf0c6de5 Sofia Papagiannaki
            user.renew_token(
397 bf0c6de5 Sofia Papagiannaki
                flush_sessions=True,
398 bf0c6de5 Sofia Papagiannaki
                current_key=self.session_key
399 bf0c6de5 Sofia Papagiannaki
            )
400 890b0eaf Sofia Papagiannaki
        if commit:
401 0eb1f53a Ilias Tsitsimpis
            user.save(**kwargs)
402 890b0eaf Sofia Papagiannaki
        return user
403 64cd4730 Antony Chazapis
404 5ce3ce4f Sofia Papagiannaki
405 890b0eaf Sofia Papagiannaki
class FeedbackForm(forms.Form):
406 890b0eaf Sofia Papagiannaki
    """
407 890b0eaf Sofia Papagiannaki
    Form for writing feedback.
408 890b0eaf Sofia Papagiannaki
    """
409 0a569195 Sofia Papagiannaki
    feedback_msg = forms.CharField(widget=forms.Textarea, label=u'Message')
410 8f5a3a06 Sofia Papagiannaki
    feedback_data = forms.CharField(widget=forms.HiddenInput(), label='',
411 8f5a3a06 Sofia Papagiannaki
                                    required=False)
412 5ed6816e Sofia Papagiannaki
413 5ce3ce4f Sofia Papagiannaki
414 5ed6816e Sofia Papagiannaki
class SendInvitationForm(forms.Form):
415 5ed6816e Sofia Papagiannaki
    """
416 5ed6816e Sofia Papagiannaki
    Form for sending an invitations
417 5ed6816e Sofia Papagiannaki
    """
418 18ffbee1 Sofia Papagiannaki
419 5ce3ce4f Sofia Papagiannaki
    email = forms.EmailField(required=True, label='Email address')
420 5ce3ce4f Sofia Papagiannaki
    first_name = forms.EmailField(label='First name')
421 5ce3ce4f Sofia Papagiannaki
    last_name = forms.EmailField(label='Last name')
422 5ce3ce4f Sofia Papagiannaki
423 e2125441 Sofia Papagiannaki
424 e2125441 Sofia Papagiannaki
class ExtendedPasswordResetForm(PasswordResetForm):
425 e2125441 Sofia Papagiannaki
    """
426 dd5f8f4d Kostas Papadimitriou
    Extends PasswordResetForm by overriding
427 18ffbee1 Sofia Papagiannaki

428 dd5f8f4d Kostas Papadimitriou
    save method: to pass a custom from_email in send_mail.
429 dd5f8f4d Kostas Papadimitriou
    clean_email: to handle local auth provider checks
430 e2125441 Sofia Papagiannaki
    """
431 23c271b3 Sofia Papagiannaki
    def clean_email(self):
432 9d20fe23 Kostas Papadimitriou
        # we override the default django auth clean_email to provide more
433 9d20fe23 Kostas Papadimitriou
        # detailed messages in case of inactive users
434 9d20fe23 Kostas Papadimitriou
        email = self.cleaned_data['email']
435 23c271b3 Sofia Papagiannaki
        try:
436 dd5f8f4d Kostas Papadimitriou
            user = AstakosUser.objects.get_by_identifier(email)
437 9d20fe23 Kostas Papadimitriou
            self.users_cache = [user]
438 dd5f8f4d Kostas Papadimitriou
            if not user.is_active:
439 e7cb4085 Kostas Papadimitriou
                msg = mark_safe(user.get_inactive_message('local'))
440 e7cb4085 Kostas Papadimitriou
                raise forms.ValidationError(msg)
441 dd5f8f4d Kostas Papadimitriou
442 9d20fe23 Kostas Papadimitriou
            provider = auth_providers.get_provider('local', user)
443 23c271b3 Sofia Papagiannaki
            if not user.has_usable_password():
444 9d20fe23 Kostas Papadimitriou
                msg = provider.get_unusable_password_msg
445 e7cb4085 Kostas Papadimitriou
                raise forms.ValidationError(mark_safe(msg))
446 d2633501 Kostas Papadimitriou
447 d2633501 Kostas Papadimitriou
            if not user.can_change_password():
448 9d20fe23 Kostas Papadimitriou
                msg = provider.get_cannot_change_password_msg
449 e7cb4085 Kostas Papadimitriou
                raise forms.ValidationError(mark_safe(msg))
450 9d20fe23 Kostas Papadimitriou
451 9d20fe23 Kostas Papadimitriou
        except AstakosUser.DoesNotExist:
452 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.EMAIL_UNKNOWN))
453 23c271b3 Sofia Papagiannaki
        return email
454 ab8bfb29 Kostas Papadimitriou
455 8fb8d0cf Giorgos Korfiatis
    def save(self, domain_override=None,
456 8fb8d0cf Giorgos Korfiatis
             email_template_name='registration/password_reset_email.html',
457 8fb8d0cf Giorgos Korfiatis
             use_https=False, token_generator=default_token_generator,
458 0eb1f53a Ilias Tsitsimpis
             request=None, **kwargs):
459 e2125441 Sofia Papagiannaki
        """
460 8fb8d0cf Giorgos Korfiatis
        Generates a one-use only link for resetting password and sends to the
461 8fb8d0cf Giorgos Korfiatis
        user.
462 0a70d2c5 Christos Stavrakakis

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