Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / forms.py @ 373daf6a

History | View | Annotate | Download (21.2 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 8f378756 Sofia Papagiannaki
from urlparse import urljoin
34 270dd48d 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 1039bab1 Sofia Papagiannaki
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, \
39 1039bab1 Sofia Papagiannaki
    PasswordResetForm, PasswordChangeForm
40 e2125441 Sofia Papagiannaki
from django.core.mail import send_mail
41 e2125441 Sofia Papagiannaki
from django.contrib.auth.tokens import default_token_generator
42 e2125441 Sofia Papagiannaki
from django.template import Context, loader
43 e2125441 Sofia Papagiannaki
from django.utils.http import int_to_base36
44 374611bc Sofia Papagiannaki
from django.core.urlresolvers import reverse
45 270dd48d Sofia Papagiannaki
from django.utils.functional import lazy
46 18ffbee1 Sofia Papagiannaki
from django.utils.safestring import mark_safe
47 0a569195 Sofia Papagiannaki
from django.contrib import messages
48 49790d9d Sofia Papagiannaki
from django.utils.encoding import smart_str
49 8e45d6fd Sofia Papagiannaki
from django.forms.extras.widgets import SelectDateWidget
50 8e45d6fd Sofia Papagiannaki
from django.db.models import Q
51 5ed6816e Sofia Papagiannaki
52 8e45d6fd Sofia Papagiannaki
from astakos.im.models import *
53 111f3da6 Sofia Papagiannaki
from astakos.im.settings import INVITATIONS_PER_LEVEL, DEFAULT_FROM_EMAIL, \
54 111f3da6 Sofia Papagiannaki
    BASEURL, SITENAME, RECAPTCHA_PRIVATE_KEY, DEFAULT_CONTACT_EMAIL, \
55 111f3da6 Sofia Papagiannaki
    RECAPTCHA_ENABLED, LOGGING_LEVEL
56 45f8d9ff Sofia Papagiannaki
from astakos.im.widgets import DummyWidget, RecaptchaWidget
57 49790d9d Sofia Papagiannaki
from astakos.im.functions import send_change_email
58 270dd48d Sofia Papagiannaki
59 270dd48d Sofia Papagiannaki
# since Django 1.4 use django.core.urlresolvers.reverse_lazy instead
60 09e7393c Sofia Papagiannaki
from astakos.im.util import reverse_lazy, reserved_email, get_query
61 64cd4730 Antony Chazapis
62 3bf924ec Sofia Papagiannaki
import logging
63 49790d9d Sofia Papagiannaki
import hashlib
64 db7fecd9 Sofia Papagiannaki
import recaptcha.client.captcha as captcha
65 49790d9d Sofia Papagiannaki
from random import random
66 64cd4730 Antony Chazapis
67 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
68 e015e9e6 Sofia Papagiannaki
69 15efc749 Sofia Papagiannaki
class LocalUserCreationForm(UserCreationForm):
70 890b0eaf Sofia Papagiannaki
    """
71 890b0eaf Sofia Papagiannaki
    Extends the built in UserCreationForm in several ways:
72 18ffbee1 Sofia Papagiannaki

73 8316698a Sofia Papagiannaki
    * Adds email, first_name, last_name, recaptcha_challenge_field, recaptcha_response_field field.
74 5ed6816e Sofia Papagiannaki
    * The username field isn't visible and it is assigned a generated id.
75 18ffbee1 Sofia Papagiannaki
    * User created is not active.
76 890b0eaf Sofia Papagiannaki
    """
77 db7fecd9 Sofia Papagiannaki
    recaptcha_challenge_field = forms.CharField(widget=DummyWidget)
78 db7fecd9 Sofia Papagiannaki
    recaptcha_response_field = forms.CharField(widget=RecaptchaWidget, label='')
79 18ffbee1 Sofia Papagiannaki
80 794852f2 Sofia Papagiannaki
    class Meta:
81 794852f2 Sofia Papagiannaki
        model = AstakosUser
82 45f8d9ff Sofia Papagiannaki
        fields = ("email", "first_name", "last_name", "has_signed_terms", "has_signed_terms")
83 18ffbee1 Sofia Papagiannaki
84 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
85 64cd4730 Antony Chazapis
        """
86 890b0eaf Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
87 64cd4730 Antony Chazapis
        """
88 672d445a Sofia Papagiannaki
        request = kwargs.get('request', None)
89 672d445a Sofia Papagiannaki
        if request:
90 672d445a Sofia Papagiannaki
            kwargs.pop('request')
91 672d445a Sofia Papagiannaki
            self.ip = request.META.get('REMOTE_ADDR',
92 672d445a Sofia Papagiannaki
                                       request.META.get('HTTP_X_REAL_IP', None))
93 672d445a Sofia Papagiannaki
        
94 15efc749 Sofia Papagiannaki
        super(LocalUserCreationForm, self).__init__(*args, **kwargs)
95 890b0eaf Sofia Papagiannaki
        self.fields.keyOrder = ['email', 'first_name', 'last_name',
96 d8f63346 Sofia Papagiannaki
                                'password1', 'password2']
97 1b3398a0 Olga Brani
98 53bf2659 Sofia Papagiannaki
        if RECAPTCHA_ENABLED:
99 53bf2659 Sofia Papagiannaki
            self.fields.keyOrder.extend(['recaptcha_challenge_field',
100 53bf2659 Sofia Papagiannaki
                                         'recaptcha_response_field',])
101 1b3398a0 Olga Brani
        if get_latest_terms():
102 1b3398a0 Olga Brani
            self.fields.keyOrder.append('has_signed_terms')
103 1b3398a0 Olga Brani
            
104 18ffbee1 Sofia Papagiannaki
        if 'has_signed_terms' in self.fields:
105 18ffbee1 Sofia Papagiannaki
            # Overriding field label since we need to apply a link
106 18ffbee1 Sofia Papagiannaki
            # to the terms within the label
107 18ffbee1 Sofia Papagiannaki
            terms_link_html = '<a href="%s" target="_blank">%s</a>' \
108 18ffbee1 Sofia Papagiannaki
                    % (reverse('latest_terms'), _("the terms"))
109 18ffbee1 Sofia Papagiannaki
            self.fields['has_signed_terms'].label = \
110 18ffbee1 Sofia Papagiannaki
                    mark_safe("I agree with %s" % terms_link_html)
111 18ffbee1 Sofia Papagiannaki
112 af4eb974 Sofia Papagiannaki
    def clean_email(self):
113 af4eb974 Sofia Papagiannaki
        email = self.cleaned_data['email']
114 881c856c Sofia Papagiannaki
        if not email:
115 881c856c Sofia Papagiannaki
            raise forms.ValidationError(_("This field is required"))
116 0a569195 Sofia Papagiannaki
        if reserved_email(email):
117 c37263ea Sofia Papagiannaki
            raise forms.ValidationError(_("This email is already used"))
118 0a569195 Sofia Papagiannaki
        return email
119 18ffbee1 Sofia Papagiannaki
120 270dd48d Sofia Papagiannaki
    def clean_has_signed_terms(self):
121 270dd48d Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
122 270dd48d Sofia Papagiannaki
        if not has_signed_terms:
123 270dd48d Sofia Papagiannaki
            raise forms.ValidationError(_('You have to agree with the terms'))
124 270dd48d Sofia Papagiannaki
        return has_signed_terms
125 18ffbee1 Sofia Papagiannaki
126 db7fecd9 Sofia Papagiannaki
    def clean_recaptcha_response_field(self):
127 db7fecd9 Sofia Papagiannaki
        if 'recaptcha_challenge_field' in self.cleaned_data:
128 db7fecd9 Sofia Papagiannaki
            self.validate_captcha()
129 db7fecd9 Sofia Papagiannaki
        return self.cleaned_data['recaptcha_response_field']
130 db7fecd9 Sofia Papagiannaki
131 db7fecd9 Sofia Papagiannaki
    def clean_recaptcha_challenge_field(self):
132 db7fecd9 Sofia Papagiannaki
        if 'recaptcha_response_field' in self.cleaned_data:
133 db7fecd9 Sofia Papagiannaki
            self.validate_captcha()
134 db7fecd9 Sofia Papagiannaki
        return self.cleaned_data['recaptcha_challenge_field']
135 db7fecd9 Sofia Papagiannaki
136 db7fecd9 Sofia Papagiannaki
    def validate_captcha(self):
137 db7fecd9 Sofia Papagiannaki
        rcf = self.cleaned_data['recaptcha_challenge_field']
138 db7fecd9 Sofia Papagiannaki
        rrf = self.cleaned_data['recaptcha_response_field']
139 db7fecd9 Sofia Papagiannaki
        check = captcha.submit(rcf, rrf, RECAPTCHA_PRIVATE_KEY, self.ip)
140 db7fecd9 Sofia Papagiannaki
        if not check.is_valid:
141 db7fecd9 Sofia Papagiannaki
            raise forms.ValidationError(_('You have not entered the correct words'))
142 18ffbee1 Sofia Papagiannaki
143 890b0eaf Sofia Papagiannaki
    def save(self, commit=True):
144 64cd4730 Antony Chazapis
        """
145 890b0eaf Sofia Papagiannaki
        Saves the email, first_name and last_name properties, after the normal
146 890b0eaf Sofia Papagiannaki
        save behavior is complete.
147 890b0eaf Sofia Papagiannaki
        """
148 15efc749 Sofia Papagiannaki
        user = super(LocalUserCreationForm, self).save(commit=False)
149 3bf924ec Sofia Papagiannaki
        user.renew_token()
150 9fb8e808 Sofia Papagiannaki
        if commit:
151 9fb8e808 Sofia Papagiannaki
            user.save()
152 111f3da6 Sofia Papagiannaki
            logger._log(LOGGING_LEVEL, 'Created user %s' % user.email, [])
153 890b0eaf Sofia Papagiannaki
        return user
154 64cd4730 Antony Chazapis
155 15efc749 Sofia Papagiannaki
class InvitedLocalUserCreationForm(LocalUserCreationForm):
156 890b0eaf Sofia Papagiannaki
    """
157 062c970c Sofia Papagiannaki
    Extends the LocalUserCreationForm: email is readonly.
158 890b0eaf Sofia Papagiannaki
    """
159 794852f2 Sofia Papagiannaki
    class Meta:
160 794852f2 Sofia Papagiannaki
        model = AstakosUser
161 270dd48d Sofia Papagiannaki
        fields = ("email", "first_name", "last_name", "has_signed_terms")
162 18ffbee1 Sofia Papagiannaki
163 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
164 64cd4730 Antony Chazapis
        """
165 3bf924ec Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
166 64cd4730 Antony Chazapis
        """
167 15efc749 Sofia Papagiannaki
        super(InvitedLocalUserCreationForm, self).__init__(*args, **kwargs)
168 18ffbee1 Sofia Papagiannaki
169 64cd4730 Antony Chazapis
        #set readonly form fields
170 062c970c Sofia Papagiannaki
        ro = ('email', 'username',)
171 4e30244e Sofia Papagiannaki
        for f in ro:
172 4e30244e Sofia Papagiannaki
            self.fields[f].widget.attrs['readonly'] = True
173 4e30244e Sofia Papagiannaki
        
174 18ffbee1 Sofia Papagiannaki
175 9fb8e808 Sofia Papagiannaki
    def save(self, commit=True):
176 15efc749 Sofia Papagiannaki
        user = super(InvitedLocalUserCreationForm, self).save(commit=False)
177 881c856c Sofia Papagiannaki
        level = user.invitation.inviter.level + 1
178 881c856c Sofia Papagiannaki
        user.level = level
179 8316698a Sofia Papagiannaki
        user.invitations = INVITATIONS_PER_LEVEL.get(level, 0)
180 8316698a Sofia Papagiannaki
        user.email_verified = True
181 9fb8e808 Sofia Papagiannaki
        if commit:
182 9fb8e808 Sofia Papagiannaki
            user.save()
183 9fb8e808 Sofia Papagiannaki
        return user
184 5ed6816e Sofia Papagiannaki
185 18ffbee1 Sofia Papagiannaki
class ThirdPartyUserCreationForm(forms.ModelForm):
186 8f5a3a06 Sofia Papagiannaki
    class Meta:
187 8f5a3a06 Sofia Papagiannaki
        model = AstakosUser
188 45f8d9ff Sofia Papagiannaki
        fields = ("email", "first_name", "last_name", "third_party_identifier", "has_signed_terms")
189 8f5a3a06 Sofia Papagiannaki
    
190 8f5a3a06 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
191 8f5a3a06 Sofia Papagiannaki
        """
192 8f5a3a06 Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
193 8f5a3a06 Sofia Papagiannaki
        """
194 0a569195 Sofia Papagiannaki
        self.request = kwargs.get('request', None)
195 0a569195 Sofia Papagiannaki
        if self.request:
196 0a569195 Sofia Papagiannaki
            kwargs.pop('request')
197 8f5a3a06 Sofia Papagiannaki
        super(ThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
198 0a569195 Sofia Papagiannaki
        self.fields.keyOrder = ['email', 'first_name', 'last_name', 'third_party_identifier']
199 8f5a3a06 Sofia Papagiannaki
        if get_latest_terms():
200 8f5a3a06 Sofia Papagiannaki
            self.fields.keyOrder.append('has_signed_terms')
201 18ffbee1 Sofia Papagiannaki
        #set readonly form fields
202 ca828a10 Sofia Papagiannaki
        ro = ["third_party_identifier"]
203 18ffbee1 Sofia Papagiannaki
        for f in ro:
204 18ffbee1 Sofia Papagiannaki
            self.fields[f].widget.attrs['readonly'] = True
205 18ffbee1 Sofia Papagiannaki
        
206 18ffbee1 Sofia Papagiannaki
        if 'has_signed_terms' in self.fields:
207 18ffbee1 Sofia Papagiannaki
            # Overriding field label since we need to apply a link
208 18ffbee1 Sofia Papagiannaki
            # to the terms within the label
209 18ffbee1 Sofia Papagiannaki
            terms_link_html = '<a href="%s" target="_blank">%s</a>' \
210 18ffbee1 Sofia Papagiannaki
                    % (reverse('latest_terms'), _("the terms"))
211 18ffbee1 Sofia Papagiannaki
            self.fields['has_signed_terms'].label = \
212 18ffbee1 Sofia Papagiannaki
                    mark_safe("I agree with %s" % terms_link_html)
213 18ffbee1 Sofia Papagiannaki
    
214 18ffbee1 Sofia Papagiannaki
    def clean_email(self):
215 18ffbee1 Sofia Papagiannaki
        email = self.cleaned_data['email']
216 18ffbee1 Sofia Papagiannaki
        if not email:
217 18ffbee1 Sofia Papagiannaki
            raise forms.ValidationError(_("This field is required"))
218 0a569195 Sofia Papagiannaki
        return email
219 18ffbee1 Sofia Papagiannaki
    
220 18ffbee1 Sofia Papagiannaki
    def clean_has_signed_terms(self):
221 18ffbee1 Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
222 18ffbee1 Sofia Papagiannaki
        if not has_signed_terms:
223 18ffbee1 Sofia Papagiannaki
            raise forms.ValidationError(_('You have to agree with the terms'))
224 18ffbee1 Sofia Papagiannaki
        return has_signed_terms
225 8f5a3a06 Sofia Papagiannaki
    
226 8f5a3a06 Sofia Papagiannaki
    def save(self, commit=True):
227 8f5a3a06 Sofia Papagiannaki
        user = super(ThirdPartyUserCreationForm, self).save(commit=False)
228 8f5a3a06 Sofia Papagiannaki
        user.set_unusable_password()
229 18ffbee1 Sofia Papagiannaki
        user.renew_token()
230 0a569195 Sofia Papagiannaki
        user.provider = get_query(self.request).get('provider')
231 8f5a3a06 Sofia Papagiannaki
        if commit:
232 8f5a3a06 Sofia Papagiannaki
            user.save()
233 111f3da6 Sofia Papagiannaki
            logger._log(LOGGING_LEVEL, 'Created user %s' % user.email, [])
234 8f5a3a06 Sofia Papagiannaki
        return user
235 8f5a3a06 Sofia Papagiannaki
236 8f5a3a06 Sofia Papagiannaki
class InvitedThirdPartyUserCreationForm(ThirdPartyUserCreationForm):
237 4e30244e Sofia Papagiannaki
    """
238 062c970c Sofia Papagiannaki
    Extends the ThirdPartyUserCreationForm: email is readonly.
239 4e30244e Sofia Papagiannaki
    """
240 8f5a3a06 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
241 4e30244e Sofia Papagiannaki
        """
242 4e30244e Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
243 4e30244e Sofia Papagiannaki
        """
244 8f5a3a06 Sofia Papagiannaki
        super(InvitedThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
245 4e30244e Sofia Papagiannaki
246 8f5a3a06 Sofia Papagiannaki
        #set readonly form fields
247 062c970c Sofia Papagiannaki
        ro = ('email',)
248 4e30244e Sofia Papagiannaki
        for f in ro:
249 4e30244e Sofia Papagiannaki
            self.fields[f].widget.attrs['readonly'] = True
250 4e30244e Sofia Papagiannaki
    
251 4e30244e Sofia Papagiannaki
    def save(self, commit=True):
252 4e30244e Sofia Papagiannaki
        user = super(InvitedThirdPartyUserCreationForm, self).save(commit=False)
253 4e30244e Sofia Papagiannaki
        level = user.invitation.inviter.level + 1
254 4e30244e Sofia Papagiannaki
        user.level = level
255 4e30244e Sofia Papagiannaki
        user.invitations = INVITATIONS_PER_LEVEL.get(level, 0)
256 4e30244e Sofia Papagiannaki
        user.email_verified = True
257 4e30244e Sofia Papagiannaki
        if commit:
258 4e30244e Sofia Papagiannaki
            user.save()
259 4e30244e Sofia Papagiannaki
        return user
260 8f5a3a06 Sofia Papagiannaki
261 18ffbee1 Sofia Papagiannaki
class ShibbolethUserCreationForm(ThirdPartyUserCreationForm):
262 ca828a10 Sofia Papagiannaki
    additional_email = forms.CharField(widget=forms.HiddenInput(), label='', required = False)
263 ca828a10 Sofia Papagiannaki
    
264 ca828a10 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
265 ca828a10 Sofia Papagiannaki
        super(ShibbolethUserCreationForm, self).__init__(*args, **kwargs)
266 ca828a10 Sofia Papagiannaki
        self.fields.keyOrder.append('additional_email')
267 ca828a10 Sofia Papagiannaki
        # copy email value to additional_mail in case user will change it
268 ca828a10 Sofia Papagiannaki
        name = 'email'
269 ca828a10 Sofia Papagiannaki
        field = self.fields[name]
270 ca828a10 Sofia Papagiannaki
        self.initial['additional_email'] = self.initial.get(name, field.initial)
271 ca828a10 Sofia Papagiannaki
    
272 18ffbee1 Sofia Papagiannaki
    def clean_email(self):
273 18ffbee1 Sofia Papagiannaki
        email = self.cleaned_data['email']
274 0a569195 Sofia Papagiannaki
        for user in AstakosUser.objects.filter(email = email):
275 0a569195 Sofia Papagiannaki
            if user.provider == 'shibboleth':
276 18ffbee1 Sofia Papagiannaki
                raise forms.ValidationError(_("This email is already associated with another shibboleth account."))
277 591d0505 Sofia Papagiannaki
            elif not user.is_active:
278 591d0505 Sofia Papagiannaki
                raise forms.ValidationError(_("This email is already associated with an inactive account. \
279 591d0505 Sofia Papagiannaki
                                              You need to wait to be activated before being able to switch to a shibboleth account."))
280 ab8f7956 Sofia Papagiannaki
        super(ShibbolethUserCreationForm, self).clean_email()
281 0a569195 Sofia Papagiannaki
        return email
282 4e30244e Sofia Papagiannaki
283 0a569195 Sofia Papagiannaki
class InvitedShibbolethUserCreationForm(ShibbolethUserCreationForm, InvitedThirdPartyUserCreationForm):
284 4e30244e Sofia Papagiannaki
    pass
285 18ffbee1 Sofia Papagiannaki
    
286 5ed6816e Sofia Papagiannaki
class LoginForm(AuthenticationForm):
287 5ed6816e Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
288 672d445a Sofia Papagiannaki
    recaptcha_challenge_field = forms.CharField(widget=DummyWidget)
289 672d445a Sofia Papagiannaki
    recaptcha_response_field = forms.CharField(widget=RecaptchaWidget, label='')
290 672d445a Sofia Papagiannaki
    
291 672d445a Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
292 672d445a Sofia Papagiannaki
        was_limited = kwargs.get('was_limited', False)
293 672d445a Sofia Papagiannaki
        request = kwargs.get('request', None)
294 672d445a Sofia Papagiannaki
        if request:
295 672d445a Sofia Papagiannaki
            self.ip = request.META.get('REMOTE_ADDR',
296 672d445a Sofia Papagiannaki
                                       request.META.get('HTTP_X_REAL_IP', None))
297 672d445a Sofia Papagiannaki
        
298 672d445a Sofia Papagiannaki
        t = ('request', 'was_limited')
299 672d445a Sofia Papagiannaki
        for elem in t:
300 672d445a Sofia Papagiannaki
            if elem in kwargs.keys():
301 672d445a Sofia Papagiannaki
                kwargs.pop(elem)
302 672d445a Sofia Papagiannaki
        super(LoginForm, self).__init__(*args, **kwargs)
303 672d445a Sofia Papagiannaki
        
304 672d445a Sofia Papagiannaki
        self.fields.keyOrder = ['username', 'password']
305 672d445a Sofia Papagiannaki
        if was_limited and RECAPTCHA_ENABLED:
306 672d445a Sofia Papagiannaki
            self.fields.keyOrder.extend(['recaptcha_challenge_field',
307 672d445a Sofia Papagiannaki
                                         'recaptcha_response_field',])
308 672d445a Sofia Papagiannaki
    
309 672d445a Sofia Papagiannaki
    def clean_recaptcha_response_field(self):
310 672d445a Sofia Papagiannaki
        if 'recaptcha_challenge_field' in self.cleaned_data:
311 672d445a Sofia Papagiannaki
            self.validate_captcha()
312 672d445a Sofia Papagiannaki
        return self.cleaned_data['recaptcha_response_field']
313 672d445a Sofia Papagiannaki
314 672d445a Sofia Papagiannaki
    def clean_recaptcha_challenge_field(self):
315 672d445a Sofia Papagiannaki
        if 'recaptcha_response_field' in self.cleaned_data:
316 672d445a Sofia Papagiannaki
            self.validate_captcha()
317 672d445a Sofia Papagiannaki
        return self.cleaned_data['recaptcha_challenge_field']
318 672d445a Sofia Papagiannaki
319 672d445a Sofia Papagiannaki
    def validate_captcha(self):
320 672d445a Sofia Papagiannaki
        rcf = self.cleaned_data['recaptcha_challenge_field']
321 672d445a Sofia Papagiannaki
        rrf = self.cleaned_data['recaptcha_response_field']
322 672d445a Sofia Papagiannaki
        check = captcha.submit(rcf, rrf, RECAPTCHA_PRIVATE_KEY, self.ip)
323 672d445a Sofia Papagiannaki
        if not check.is_valid:
324 672d445a Sofia Papagiannaki
            raise forms.ValidationError(_('You have not entered the correct words'))
325 eedb3923 Sofia Papagiannaki
    
326 eedb3923 Sofia Papagiannaki
    def clean(self):
327 eedb3923 Sofia Papagiannaki
        super(LoginForm, self).clean()
328 21f89374 Sofia Papagiannaki
        if self.user_cache and self.user_cache.provider not in ('local', ''):
329 eedb3923 Sofia Papagiannaki
            raise forms.ValidationError(_('Local login is not the current authentication method for this account.'))
330 eedb3923 Sofia Papagiannaki
        return self.cleaned_data
331 64cd4730 Antony Chazapis
332 890b0eaf Sofia Papagiannaki
class ProfileForm(forms.ModelForm):
333 890b0eaf Sofia Papagiannaki
    """
334 890b0eaf Sofia Papagiannaki
    Subclass of ``ModelForm`` for permiting user to edit his/her profile.
335 890b0eaf Sofia Papagiannaki
    Most of the fields are readonly since the user is not allowed to change them.
336 18ffbee1 Sofia Papagiannaki

337 890b0eaf Sofia Papagiannaki
    The class defines a save method which sets ``is_verified`` to True so as the user
338 890b0eaf Sofia Papagiannaki
    during the next login will not to be redirected to profile page.
339 890b0eaf Sofia Papagiannaki
    """
340 c301698f Sofia Papagiannaki
    renew = forms.BooleanField(label='Renew token', required=False)
341 18ffbee1 Sofia Papagiannaki
342 890b0eaf Sofia Papagiannaki
    class Meta:
343 890b0eaf Sofia Papagiannaki
        model = AstakosUser
344 0a569195 Sofia Papagiannaki
        fields = ('email', 'first_name', 'last_name', 'auth_token', 'auth_token_expires')
345 18ffbee1 Sofia Papagiannaki
346 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
347 890b0eaf Sofia Papagiannaki
        super(ProfileForm, self).__init__(*args, **kwargs)
348 890b0eaf Sofia Papagiannaki
        instance = getattr(self, 'instance', None)
349 0a569195 Sofia Papagiannaki
        ro_fields = ('email', 'auth_token', 'auth_token_expires')
350 890b0eaf Sofia Papagiannaki
        if instance and instance.id:
351 890b0eaf Sofia Papagiannaki
            for field in ro_fields:
352 890b0eaf Sofia Papagiannaki
                self.fields[field].widget.attrs['readonly'] = True
353 18ffbee1 Sofia Papagiannaki
354 890b0eaf Sofia Papagiannaki
    def save(self, commit=True):
355 890b0eaf Sofia Papagiannaki
        user = super(ProfileForm, self).save(commit=False)
356 890b0eaf Sofia Papagiannaki
        user.is_verified = True
357 c301698f Sofia Papagiannaki
        if self.cleaned_data.get('renew'):
358 c301698f Sofia Papagiannaki
            user.renew_token()
359 890b0eaf Sofia Papagiannaki
        if commit:
360 890b0eaf Sofia Papagiannaki
            user.save()
361 890b0eaf Sofia Papagiannaki
        return user
362 64cd4730 Antony Chazapis
363 890b0eaf Sofia Papagiannaki
class FeedbackForm(forms.Form):
364 890b0eaf Sofia Papagiannaki
    """
365 890b0eaf Sofia Papagiannaki
    Form for writing feedback.
366 890b0eaf Sofia Papagiannaki
    """
367 0a569195 Sofia Papagiannaki
    feedback_msg = forms.CharField(widget=forms.Textarea, label=u'Message')
368 8f5a3a06 Sofia Papagiannaki
    feedback_data = forms.CharField(widget=forms.HiddenInput(), label='',
369 8f5a3a06 Sofia Papagiannaki
                                    required=False)
370 5ed6816e Sofia Papagiannaki
371 5ed6816e Sofia Papagiannaki
class SendInvitationForm(forms.Form):
372 5ed6816e Sofia Papagiannaki
    """
373 5ed6816e Sofia Papagiannaki
    Form for sending an invitations
374 5ed6816e Sofia Papagiannaki
    """
375 18ffbee1 Sofia Papagiannaki
376 5ed6816e Sofia Papagiannaki
    email = forms.EmailField(required = True, label = 'Email address')
377 5ed6816e Sofia Papagiannaki
    first_name = forms.EmailField(label = 'First name')
378 5ed6816e Sofia Papagiannaki
    last_name = forms.EmailField(label = 'Last name')
379 e2125441 Sofia Papagiannaki
380 e2125441 Sofia Papagiannaki
class ExtendedPasswordResetForm(PasswordResetForm):
381 e2125441 Sofia Papagiannaki
    """
382 e2125441 Sofia Papagiannaki
    Extends PasswordResetForm by overriding save method:
383 e2125441 Sofia Papagiannaki
    passes a custom from_email in send_mail.
384 18ffbee1 Sofia Papagiannaki

385 e2125441 Sofia Papagiannaki
    Since Django 1.3 this is useless since ``django.contrib.auth.views.reset_password``
386 e2125441 Sofia Papagiannaki
    accepts a from_email argument.
387 e2125441 Sofia Papagiannaki
    """
388 23c271b3 Sofia Papagiannaki
    def clean_email(self):
389 23c271b3 Sofia Papagiannaki
        email = super(ExtendedPasswordResetForm, self).clean_email()
390 23c271b3 Sofia Papagiannaki
        try:
391 0a569195 Sofia Papagiannaki
            user = AstakosUser.objects.get(email=email, is_active=True)
392 23c271b3 Sofia Papagiannaki
            if not user.has_usable_password():
393 23c271b3 Sofia Papagiannaki
                raise forms.ValidationError(_("This account has not a usable password."))
394 23c271b3 Sofia Papagiannaki
        except AstakosUser.DoesNotExist, e:
395 23c271b3 Sofia Papagiannaki
            raise forms.ValidationError(_('That e-mail address doesn\'t have an associated user account. Are you sure you\'ve registered?'))
396 23c271b3 Sofia Papagiannaki
        return email
397 23c271b3 Sofia Papagiannaki
    
398 e2125441 Sofia Papagiannaki
    def save(self, domain_override=None, email_template_name='registration/password_reset_email.html',
399 e2125441 Sofia Papagiannaki
             use_https=False, token_generator=default_token_generator, request=None):
400 e2125441 Sofia Papagiannaki
        """
401 e2125441 Sofia Papagiannaki
        Generates a one-use only link for resetting password and sends to the user.
402 e2125441 Sofia Papagiannaki
        """
403 e2125441 Sofia Papagiannaki
        for user in self.users_cache:
404 18ffbee1 Sofia Papagiannaki
            url = reverse('django.contrib.auth.views.password_reset_confirm',
405 18ffbee1 Sofia Papagiannaki
                          kwargs={'uidb36':int_to_base36(user.id),
406 18ffbee1 Sofia Papagiannaki
                                  'token':token_generator.make_token(user)})
407 a53b19da Sofia Papagiannaki
            url = urljoin(BASEURL, url)
408 e2125441 Sofia Papagiannaki
            t = loader.get_template(email_template_name)
409 e2125441 Sofia Papagiannaki
            c = {
410 e2125441 Sofia Papagiannaki
                'email': user.email,
411 8f378756 Sofia Papagiannaki
                'url': url,
412 374611bc Sofia Papagiannaki
                'site_name': SITENAME,
413 e2125441 Sofia Papagiannaki
                'user': user,
414 a53b19da Sofia Papagiannaki
                'baseurl': BASEURL,
415 09122dd8 Sofia Papagiannaki
                'support': DEFAULT_CONTACT_EMAIL
416 e2125441 Sofia Papagiannaki
            }
417 d552ecb7 Antony Chazapis
            from_email = DEFAULT_FROM_EMAIL
418 4abc7b29 Sofia Papagiannaki
            send_mail(_("Password reset on %s alpha2 testing") % SITENAME,
419 e2125441 Sofia Papagiannaki
                t.render(Context(c)), from_email, [user.email])
420 270dd48d Sofia Papagiannaki
421 49790d9d Sofia Papagiannaki
class EmailChangeForm(forms.ModelForm):
422 49790d9d Sofia Papagiannaki
    class Meta:
423 49790d9d Sofia Papagiannaki
        model = EmailChange
424 49790d9d Sofia Papagiannaki
        fields = ('new_email_address',)
425 49790d9d Sofia Papagiannaki
            
426 49790d9d Sofia Papagiannaki
    def clean_new_email_address(self):
427 49790d9d Sofia Papagiannaki
        addr = self.cleaned_data['new_email_address']
428 49790d9d Sofia Papagiannaki
        if AstakosUser.objects.filter(email__iexact=addr):
429 49790d9d Sofia Papagiannaki
            raise forms.ValidationError(_(u'This email address is already in use. Please supply a different email address.'))
430 49790d9d Sofia Papagiannaki
        return addr
431 49790d9d Sofia Papagiannaki
    
432 49790d9d Sofia Papagiannaki
    def save(self, email_template_name, request, commit=True):
433 49790d9d Sofia Papagiannaki
        ec = super(EmailChangeForm, self).save(commit=False)
434 49790d9d Sofia Papagiannaki
        ec.user = request.user
435 49790d9d Sofia Papagiannaki
        activation_key = hashlib.sha1(str(random()) + smart_str(ec.new_email_address))
436 49790d9d Sofia Papagiannaki
        ec.activation_key=activation_key.hexdigest()
437 49790d9d Sofia Papagiannaki
        if commit:
438 49790d9d Sofia Papagiannaki
            ec.save()
439 49790d9d Sofia Papagiannaki
        send_change_email(ec, request, email_template_name=email_template_name)
440 49790d9d Sofia Papagiannaki
441 270dd48d Sofia Papagiannaki
class SignApprovalTermsForm(forms.ModelForm):
442 270dd48d Sofia Papagiannaki
    class Meta:
443 270dd48d Sofia Papagiannaki
        model = AstakosUser
444 270dd48d Sofia Papagiannaki
        fields = ("has_signed_terms",)
445 18ffbee1 Sofia Papagiannaki
446 270dd48d Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
447 270dd48d Sofia Papagiannaki
        super(SignApprovalTermsForm, self).__init__(*args, **kwargs)
448 18ffbee1 Sofia Papagiannaki
449 270dd48d Sofia Papagiannaki
    def clean_has_signed_terms(self):
450 270dd48d Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
451 270dd48d Sofia Papagiannaki
        if not has_signed_terms:
452 270dd48d Sofia Papagiannaki
            raise forms.ValidationError(_('You have to agree with the terms'))
453 270dd48d Sofia Papagiannaki
        return has_signed_terms
454 8f5a3a06 Sofia Papagiannaki
455 8f5a3a06 Sofia Papagiannaki
class InvitationForm(forms.ModelForm):
456 8f5a3a06 Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
457 8f5a3a06 Sofia Papagiannaki
    
458 18ffbee1 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
459 18ffbee1 Sofia Papagiannaki
        super(InvitationForm, self).__init__(*args, **kwargs)
460 18ffbee1 Sofia Papagiannaki
    
461 8f5a3a06 Sofia Papagiannaki
    class Meta:
462 8f5a3a06 Sofia Papagiannaki
        model = Invitation
463 8f5a3a06 Sofia Papagiannaki
        fields = ('username', 'realname')
464 8f5a3a06 Sofia Papagiannaki
    
465 8f5a3a06 Sofia Papagiannaki
    def clean_username(self):
466 8f5a3a06 Sofia Papagiannaki
        username = self.cleaned_data['username']
467 8f5a3a06 Sofia Papagiannaki
        try:
468 8f5a3a06 Sofia Papagiannaki
            Invitation.objects.get(username = username)
469 8f5a3a06 Sofia Papagiannaki
            raise forms.ValidationError(_('There is already invitation for this email.'))
470 8f5a3a06 Sofia Papagiannaki
        except Invitation.DoesNotExist:
471 8f5a3a06 Sofia Papagiannaki
            pass
472 18ffbee1 Sofia Papagiannaki
        return username
473 1039bab1 Sofia Papagiannaki
474 1039bab1 Sofia Papagiannaki
class ExtendedPasswordChangeForm(PasswordChangeForm):
475 1039bab1 Sofia Papagiannaki
    """
476 1039bab1 Sofia Papagiannaki
    Extends PasswordChangeForm by enabling user
477 1039bab1 Sofia Papagiannaki
    to optionally renew also the token.
478 1039bab1 Sofia Papagiannaki
    """
479 1039bab1 Sofia Papagiannaki
    renew = forms.BooleanField(label='Renew token', required=False)
480 1039bab1 Sofia Papagiannaki
    
481 1039bab1 Sofia Papagiannaki
    def __init__(self, user, *args, **kwargs):
482 1039bab1 Sofia Papagiannaki
        super(ExtendedPasswordChangeForm, self).__init__(user, *args, **kwargs)
483 1039bab1 Sofia Papagiannaki
    
484 1039bab1 Sofia Papagiannaki
    def save(self, commit=True):
485 1039bab1 Sofia Papagiannaki
        user = super(ExtendedPasswordChangeForm, self).save(commit=False)
486 1039bab1 Sofia Papagiannaki
        if self.cleaned_data.get('renew'):
487 1039bab1 Sofia Papagiannaki
            user.renew_token()
488 1039bab1 Sofia Papagiannaki
        if commit:
489 1039bab1 Sofia Papagiannaki
            user.save()
490 8e45d6fd Sofia Papagiannaki
        return user
491 8e45d6fd Sofia Papagiannaki
492 8e45d6fd Sofia Papagiannaki
def get_astakos_group_creation_form(request):
493 8e45d6fd Sofia Papagiannaki
    class AstakosGroupCreationForm(forms.ModelForm):
494 373daf6a Sofia Papagiannaki
        issue_date = forms.DateField(widget=SelectDateWidget(), initial=datetime.now())
495 373daf6a Sofia Papagiannaki
        # TODO set initial in exact one month
496 373daf6a Sofia Papagiannaki
        expiration_date = forms.DateField(widget=SelectDateWidget(), initial = datetime.now() + timedelta(days=30))
497 8e45d6fd Sofia Papagiannaki
        kind = forms.ModelChoiceField(queryset=GroupKind.objects.all(), empty_label=None)
498 76c68fd6 Sofia Papagiannaki
        name = forms.URLField()
499 8e45d6fd Sofia Papagiannaki
        
500 8e45d6fd Sofia Papagiannaki
        class Meta:
501 8e45d6fd Sofia Papagiannaki
            model = AstakosGroup
502 8e45d6fd Sofia Papagiannaki
        
503 8e45d6fd Sofia Papagiannaki
        def __init__(self, *args, **kwargs):
504 8e45d6fd Sofia Papagiannaki
            super(AstakosGroupCreationForm, self).__init__(*args, **kwargs)
505 76c68fd6 Sofia Papagiannaki
            self.fields.keyOrder = ['kind', 'name', 'desc', 'issue_date',
506 8e45d6fd Sofia Papagiannaki
                                    'expiration_date', 'estimated_participants',
507 8e45d6fd Sofia Papagiannaki
                                    'moderatation_enabled']
508 8e45d6fd Sofia Papagiannaki
        
509 8e45d6fd Sofia Papagiannaki
        def save(self, commit=True):
510 8e45d6fd Sofia Papagiannaki
            g = super(AstakosGroupCreationForm, self).save(commit=False)
511 8e45d6fd Sofia Papagiannaki
            if commit: 
512 8e45d6fd Sofia Papagiannaki
                g.save()
513 8e45d6fd Sofia Papagiannaki
                g.owner = [request.user]
514 373daf6a Sofia Papagiannaki
                g.approve_member(request.user)
515 8e45d6fd Sofia Papagiannaki
            return g
516 8e45d6fd Sofia Papagiannaki
    
517 8e45d6fd Sofia Papagiannaki
    return AstakosGroupCreationForm
518 8e45d6fd Sofia Papagiannaki
519 373daf6a Sofia Papagiannaki
def get_astakos_group_policy_creation_form(astakosgroup):
520 8e45d6fd Sofia Papagiannaki
    class AstakosGroupPolicyCreationForm(forms.ModelForm):
521 373daf6a Sofia Papagiannaki
        choices = Resource.objects.filter(~Q(astakosgroup=astakosgroup))
522 8e45d6fd Sofia Papagiannaki
        resource = forms.ModelChoiceField(queryset=choices, empty_label=None)
523 373daf6a Sofia Papagiannaki
        # TODO check that it does not hit the db
524 373daf6a Sofia Papagiannaki
        group = forms.ModelChoiceField(queryset=AstakosGroup.objects.all(), initial=astakosgroup, widget=forms.HiddenInput())
525 8e45d6fd Sofia Papagiannaki
        
526 8e45d6fd Sofia Papagiannaki
        class Meta:
527 8e45d6fd Sofia Papagiannaki
            model = AstakosGroupQuota
528 8e45d6fd Sofia Papagiannaki
    
529 7cb372c7 Sofia Papagiannaki
    return AstakosGroupPolicyCreationForm