Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / forms.py @ 21f89374

History | View | Annotate | Download (19.5 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 5ed6816e Sofia Papagiannaki
50 49790d9d Sofia Papagiannaki
from astakos.im.models import AstakosUser, Invitation, get_latest_terms, EmailChange
51 111f3da6 Sofia Papagiannaki
from astakos.im.settings import INVITATIONS_PER_LEVEL, DEFAULT_FROM_EMAIL, \
52 111f3da6 Sofia Papagiannaki
    BASEURL, SITENAME, RECAPTCHA_PRIVATE_KEY, DEFAULT_CONTACT_EMAIL, \
53 111f3da6 Sofia Papagiannaki
    RECAPTCHA_ENABLED, LOGGING_LEVEL
54 45f8d9ff Sofia Papagiannaki
from astakos.im.widgets import DummyWidget, RecaptchaWidget
55 49790d9d Sofia Papagiannaki
from astakos.im.functions import send_change_email
56 270dd48d Sofia Papagiannaki
57 270dd48d Sofia Papagiannaki
# since Django 1.4 use django.core.urlresolvers.reverse_lazy instead
58 09e7393c Sofia Papagiannaki
from astakos.im.util import reverse_lazy, reserved_email, get_query
59 64cd4730 Antony Chazapis
60 3bf924ec Sofia Papagiannaki
import logging
61 49790d9d Sofia Papagiannaki
import hashlib
62 db7fecd9 Sofia Papagiannaki
import recaptcha.client.captcha as captcha
63 49790d9d Sofia Papagiannaki
from random import random
64 64cd4730 Antony Chazapis
65 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
66 e015e9e6 Sofia Papagiannaki
67 15efc749 Sofia Papagiannaki
class LocalUserCreationForm(UserCreationForm):
68 890b0eaf Sofia Papagiannaki
    """
69 890b0eaf Sofia Papagiannaki
    Extends the built in UserCreationForm in several ways:
70 18ffbee1 Sofia Papagiannaki

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

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

382 e2125441 Sofia Papagiannaki
    Since Django 1.3 this is useless since ``django.contrib.auth.views.reset_password``
383 e2125441 Sofia Papagiannaki
    accepts a from_email argument.
384 e2125441 Sofia Papagiannaki
    """
385 23c271b3 Sofia Papagiannaki
    def clean_email(self):
386 23c271b3 Sofia Papagiannaki
        email = super(ExtendedPasswordResetForm, self).clean_email()
387 23c271b3 Sofia Papagiannaki
        try:
388 0a569195 Sofia Papagiannaki
            user = AstakosUser.objects.get(email=email, is_active=True)
389 23c271b3 Sofia Papagiannaki
            if not user.has_usable_password():
390 23c271b3 Sofia Papagiannaki
                raise forms.ValidationError(_("This account has not a usable password."))
391 23c271b3 Sofia Papagiannaki
        except AstakosUser.DoesNotExist, e:
392 23c271b3 Sofia Papagiannaki
            raise forms.ValidationError(_('That e-mail address doesn\'t have an associated user account. Are you sure you\'ve registered?'))
393 23c271b3 Sofia Papagiannaki
        return email
394 23c271b3 Sofia Papagiannaki
    
395 e2125441 Sofia Papagiannaki
    def save(self, domain_override=None, email_template_name='registration/password_reset_email.html',
396 e2125441 Sofia Papagiannaki
             use_https=False, token_generator=default_token_generator, request=None):
397 e2125441 Sofia Papagiannaki
        """
398 e2125441 Sofia Papagiannaki
        Generates a one-use only link for resetting password and sends to the user.
399 e2125441 Sofia Papagiannaki
        """
400 e2125441 Sofia Papagiannaki
        for user in self.users_cache:
401 18ffbee1 Sofia Papagiannaki
            url = reverse('django.contrib.auth.views.password_reset_confirm',
402 18ffbee1 Sofia Papagiannaki
                          kwargs={'uidb36':int_to_base36(user.id),
403 18ffbee1 Sofia Papagiannaki
                                  'token':token_generator.make_token(user)})
404 a53b19da Sofia Papagiannaki
            url = urljoin(BASEURL, url)
405 e2125441 Sofia Papagiannaki
            t = loader.get_template(email_template_name)
406 e2125441 Sofia Papagiannaki
            c = {
407 e2125441 Sofia Papagiannaki
                'email': user.email,
408 8f378756 Sofia Papagiannaki
                'url': url,
409 374611bc Sofia Papagiannaki
                'site_name': SITENAME,
410 e2125441 Sofia Papagiannaki
                'user': user,
411 a53b19da Sofia Papagiannaki
                'baseurl': BASEURL,
412 09122dd8 Sofia Papagiannaki
                'support': DEFAULT_CONTACT_EMAIL
413 e2125441 Sofia Papagiannaki
            }
414 d552ecb7 Antony Chazapis
            from_email = DEFAULT_FROM_EMAIL
415 4abc7b29 Sofia Papagiannaki
            send_mail(_("Password reset on %s alpha2 testing") % SITENAME,
416 e2125441 Sofia Papagiannaki
                t.render(Context(c)), from_email, [user.email])
417 270dd48d Sofia Papagiannaki
418 49790d9d Sofia Papagiannaki
class EmailChangeForm(forms.ModelForm):
419 49790d9d Sofia Papagiannaki
    class Meta:
420 49790d9d Sofia Papagiannaki
        model = EmailChange
421 49790d9d Sofia Papagiannaki
        fields = ('new_email_address',)
422 49790d9d Sofia Papagiannaki
            
423 49790d9d Sofia Papagiannaki
    def clean_new_email_address(self):
424 49790d9d Sofia Papagiannaki
        addr = self.cleaned_data['new_email_address']
425 49790d9d Sofia Papagiannaki
        if AstakosUser.objects.filter(email__iexact=addr):
426 49790d9d Sofia Papagiannaki
            raise forms.ValidationError(_(u'This email address is already in use. Please supply a different email address.'))
427 49790d9d Sofia Papagiannaki
        return addr
428 49790d9d Sofia Papagiannaki
    
429 49790d9d Sofia Papagiannaki
    def save(self, email_template_name, request, commit=True):
430 49790d9d Sofia Papagiannaki
        ec = super(EmailChangeForm, self).save(commit=False)
431 49790d9d Sofia Papagiannaki
        ec.user = request.user
432 49790d9d Sofia Papagiannaki
        activation_key = hashlib.sha1(str(random()) + smart_str(ec.new_email_address))
433 49790d9d Sofia Papagiannaki
        ec.activation_key=activation_key.hexdigest()
434 49790d9d Sofia Papagiannaki
        if commit:
435 49790d9d Sofia Papagiannaki
            ec.save()
436 49790d9d Sofia Papagiannaki
        send_change_email(ec, request, email_template_name=email_template_name)
437 49790d9d Sofia Papagiannaki
438 270dd48d Sofia Papagiannaki
class SignApprovalTermsForm(forms.ModelForm):
439 270dd48d Sofia Papagiannaki
    class Meta:
440 270dd48d Sofia Papagiannaki
        model = AstakosUser
441 270dd48d Sofia Papagiannaki
        fields = ("has_signed_terms",)
442 18ffbee1 Sofia Papagiannaki
443 270dd48d Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
444 270dd48d Sofia Papagiannaki
        super(SignApprovalTermsForm, self).__init__(*args, **kwargs)
445 18ffbee1 Sofia Papagiannaki
446 270dd48d Sofia Papagiannaki
    def clean_has_signed_terms(self):
447 270dd48d Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
448 270dd48d Sofia Papagiannaki
        if not has_signed_terms:
449 270dd48d Sofia Papagiannaki
            raise forms.ValidationError(_('You have to agree with the terms'))
450 270dd48d Sofia Papagiannaki
        return has_signed_terms
451 8f5a3a06 Sofia Papagiannaki
452 8f5a3a06 Sofia Papagiannaki
class InvitationForm(forms.ModelForm):
453 8f5a3a06 Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
454 8f5a3a06 Sofia Papagiannaki
    
455 18ffbee1 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
456 18ffbee1 Sofia Papagiannaki
        super(InvitationForm, self).__init__(*args, **kwargs)
457 18ffbee1 Sofia Papagiannaki
    
458 8f5a3a06 Sofia Papagiannaki
    class Meta:
459 8f5a3a06 Sofia Papagiannaki
        model = Invitation
460 8f5a3a06 Sofia Papagiannaki
        fields = ('username', 'realname')
461 8f5a3a06 Sofia Papagiannaki
    
462 8f5a3a06 Sofia Papagiannaki
    def clean_username(self):
463 8f5a3a06 Sofia Papagiannaki
        username = self.cleaned_data['username']
464 8f5a3a06 Sofia Papagiannaki
        try:
465 8f5a3a06 Sofia Papagiannaki
            Invitation.objects.get(username = username)
466 8f5a3a06 Sofia Papagiannaki
            raise forms.ValidationError(_('There is already invitation for this email.'))
467 8f5a3a06 Sofia Papagiannaki
        except Invitation.DoesNotExist:
468 8f5a3a06 Sofia Papagiannaki
            pass
469 18ffbee1 Sofia Papagiannaki
        return username
470 1039bab1 Sofia Papagiannaki
471 1039bab1 Sofia Papagiannaki
class ExtendedPasswordChangeForm(PasswordChangeForm):
472 1039bab1 Sofia Papagiannaki
    """
473 1039bab1 Sofia Papagiannaki
    Extends PasswordChangeForm by enabling user
474 1039bab1 Sofia Papagiannaki
    to optionally renew also the token.
475 1039bab1 Sofia Papagiannaki
    """
476 1039bab1 Sofia Papagiannaki
    renew = forms.BooleanField(label='Renew token', required=False)
477 1039bab1 Sofia Papagiannaki
    
478 1039bab1 Sofia Papagiannaki
    def __init__(self, user, *args, **kwargs):
479 1039bab1 Sofia Papagiannaki
        super(ExtendedPasswordChangeForm, self).__init__(user, *args, **kwargs)
480 1039bab1 Sofia Papagiannaki
    
481 1039bab1 Sofia Papagiannaki
    def save(self, commit=True):
482 1039bab1 Sofia Papagiannaki
        user = super(ExtendedPasswordChangeForm, self).save(commit=False)
483 1039bab1 Sofia Papagiannaki
        if self.cleaned_data.get('renew'):
484 1039bab1 Sofia Papagiannaki
            user.renew_token()
485 1039bab1 Sofia Papagiannaki
        if commit:
486 1039bab1 Sofia Papagiannaki
            user.save()
487 1039bab1 Sofia Papagiannaki
        return user