Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (40.8 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 890b0eaf Sofia Papagiannaki
    def save(self, commit=True):
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 15efc749 Sofia Papagiannaki
        user = super(LocalUserCreationForm, self).save(commit=False)
194 e7cb4085 Kostas Papadimitriou
        user.date_signed_terms = datetime.now()
195 d2633501 Kostas Papadimitriou
        user.renew_token()
196 9fb8e808 Sofia Papagiannaki
        if commit:
197 9fb8e808 Sofia Papagiannaki
            user.save()
198 e7cb4085 Kostas Papadimitriou
            logger.info('Created user %s', user.log_display)
199 890b0eaf Sofia Papagiannaki
        return user
200 64cd4730 Antony Chazapis
201 5ce3ce4f Sofia Papagiannaki
202 15efc749 Sofia Papagiannaki
class InvitedLocalUserCreationForm(LocalUserCreationForm):
203 890b0eaf Sofia Papagiannaki
    """
204 062c970c Sofia Papagiannaki
    Extends the LocalUserCreationForm: email is readonly.
205 890b0eaf Sofia Papagiannaki
    """
206 794852f2 Sofia Papagiannaki
    class Meta:
207 794852f2 Sofia Papagiannaki
        model = AstakosUser
208 270dd48d Sofia Papagiannaki
        fields = ("email", "first_name", "last_name", "has_signed_terms")
209 18ffbee1 Sofia Papagiannaki
210 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
211 64cd4730 Antony Chazapis
        """
212 3bf924ec Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
213 64cd4730 Antony Chazapis
        """
214 15efc749 Sofia Papagiannaki
        super(InvitedLocalUserCreationForm, self).__init__(*args, **kwargs)
215 18ffbee1 Sofia Papagiannaki
216 64cd4730 Antony Chazapis
        #set readonly form fields
217 062c970c Sofia Papagiannaki
        ro = ('email', 'username',)
218 4e30244e Sofia Papagiannaki
        for f in ro:
219 4e30244e Sofia Papagiannaki
            self.fields[f].widget.attrs['readonly'] = True
220 ab8bfb29 Kostas Papadimitriou
221 9fb8e808 Sofia Papagiannaki
    def save(self, commit=True):
222 15efc749 Sofia Papagiannaki
        user = super(InvitedLocalUserCreationForm, self).save(commit=False)
223 74836e50 Sofia Papagiannaki
        user.set_invitations_level()
224 8316698a Sofia Papagiannaki
        user.email_verified = True
225 9fb8e808 Sofia Papagiannaki
        if commit:
226 9fb8e808 Sofia Papagiannaki
            user.save()
227 9fb8e808 Sofia Papagiannaki
        return user
228 5ed6816e Sofia Papagiannaki
229 d2633501 Kostas Papadimitriou
230 d2633501 Kostas Papadimitriou
class ThirdPartyUserCreationForm(forms.ModelForm, StoreUserMixin):
231 1177e91b Olga Brani
    email = forms.EmailField(
232 1177e91b Olga Brani
        label='Contact email',
233 e7cb4085 Kostas Papadimitriou
        help_text='This is needed for contact purposes. '
234 e7cb4085 Kostas Papadimitriou
        'It doesn&#39;t need to be the same with the one you '
235 d6ea9b3d Olga Brani
        'provided to login previously. '
236 1177e91b Olga Brani
    )
237 43332a76 Kostas Papadimitriou
238 8f5a3a06 Sofia Papagiannaki
    class Meta:
239 8f5a3a06 Sofia Papagiannaki
        model = AstakosUser
240 e7cb4085 Kostas Papadimitriou
        fields = ['email', 'first_name', 'last_name', 'has_signed_terms']
241 ab8bfb29 Kostas Papadimitriou
242 8f5a3a06 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
243 8f5a3a06 Sofia Papagiannaki
        """
244 8f5a3a06 Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
245 8f5a3a06 Sofia Papagiannaki
        """
246 e7cb4085 Kostas Papadimitriou
247 e7cb4085 Kostas Papadimitriou
        self.provider = kwargs.pop('provider', None)
248 139eae46 Kostas Papadimitriou
        self.request = kwargs.pop('request', None)
249 e7cb4085 Kostas Papadimitriou
        if not self.provider or self.provider == 'local':
250 e7cb4085 Kostas Papadimitriou
            raise Exception('Invalid provider, %r' % self.provider)
251 e7cb4085 Kostas Papadimitriou
252 e7cb4085 Kostas Papadimitriou
        # ThirdPartyUserCreationForm should always get instantiated with
253 e7cb4085 Kostas Papadimitriou
        # a third_party_token value
254 e7cb4085 Kostas Papadimitriou
        self.third_party_token = kwargs.pop('third_party_token', None)
255 e7cb4085 Kostas Papadimitriou
        if not self.third_party_token:
256 e7cb4085 Kostas Papadimitriou
            raise Exception('ThirdPartyUserCreationForm'
257 e7cb4085 Kostas Papadimitriou
                            ' requires third_party_token')
258 2e90e3ec Kostas Papadimitriou
259 8f5a3a06 Sofia Papagiannaki
        super(ThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
260 2e90e3ec Kostas Papadimitriou
261 4a13d054 Kostas Papadimitriou
        if not get_latest_terms():
262 4a13d054 Kostas Papadimitriou
            del self.fields['has_signed_terms']
263 4a13d054 Kostas Papadimitriou
264 18ffbee1 Sofia Papagiannaki
        if 'has_signed_terms' in self.fields:
265 18ffbee1 Sofia Papagiannaki
            # Overriding field label since we need to apply a link
266 18ffbee1 Sofia Papagiannaki
            # to the terms within the label
267 18ffbee1 Sofia Papagiannaki
            terms_link_html = '<a href="%s" target="_blank">%s</a>' \
268 5ce3ce4f Sofia Papagiannaki
                % (reverse('latest_terms'), _("the terms"))
269 18ffbee1 Sofia Papagiannaki
            self.fields['has_signed_terms'].label = \
270 9d20fe23 Kostas Papadimitriou
                mark_safe("I agree with %s" % terms_link_html)
271 2e90e3ec Kostas Papadimitriou
272 18ffbee1 Sofia Papagiannaki
    def clean_email(self):
273 e5966bd9 Kostas Papadimitriou
        email = self.cleaned_data['email']
274 18ffbee1 Sofia Papagiannaki
        if not email:
275 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.REQUIRED_FIELD))
276 43332a76 Kostas Papadimitriou
        if reserved_verified_email(email):
