Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (40.6 kB)

1 aba1e498 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 18ffbee1 Sofia Papagiannaki
#
3 64cd4730 Antony Chazapis
# Redistribution and use in source and binary forms, with or
4 64cd4730 Antony Chazapis
# without modification, are permitted provided that the following
5 64cd4730 Antony Chazapis
# conditions are met:
6 18ffbee1 Sofia Papagiannaki
#
7 64cd4730 Antony Chazapis
#   1. Redistributions of source code must retain the above
8 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
9 64cd4730 Antony Chazapis
#      disclaimer.
10 18ffbee1 Sofia Papagiannaki
#
11 64cd4730 Antony Chazapis
#   2. Redistributions in binary form must reproduce the above
12 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
13 64cd4730 Antony Chazapis
#      disclaimer in the documentation and/or other materials
14 64cd4730 Antony Chazapis
#      provided with the distribution.
15 18ffbee1 Sofia Papagiannaki
#
16 64cd4730 Antony Chazapis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 64cd4730 Antony Chazapis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 64cd4730 Antony Chazapis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 64cd4730 Antony Chazapis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 64cd4730 Antony Chazapis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 64cd4730 Antony Chazapis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 64cd4730 Antony Chazapis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 64cd4730 Antony Chazapis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 64cd4730 Antony Chazapis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 64cd4730 Antony Chazapis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 64cd4730 Antony Chazapis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 64cd4730 Antony Chazapis
# POSSIBILITY OF SUCH DAMAGE.
28 18ffbee1 Sofia Papagiannaki
#
29 64cd4730 Antony Chazapis
# The views and conclusions contained in the software and
30 64cd4730 Antony Chazapis
# documentation are those of the authors and should not be
31 64cd4730 Antony Chazapis
# interpreted as representing official policies, either expressed
32 64cd4730 Antony Chazapis
# or implied, of GRNET S.A.
33 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 734107ef Kostas Papadimitriou
from synnefo_branding.utils import render_to_string
49 d2c9adac Christos Stavrakakis
from synnefo.lib import join_urls
50 3e0a032d Sofia Papagiannaki
from astakos.im.models import AstakosUser, EmailChange, Invitation, Resource, \
51 3e0a032d Sofia Papagiannaki
    PendingThirdPartyUser, get_latest_terms, ProjectApplication, Project
52 75380308 Kostas Papadimitriou
from astakos.im import presentation
53 45f8d9ff Sofia Papagiannaki
from astakos.im.widgets import DummyWidget, RecaptchaWidget
54 3e0a032d Sofia Papagiannaki
from astakos.im.functions import send_change_email, submit_application, \
55 f12bcb3d Giorgos Korfiatis
    accept_membership_project_checks, ProjectError
56 270dd48d Sofia Papagiannaki
57 3e0a032d Sofia Papagiannaki
from astakos.im.util import reserved_verified_email, model_to_dict
58 c4b1a172 Kostas Papadimitriou
from astakos.im import auth_providers
59 8998f09a Sofia Papagiannaki
from astakos.im import settings
60 64cd4730 Antony Chazapis
61 ae497612 Olga Brani
import astakos.im.messages as astakos_messages
62 64cd4730 Antony Chazapis
63 3bf924ec Sofia Papagiannaki
import logging
64 49790d9d Sofia Papagiannaki
import hashlib
65 db7fecd9 Sofia Papagiannaki
import recaptcha.client.captcha as captcha
66 caf70869 Sofia Papagiannaki
import re
67 64cd4730 Antony Chazapis
68 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
69 e015e9e6 Sofia Papagiannaki
70 caf70869 Sofia Papagiannaki
DOMAIN_VALUE_REGEX = re.compile(
71 892410d3 Sofia Papagiannaki
    r'^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$',
72 73fbaec4 Sofia Papagiannaki
    re.IGNORECASE)
73 d2633501 Kostas Papadimitriou
74 e7cb4085 Kostas Papadimitriou
75 caf70869 Sofia Papagiannaki
class StoreUserMixin(object):
76 e5966bd9 Kostas Papadimitriou
77 e7cb4085 Kostas Papadimitriou
    def store_user(self, user, request=None):
78 43332a76 Kostas Papadimitriou
        """
79 43332a76 Kostas Papadimitriou
        WARNING: this should be wrapped inside a transactional view/method.
80 43332a76 Kostas Papadimitriou
        """
81 d2633501 Kostas Papadimitriou
        user.save()
82 d2633501 Kostas Papadimitriou
        self.post_store_user(user, request)
83 d2633501 Kostas Papadimitriou
        return user
84 d2633501 Kostas Papadimitriou
85 d2633501 Kostas Papadimitriou
    def post_store_user(self, user, request):
86 d2633501 Kostas Papadimitriou
        """
87 d2633501 Kostas Papadimitriou
        Interface method for descendant backends to be able to do stuff within
88 d2633501 Kostas Papadimitriou
        the transaction enabled by store_user.
89 d2633501 Kostas Papadimitriou
        """
90 d2633501 Kostas Papadimitriou
        pass
91 d2633501 Kostas Papadimitriou
92 d2633501 Kostas Papadimitriou
93 d2633501 Kostas Papadimitriou
class LocalUserCreationForm(UserCreationForm, StoreUserMixin):
94 890b0eaf Sofia Papagiannaki
    """
95 890b0eaf Sofia Papagiannaki
    Extends the built in UserCreationForm in several ways:
96 18ffbee1 Sofia Papagiannaki

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

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

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