Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / forms.py @ 8998f09a

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 e47fb17a Sofia Papagiannaki
from django.core.exceptions import PermissionDenied
48 5ed6816e Sofia Papagiannaki
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 3e0a032d Sofia Papagiannaki
    accept_membership_checks
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 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 e7cb4085 Kostas Papadimitriou
        if not self.provider or self.provider == 'local':
248 e7cb4085 Kostas Papadimitriou
            raise Exception('Invalid provider, %r' % self.provider)
249 e7cb4085 Kostas Papadimitriou
250 e7cb4085 Kostas Papadimitriou
        # ThirdPartyUserCreationForm should always get instantiated with
251 e7cb4085 Kostas Papadimitriou
        # a third_party_token value
252 e7cb4085 Kostas Papadimitriou
        self.third_party_token = kwargs.pop('third_party_token', None)
253 e7cb4085 Kostas Papadimitriou
        if not self.third_party_token:
254 e7cb4085 Kostas Papadimitriou
            raise Exception('ThirdPartyUserCreationForm'
255 e7cb4085 Kostas Papadimitriou
                            ' requires third_party_token')
256 2e90e3ec Kostas Papadimitriou
257 8f5a3a06 Sofia Papagiannaki
        super(ThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
258 2e90e3ec Kostas Papadimitriou
259 4a13d054 Kostas Papadimitriou
        if not get_latest_terms():
260 4a13d054 Kostas Papadimitriou
            del self.fields['has_signed_terms']
261 4a13d054 Kostas Papadimitriou
262 18ffbee1 Sofia Papagiannaki
        if 'has_signed_terms' in self.fields:
263 18ffbee1 Sofia Papagiannaki
            # Overriding field label since we need to apply a link
264 18ffbee1 Sofia Papagiannaki
            # to the terms within the label
265 18ffbee1 Sofia Papagiannaki
            terms_link_html = '<a href="%s" target="_blank">%s</a>' \
266 5ce3ce4f Sofia Papagiannaki
                % (reverse('latest_terms'), _("the terms"))
267 18ffbee1 Sofia Papagiannaki
            self.fields['has_signed_terms'].label = \
268 9d20fe23 Kostas Papadimitriou
                mark_safe("I agree with %s" % terms_link_html)
269 2e90e3ec Kostas Papadimitriou
270 18ffbee1 Sofia Papagiannaki
    def clean_email(self):
271 e5966bd9 Kostas Papadimitriou
        email = self.cleaned_data['email']
272 18ffbee1 Sofia Papagiannaki
        if not email:
273 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.REQUIRED_FIELD))
274 43332a76 Kostas Papadimitriou
        if reserved_verified_email(email):
275 e7cb4085 Kostas Papadimitriou
            provider_id = self.provider
276 9d20fe23 Kostas Papadimitriou
            provider = auth_providers.get_provider(provider_id)
277 9d20fe23 Kostas Papadimitriou
            extra_message = provider.get_add_to_existing_account_msg
278 564a2292 Kostas Papadimitriou
279 e7cb4085 Kostas Papadimitriou
            raise forms.ValidationError(mark_safe(
280 e7cb4085 Kostas Papadimitriou
                _(astakos_messages.EMAIL_USED) + ' ' + extra_message))
281 0a569195 Sofia Papagiannaki
        return email
282 ab8bfb29 Kostas Papadimitriou
283 18ffbee1 Sofia Papagiannaki
    def clean_has_signed_terms(self):
284 18ffbee1 Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
285 18ffbee1 Sofia Papagiannaki
        if not has_signed_terms:
286 ae497612 Olga Brani
            raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
287 18ffbee1 Sofia Papagiannaki
        return has_signed_terms
288 ab8bfb29 Kostas Papadimitriou
289 e7cb4085 Kostas Papadimitriou
    def _get_pending_user(self):
290 e7cb4085 Kostas Papadimitriou
        return PendingThirdPartyUser.objects.get(token=self.third_party_token)
291 e7cb4085 Kostas Papadimitriou
292 e7cb4085 Kostas Papadimitriou
    def post_store_user(self, user, request=None):
293 e7cb4085 Kostas Papadimitriou
        pending = self._get_pending_user()
294 9d20fe23 Kostas Papadimitriou
        provider = pending.get_provider(user)
295 9d20fe23 Kostas Papadimitriou
        provider.add_to_user()
296 9d20fe23 Kostas Papadimitriou
        pending.delete()
297 d2633501 Kostas Papadimitriou
298 8f5a3a06 Sofia Papagiannaki
    def save(self, commit=True):
299 8f5a3a06 Sofia Papagiannaki
        user = super(ThirdPartyUserCreationForm, self).save(commit=False)
300 8f5a3a06 Sofia Papagiannaki
        user.set_unusable_password()
301 d2633501 Kostas Papadimitriou
        user.renew_token()
302 e7cb4085 Kostas Papadimitriou
        user.date_signed_terms = datetime.now()
303 8f5a3a06 Sofia Papagiannaki
        if commit:
304 8f5a3a06 Sofia Papagiannaki
            user.save()