277 e7cb4085 Kostas Papadimitriou
            provider_id = self.provider
278 9d20fe23 Kostas Papadimitriou
            provider = auth_providers.get_provider(provider_id)
279 9d20fe23 Kostas Papadimitriou
            extra_message = provider.get_add_to_existing_account_msg
280 564a2292 Kostas Papadimitriou
281 e7cb4085 Kostas Papadimitriou
            raise forms.ValidationError(mark_safe(
282 e7cb4085 Kostas Papadimitriou
                _(astakos_messages.EMAIL_USED) + ' ' + extra_message))
283 0a569195 Sofia Papagiannaki
        return email
284 ab8bfb29 Kostas Papadimitriou
285 18ffbee1 Sofia Papagiannaki
    def clean_has_signed_terms(self):
286 18ffbee1 Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
287 18ffbee1 Sofia Papagiannaki
        if not has_signed_terms:
288 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
289 18ffbee1 Sofia Papagiannaki
        return has_signed_terms
290 ab8bfb29 Kostas Papadimitriou
291 e7cb4085 Kostas Papadimitriou
    def _get_pending_user(self):
292 e7cb4085 Kostas Papadimitriou
        return PendingThirdPartyUser.objects.get(token=self.third_party_token)
293 e7cb4085 Kostas Papadimitriou
294 e7cb4085 Kostas Papadimitriou
    def post_store_user(self, user, request=None):
