Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / forms.py @ 0a569195

History | View | Annotate | Download (17.4 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 e2125441 Sofia Papagiannaki
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, PasswordResetForm
39 e2125441 Sofia Papagiannaki
from django.core.mail import send_mail
40 e2125441 Sofia Papagiannaki
from django.contrib.auth.tokens import default_token_generator
41 e2125441 Sofia Papagiannaki
from django.template import Context, loader
42 e2125441 Sofia Papagiannaki
from django.utils.http import int_to_base36
43 374611bc Sofia Papagiannaki
from django.core.urlresolvers import reverse
44 270dd48d Sofia Papagiannaki
from django.utils.functional import lazy
45 18ffbee1 Sofia Papagiannaki
from django.utils.safestring import mark_safe
46 0a569195 Sofia Papagiannaki
from django.contrib import messages
47 5ed6816e Sofia Papagiannaki
48 8f5a3a06 Sofia Papagiannaki
from astakos.im.models import AstakosUser, Invitation
49 4e30244e Sofia Papagiannaki
from astakos.im.settings import INVITATIONS_PER_LEVEL, DEFAULT_FROM_EMAIL, SITENAME, RECAPTCHA_PRIVATE_KEY, DEFAULT_CONTACT_EMAIL, RECAPTCHA_ENABLED
50 270dd48d Sofia Papagiannaki
from astakos.im.widgets import DummyWidget, RecaptchaWidget, ApprovalTermsWidget
51 270dd48d Sofia Papagiannaki
52 270dd48d Sofia Papagiannaki
# since Django 1.4 use django.core.urlresolvers.reverse_lazy instead
53 0a569195 Sofia Papagiannaki
from astakos.im.util import reverse_lazy, get_latest_terms, reserved_email, get_query
54 64cd4730 Antony Chazapis
55 3bf924ec Sofia Papagiannaki
import logging
56 db7fecd9 Sofia Papagiannaki
import recaptcha.client.captcha as captcha
57 64cd4730 Antony Chazapis
58 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
59 e015e9e6 Sofia Papagiannaki
60 15efc749 Sofia Papagiannaki
class LocalUserCreationForm(UserCreationForm):
61 890b0eaf Sofia Papagiannaki
    """
62 890b0eaf Sofia Papagiannaki
    Extends the built in UserCreationForm in several ways:
63 18ffbee1 Sofia Papagiannaki

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

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

367 e2125441 Sofia Papagiannaki
    Since Django 1.3 this is useless since ``django.contrib.auth.views.reset_password``
368 e2125441 Sofia Papagiannaki
    accepts a from_email argument.
369 e2125441 Sofia Papagiannaki
    """
370 23c271b3 Sofia Papagiannaki
    def clean_email(self):
371 23c271b3 Sofia Papagiannaki
        email = super(ExtendedPasswordResetForm, self).clean_email()
372 23c271b3 Sofia Papagiannaki
        try:
373 0a569195 Sofia Papagiannaki
            user = AstakosUser.objects.get(email=email, is_active=True)
374 23c271b3 Sofia Papagiannaki
            if not user.has_usable_password():
375 23c271b3 Sofia Papagiannaki
                raise forms.ValidationError(_("This account has not a usable password."))
376 23c271b3 Sofia Papagiannaki
        except AstakosUser.DoesNotExist, e:
377 23c271b3 Sofia Papagiannaki
            raise forms.ValidationError(_('That e-mail address doesn\'t have an associated user account. Are you sure you\'ve registered?'))
378 23c271b3 Sofia Papagiannaki
        return email
379 23c271b3 Sofia Papagiannaki
    
380 e2125441 Sofia Papagiannaki
    def save(self, domain_override=None, email_template_name='registration/password_reset_email.html',
381 e2125441 Sofia Papagiannaki
             use_https=False, token_generator=default_token_generator, request=None):
382 e2125441 Sofia Papagiannaki
        """
383 e2125441 Sofia Papagiannaki
        Generates a one-use only link for resetting password and sends to the user.
384 e2125441 Sofia Papagiannaki
        """
385 e2125441 Sofia Papagiannaki
        for user in self.users_cache:
386 18ffbee1 Sofia Papagiannaki
            url = reverse('django.contrib.auth.views.password_reset_confirm',
387 18ffbee1 Sofia Papagiannaki
                          kwargs={'uidb36':int_to_base36(user.id),
388 18ffbee1 Sofia Papagiannaki
                                  'token':token_generator.make_token(user)})
389 18ffbee1 Sofia Papagiannaki
            url = request.build_absolute_uri(url)
390 e2125441 Sofia Papagiannaki
            t = loader.get_template(email_template_name)
391 e2125441 Sofia Papagiannaki
            c = {
392 e2125441 Sofia Papagiannaki
                'email': user.email,
393 8f378756 Sofia Papagiannaki
                'url': url,
394 374611bc Sofia Papagiannaki
                'site_name': SITENAME,
395 e2125441 Sofia Papagiannaki
                'user': user,
396 4e30244e Sofia Papagiannaki
                'baseurl': request.build_absolute_uri(),
397 09122dd8 Sofia Papagiannaki
                'support': DEFAULT_CONTACT_EMAIL
398 e2125441 Sofia Papagiannaki
            }
399 d552ecb7 Antony Chazapis
            from_email = DEFAULT_FROM_EMAIL
400 4abc7b29 Sofia Papagiannaki
            send_mail(_("Password reset on %s alpha2 testing") % SITENAME,
401 e2125441 Sofia Papagiannaki
                t.render(Context(c)), from_email, [user.email])
402 270dd48d Sofia Papagiannaki
403 270dd48d Sofia Papagiannaki
class SignApprovalTermsForm(forms.ModelForm):
404 270dd48d Sofia Papagiannaki
    class Meta:
405 270dd48d Sofia Papagiannaki
        model = AstakosUser
406 270dd48d Sofia Papagiannaki
        fields = ("has_signed_terms",)
407 18ffbee1 Sofia Papagiannaki
408 270dd48d Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
409 270dd48d Sofia Papagiannaki
        super(SignApprovalTermsForm, self).__init__(*args, **kwargs)
410 18ffbee1 Sofia Papagiannaki
411 270dd48d Sofia Papagiannaki
    def clean_has_signed_terms(self):
412 270dd48d Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
413 270dd48d Sofia Papagiannaki
        if not has_signed_terms:
414 270dd48d Sofia Papagiannaki
            raise forms.ValidationError(_('You have to agree with the terms'))
415 270dd48d Sofia Papagiannaki
        return has_signed_terms
416 8f5a3a06 Sofia Papagiannaki
417 8f5a3a06 Sofia Papagiannaki
class InvitationForm(forms.ModelForm):
418 8f5a3a06 Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
419 8f5a3a06 Sofia Papagiannaki
    
420 18ffbee1 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
421 18ffbee1 Sofia Papagiannaki
        super(InvitationForm, self).__init__(*args, **kwargs)
422 18ffbee1 Sofia Papagiannaki
    
423 8f5a3a06 Sofia Papagiannaki
    class Meta:
424 8f5a3a06 Sofia Papagiannaki
        model = Invitation
425 8f5a3a06 Sofia Papagiannaki
        fields = ('username', 'realname')
426 8f5a3a06 Sofia Papagiannaki
    
427 8f5a3a06 Sofia Papagiannaki
    def clean_username(self):
428 8f5a3a06 Sofia Papagiannaki
        username = self.cleaned_data['username']
429 8f5a3a06 Sofia Papagiannaki
        try:
430 8f5a3a06 Sofia Papagiannaki
            Invitation.objects.get(username = username)
431 8f5a3a06 Sofia Papagiannaki
            raise forms.ValidationError(_('There is already invitation for this email.'))
432 8f5a3a06 Sofia Papagiannaki
        except Invitation.DoesNotExist:
433 8f5a3a06 Sofia Papagiannaki
            pass
434 18ffbee1 Sofia Papagiannaki
        return username