305 e7cb4085 Kostas Papadimitriou
            logger.info('Created user %s' % user.log_display)
306 8f5a3a06 Sofia Papagiannaki
        return user
307 8f5a3a06 Sofia Papagiannaki
308 5ce3ce4f Sofia Papagiannaki
309 8f5a3a06 Sofia Papagiannaki
class InvitedThirdPartyUserCreationForm(ThirdPartyUserCreationForm):
310 4e30244e Sofia Papagiannaki
    """
311 062c970c Sofia Papagiannaki
    Extends the ThirdPartyUserCreationForm: email is readonly.
312 4e30244e Sofia Papagiannaki
    """
313 8f5a3a06 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
314 4e30244e Sofia Papagiannaki
        """
315 4e30244e Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
316 4e30244e Sofia Papagiannaki
        """
317 5ce3ce4f Sofia Papagiannaki
        super(
318 5ce3ce4f Sofia Papagiannaki
            InvitedThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
319 4e30244e Sofia Papagiannaki
320 8f5a3a06 Sofia Papagiannaki
        #set readonly form fields
321 062c970c Sofia Papagiannaki
        ro = ('email',)
322 4e30244e Sofia Papagiannaki
        for f in ro:
323 4e30244e Sofia Papagiannaki
            self.fields[f].widget.attrs['readonly'] = True
324 ab8bfb29 Kostas Papadimitriou
325 4e30244e Sofia Papagiannaki
    def save(self, commit=True):
326 4e30244e Sofia Papagiannaki
        user = super(InvitedThirdPartyUserCreationForm, self).save(commit=False)
327 d2633501 Kostas Papadimitriou
        user.set_invitation_level()
328 4e30244e Sofia Papagiannaki
        user.email_verified = True
329 4e30244e Sofia Papagiannaki
        if commit:
330 4e30244e Sofia Papagiannaki
            user.save()
331 4e30244e Sofia Papagiannaki
        return user
332 8f5a3a06 Sofia Papagiannaki
333 5ce3ce4f Sofia Papagiannaki
334 18ffbee1 Sofia Papagiannaki
class ShibbolethUserCreationForm(ThirdPartyUserCreationForm):
335 5ce3ce4f Sofia Papagiannaki
    additional_email = forms.CharField(
336 5ce3ce4f Sofia Papagiannaki
        widget=forms.HiddenInput(), label='', required=False)
337 ab8bfb29 Kostas Papadimitriou
338 ca828a10 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
339 ca828a10 Sofia Papagiannaki
        super(ShibbolethUserCreationForm, self).__init__(*args, **kwargs)
340 ca828a10 Sofia Papagiannaki
        # copy email value to additional_mail in case user will change it
341 ca828a10 Sofia Papagiannaki
        name = 'email'
342 ca828a10 Sofia Papagiannaki
        field = self.fields[name]
343 ca828a10 Sofia Papagiannaki
        self.initial['additional_email'] = self.initial.get(name, field.initial)
344 ef20ea07 Sofia Papagiannaki
        self.initial['email'] = None
345 d2633501 Kostas Papadimitriou
346 4e30244e Sofia Papagiannaki
347 9a06d96f Olga Brani
class InvitedShibbolethUserCreationForm(ShibbolethUserCreationForm,
348 9a06d96f Olga Brani
                                        InvitedThirdPartyUserCreationForm):
349 4e30244e Sofia Papagiannaki
    pass
350 ab8bfb29 Kostas Papadimitriou
351 5ce3ce4f Sofia Papagiannaki
352 5ed6816e Sofia Papagiannaki
class LoginForm(AuthenticationForm):
353 5ed6816e Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
354 672d445a Sofia Papagiannaki
    recaptcha_challenge_field = forms.CharField(widget=DummyWidget)
355 5ce3ce4f Sofia Papagiannaki
    recaptcha_response_field = forms.CharField(
356 5ce3ce4f Sofia Papagiannaki
        widget=RecaptchaWidget, label='')
357 ab8bfb29 Kostas Papadimitriou
358 672d445a Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
359 672d445a Sofia Papagiannaki
        was_limited = kwargs.get('was_limited', False)
360 672d445a Sofia Papagiannaki
        request = kwargs.get('request', None)
361 672d445a Sofia Papagiannaki
        if request:
362 672d445a Sofia Papagiannaki
            self.ip = request.META.get('REMOTE_ADDR',
363 672d445a Sofia Papagiannaki
                                       request.META.get('HTTP_X_REAL_IP', None))
364 ab8bfb29 Kostas Papadimitriou
365 672d445a Sofia Papagiannaki
        t = ('request', 'was_limited')
366 672d445a Sofia Papagiannaki
        for elem in t:
367 672d445a Sofia Papagiannaki
            if elem in kwargs.keys():
368 672d445a Sofia Papagiannaki
                kwargs.pop(elem)
369 672d445a Sofia Papagiannaki
        super(LoginForm, self).__init__(*args, **kwargs)
370 ab8bfb29 Kostas Papadimitriou
371 672d445a Sofia Papagiannaki
        self.fields.keyOrder = ['username', 'password']
372 8998f09a Sofia Papagiannaki
        if was_limited and settings.RECAPTCHA_ENABLED:
373 672d445a Sofia Papagiannaki
            self.fields.keyOrder.extend(['recaptcha_challenge_field',
374 5ce3ce4f Sofia Papagiannaki
                                         'recaptcha_response_field', ])
375 9a06d96f Olga Brani
376 9a06d96f Olga Brani
    def clean_username(self):
377 4bdd7e3d Kostas Papadimitriou
        return self.cleaned_data['username'].lower()
378 ab8bfb29 Kostas Papadimitriou
379 672d445a Sofia Papagiannaki
    def clean_recaptcha_response_field(self):
380 672d445a Sofia Papagiannaki
        if 'recaptcha_challenge_field' in self.cleaned_data:
381 672d445a Sofia Papagiannaki
            self.validate_captcha()
382 672d445a Sofia Papagiannaki
        return self.cleaned_data['recaptcha_response_field']
383 672d445a Sofia Papagiannaki
384 672d445a Sofia Papagiannaki
    def clean_recaptcha_challenge_field(self):
385 672d445a Sofia Papagiannaki
        if 'recaptcha_response_field' in self.cleaned_data:
386 672d445a Sofia Papagiannaki
            self.validate_captcha()
387 672d445a Sofia Papagiannaki
        return self.cleaned_data['recaptcha_challenge_field']
388 672d445a Sofia Papagiannaki
389 672d445a Sofia Papagiannaki
    def validate_captcha(self):
390 672d445a Sofia Papagiannaki
        rcf = self.cleaned_data['recaptcha_challenge_field']
391 672d445a Sofia Papagiannaki
        rrf = self.cleaned_data['recaptcha_response_field']
392 8998f09a Sofia Papagiannaki
        check = captcha.submit(
393 8998f09a Sofia Papagiannaki
            rcf, rrf, settings.RECAPTCHA_PRIVATE_KEY, self.ip)
394 672d445a Sofia Papagiannaki
        if not check.is_valid:
395 8998f09a Sofia Papagiannaki
            raise forms.ValidationError(_(
396 8998f09a Sofia Papagiannaki
                astakos_messages.CAPTCHA_VALIDATION_ERR))
397 2e90e3ec Kostas Papadimitriou
398 eedb3923 Sofia Papagiannaki
    def clean(self):
399 1f3b4b39 Sofia Papagiannaki
        """
400 1f3b4b39 Sofia Papagiannaki
        Override default behavior in order to check user's activation later
401 1f3b4b39 Sofia Papagiannaki
        """
402 c4b1a172 Kostas Papadimitriou
        username = self.cleaned_data.get('username')
403 c4b1a172 Kostas Papadimitriou
404 bea8a810 Kostas Papadimitriou
        if username:
405 bea8a810 Kostas Papadimitriou
            try:
406 bea8a810 Kostas Papadimitriou
                user = AstakosUser.objects.get_by_identifier(username)
407 bea8a810 Kostas Papadimitriou
                if not user.has_auth_provider('local'):
408 9d20fe23 Kostas Papadimitriou
                    provider = auth_providers.get_provider('local', user)
409 e7cb4085 Kostas Papadimitriou
                    msg = provider.get_login_disabled_msg
410 e7cb4085 Kostas Papadimitriou
                    raise forms.ValidationError(mark_safe(msg))
411 bea8a810 Kostas Papadimitriou
            except AstakosUser.DoesNotExist:
412 bea8a810 Kostas Papadimitriou
                pass
413 c4b1a172 Kostas Papadimitriou
414 1f3b4b39 Sofia Papagiannaki
        try:
415 1f3b4b39 Sofia Papagiannaki
            super(LoginForm, self).clean()
416 1f3b4b39 Sofia Papagiannaki
        except forms.ValidationError, e:
417 c4b1a172 Kostas Papadimitriou
            if self.user_cache is None:
418 c4b1a172 Kostas Papadimitriou
                raise
419 c4b1a172 Kostas Papadimitriou
            if not self.user_cache.is_active:
420 9d20fe23 Kostas Papadimitriou
                msg = self.user_cache.get_inactive_message('local')
421 9d20fe23 Kostas Papadimitriou
                raise forms.ValidationError(msg)
422 1f3b4b39 Sofia Papagiannaki
            if self.request:
423 1f3b4b39 Sofia Papagiannaki
                if not self.request.session.test_cookie_worked():
424 1f3b4b39 Sofia Papagiannaki
                    raise
425 eedb3923 Sofia Papagiannaki
        return self.cleaned_data
426 64cd4730 Antony Chazapis
427 5ce3ce4f Sofia Papagiannaki
428 890b0eaf Sofia Papagiannaki
class ProfileForm(forms.ModelForm):
429 890b0eaf Sofia Papagiannaki
    """
430 890b0eaf Sofia Papagiannaki
    Subclass of ``ModelForm`` for permiting user to edit his/her profile.
431 9a06d96f Olga Brani
    Most of the fields are readonly since the user is not allowed to change
432 9a06d96f Olga Brani
    them.
433 18ffbee1 Sofia Papagiannaki

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

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