295 e7cb4085 Kostas Papadimitriou
        pending = self._get_pending_user()
296 9d20fe23 Kostas Papadimitriou
        provider = pending.get_provider(user)
297 9d20fe23 Kostas Papadimitriou
        provider.add_to_user()
298 9d20fe23 Kostas Papadimitriou
        pending.delete()
299 d2633501 Kostas Papadimitriou
300 8f5a3a06 Sofia Papagiannaki
    def save(self, commit=True):
301 8f5a3a06 Sofia Papagiannaki
        user = super(ThirdPartyUserCreationForm, self).save(commit=False)
302 8f5a3a06 Sofia Papagiannaki
        user.set_unusable_password()
303 d2633501 Kostas Papadimitriou
        user.renew_token()
304 e7cb4085 Kostas Papadimitriou
        user.date_signed_terms = datetime.now()
305 8f5a3a06 Sofia Papagiannaki
        if commit:
306 8f5a3a06 Sofia Papagiannaki
            user.save()
307 e7cb4085 Kostas Papadimitriou
            logger.info('Created user %s' % user.log_display)
308 8f5a3a06 Sofia Papagiannaki
        return user
309 8f5a3a06 Sofia Papagiannaki
310 5ce3ce4f Sofia Papagiannaki
311 8f5a3a06 Sofia Papagiannaki
class InvitedThirdPartyUserCreationForm(ThirdPartyUserCreationForm):
312 4e30244e Sofia Papagiannaki
    """
313 062c970c Sofia Papagiannaki
    Extends the ThirdPartyUserCreationForm: email is readonly.
314 4e30244e Sofia Papagiannaki
    """
315 8f5a3a06 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
316 4e30244e Sofia Papagiannaki
        """
317 4e30244e Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
318 4e30244e Sofia Papagiannaki
        """
319 5ce3ce4f Sofia Papagiannaki
        super(
320 5ce3ce4f Sofia Papagiannaki
            InvitedThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
321 4e30244e Sofia Papagiannaki
322 8f5a3a06 Sofia Papagiannaki
        #set readonly form fields
323 062c970c Sofia Papagiannaki
        ro = ('email',)
324 4e30244e Sofia Papagiannaki
        for f in ro:
325 4e30244e Sofia Papagiannaki
            self.fields[f].widget.attrs['readonly'] = True
326 ab8bfb29 Kostas Papadimitriou
327 4e30244e Sofia Papagiannaki
    def save(self, commit=True):
328 8fb8d0cf Giorgos Korfiatis
        user = super(
329 8fb8d0cf Giorgos Korfiatis
            InvitedThirdPartyUserCreationForm, self).save(commit=False)
330 d2633501 Kostas Papadimitriou
        user.set_invitation_level()
331 4e30244e Sofia Papagiannaki
        user.email_verified = True
332 4e30244e Sofia Papagiannaki
        if commit:
333 4e30244e Sofia Papagiannaki
            user.save()
334 4e30244e Sofia Papagiannaki
        return user
335 8f5a3a06 Sofia Papagiannaki
336 5ce3ce4f Sofia Papagiannaki
337 18ffbee1 Sofia Papagiannaki
class ShibbolethUserCreationForm(ThirdPartyUserCreationForm):
338 5ce3ce4f Sofia Papagiannaki
    additional_email = forms.CharField(
339 5ce3ce4f Sofia Papagiannaki
        widget=forms.HiddenInput(), label='', required=False)
340 ab8bfb29 Kostas Papadimitriou
341 ca828a10 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
342 ca828a10 Sofia Papagiannaki
        super(ShibbolethUserCreationForm, self).__init__(*args, **kwargs)
343 ca828a10 Sofia Papagiannaki
        # copy email value to additional_mail in case user will change it
344 ca828a10 Sofia Papagiannaki
        name = 'email'
345 ca828a10 Sofia Papagiannaki
        field = self.fields[name]
346 8fb8d0cf Giorgos Korfiatis
        self.initial['additional_email'] = self.initial.get(
347 8fb8d0cf Giorgos Korfiatis
            name, field.initial)
348 ef20ea07 Sofia Papagiannaki
        self.initial['email'] = None
349 d2633501 Kostas Papadimitriou
350 4e30244e Sofia Papagiannaki
351 9a06d96f Olga Brani
class InvitedShibbolethUserCreationForm(ShibbolethUserCreationForm,
352 9a06d96f Olga Brani
                                        InvitedThirdPartyUserCreationForm):
353 4e30244e Sofia Papagiannaki
    pass
354 ab8bfb29 Kostas Papadimitriou
355 5ce3ce4f Sofia Papagiannaki
356 5ed6816e Sofia Papagiannaki
class LoginForm(AuthenticationForm):
357 5ed6816e Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
358 672d445a Sofia Papagiannaki
    recaptcha_challenge_field = forms.CharField(widget=DummyWidget)
359 5ce3ce4f Sofia Papagiannaki
    recaptcha_response_field = forms.CharField(
360 5ce3ce4f Sofia Papagiannaki
        widget=RecaptchaWidget, label='')
361 ab8bfb29 Kostas Papadimitriou
362 672d445a Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
363 672d445a Sofia Papagiannaki
        was_limited = kwargs.get('was_limited', False)
364 672d445a Sofia Papagiannaki
        request = kwargs.get('request', None)
365 672d445a Sofia Papagiannaki
        if request:
366 8fb8d0cf Giorgos Korfiatis
            self.ip = request.META.get(
367 8fb8d0cf Giorgos Korfiatis
                'REMOTE_ADDR',
368 8fb8d0cf Giorgos Korfiatis
                request.META.get('HTTP_X_REAL_IP', None))
369 ab8bfb29 Kostas Papadimitriou
370 672d445a Sofia Papagiannaki
        t = ('request', 'was_limited')
371 672d445a Sofia Papagiannaki
        for elem in t:
372 672d445a Sofia Papagiannaki
            if elem in kwargs.keys():
373 672d445a Sofia Papagiannaki
                kwargs.pop(elem)
374 672d445a Sofia Papagiannaki
        super(LoginForm, self).__init__(*args, **kwargs)
375 ab8bfb29 Kostas Papadimitriou
376 672d445a Sofia Papagiannaki
        self.fields.keyOrder = ['username', 'password']
377 8998f09a Sofia Papagiannaki
        if was_limited and settings.RECAPTCHA_ENABLED:
378 672d445a Sofia Papagiannaki
            self.fields.keyOrder.extend(['recaptcha_challenge_field',
379 5ce3ce4f Sofia Papagiannaki
                                         'recaptcha_response_field', ])
380 9a06d96f Olga Brani
381 9a06d96f Olga Brani
    def clean_username(self):
382 4bdd7e3d Kostas Papadimitriou
        return self.cleaned_data['username'].lower()
383 ab8bfb29 Kostas Papadimitriou
384 672d445a Sofia Papagiannaki
    def clean_recaptcha_response_field(self):
385 672d445a Sofia Papagiannaki
        if 'recaptcha_challenge_field' in self.cleaned_data:
386 672d445a Sofia Papagiannaki
            self.validate_captcha()
387 672d445a Sofia Papagiannaki
        return self.cleaned_data['recaptcha_response_field']
388 672d445a Sofia Papagiannaki
389 672d445a Sofia Papagiannaki
    def clean_recaptcha_challenge_field(self):
390 672d445a Sofia Papagiannaki
        if 'recaptcha_response_field' in self.cleaned_data:
391 672d445a Sofia Papagiannaki
            self.validate_captcha()
392 672d445a Sofia Papagiannaki
        return self.cleaned_data['recaptcha_challenge_field']
393 672d445a Sofia Papagiannaki
394 672d445a Sofia Papagiannaki
    def validate_captcha(self):
395 672d445a Sofia Papagiannaki
        rcf = self.cleaned_data['recaptcha_challenge_field']
396 672d445a Sofia Papagiannaki
        rrf = self.cleaned_data['recaptcha_response_field']
397 8998f09a Sofia Papagiannaki
        check = captcha.submit(
398 8998f09a Sofia Papagiannaki
            rcf, rrf, settings.RECAPTCHA_PRIVATE_KEY, self.ip)
399 672d445a Sofia Papagiannaki
        if not check.is_valid:
400 8998f09a Sofia Papagiannaki
            raise forms.ValidationError(_(
401 8998f09a Sofia Papagiannaki
                astakos_messages.CAPTCHA_VALIDATION_ERR))
402 2e90e3ec Kostas Papadimitriou
403 eedb3923 Sofia Papagiannaki
    def clean(self):
404 1f3b4b39 Sofia Papagiannaki
        """
405 1f3b4b39 Sofia Papagiannaki
        Override default behavior in order to check user's activation later
406 1f3b4b39 Sofia Papagiannaki
        """
407 c4b1a172 Kostas Papadimitriou
        username = self.cleaned_data.get('username')
408 c4b1a172 Kostas Papadimitriou
409 bea8a810 Kostas Papadimitriou
        if username:
410 bea8a810 Kostas Papadimitriou
            try:
411 bea8a810 Kostas Papadimitriou
                user = AstakosUser.objects.get_by_identifier(username)
412 bea8a810 Kostas Papadimitriou
                if not user.has_auth_provider('local'):
413 9d20fe23 Kostas Papadimitriou
                    provider = auth_providers.get_provider('local', user)
414 e7cb4085 Kostas Papadimitriou
                    msg = provider.get_login_disabled_msg
415 e7cb4085 Kostas Papadimitriou
                    raise forms.ValidationError(mark_safe(msg))
416 bea8a810 Kostas Papadimitriou
            except AstakosUser.DoesNotExist:
417 bea8a810 Kostas Papadimitriou
                pass
418 c4b1a172 Kostas Papadimitriou
419 1f3b4b39 Sofia Papagiannaki
        try:
420 1f3b4b39 Sofia Papagiannaki
            super(LoginForm, self).clean()
421 51db2da2 Giorgos Korfiatis
        except forms.ValidationError:
422 c4b1a172 Kostas Papadimitriou
            if self.user_cache is None:
423 c4b1a172 Kostas Papadimitriou
                raise
424 c4b1a172 Kostas Papadimitriou
            if not self.user_cache.is_active:
425 9d20fe23 Kostas Papadimitriou
                msg = self.user_cache.get_inactive_message('local')
426 9d20fe23 Kostas Papadimitriou
                raise forms.ValidationError(msg)
427 1f3b4b39 Sofia Papagiannaki
            if self.request:
428 1f3b4b39 Sofia Papagiannaki
                if not self.request.session.test_cookie_worked():
429 1f3b4b39 Sofia Papagiannaki
                    raise
430 eedb3923 Sofia Papagiannaki
        return self.cleaned_data
431 64cd4730 Antony Chazapis
432 5ce3ce4f Sofia Papagiannaki
433 890b0eaf Sofia Papagiannaki
class ProfileForm(forms.ModelForm):
434 890b0eaf Sofia Papagiannaki
    """
435 890b0eaf Sofia Papagiannaki
    Subclass of ``ModelForm`` for permiting user to edit his/her profile.
436 9a06d96f Olga Brani
    Most of the fields are readonly since the user is not allowed to change
437 9a06d96f Olga Brani
    them.
438 18ffbee1 Sofia Papagiannaki

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

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