Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / forms.py @ 09e7393c

History | View | Annotate | Download (17.3 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 09e7393c Sofia Papagiannaki
from astakos.im.models import AstakosUser, Invitation, get_latest_terms
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 09e7393c Sofia Papagiannaki
from astakos.im.util import reverse_lazy, 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
        return email
215 18ffbee1 Sofia Papagiannaki
    
216 18ffbee1 Sofia Papagiannaki
    def clean_has_signed_terms(self):
217 18ffbee1 Sofia Papagiannaki
        has_signed_terms = self.cleaned_data['has_signed_terms']
218 18ffbee1 Sofia Papagiannaki
        if not has_signed_terms:
219 18ffbee1 Sofia Papagiannaki
            raise forms.ValidationError(_('You have to agree with the terms'))
220 18ffbee1 Sofia Papagiannaki
        return has_signed_terms
221 8f5a3a06 Sofia Papagiannaki
    
222 8f5a3a06 Sofia Papagiannaki
    def save(self, commit=True):
223 8f5a3a06 Sofia Papagiannaki
        user = super(ThirdPartyUserCreationForm, self).save(commit=False)
224 8f5a3a06 Sofia Papagiannaki
        user.set_unusable_password()
225 18ffbee1 Sofia Papagiannaki
        user.renew_token()
226 0a569195 Sofia Papagiannaki
        user.provider = get_query(self.request).get('provider')
227 8f5a3a06 Sofia Papagiannaki
        if commit:
228 8f5a3a06 Sofia Papagiannaki
            user.save()
229 8f5a3a06 Sofia Papagiannaki
        logger.info('Created user %s', user)
230 8f5a3a06 Sofia Papagiannaki
        return user
231 8f5a3a06 Sofia Papagiannaki
232 8f5a3a06 Sofia Papagiannaki
class InvitedThirdPartyUserCreationForm(ThirdPartyUserCreationForm):
233 4e30244e Sofia Papagiannaki
    """
234 4e30244e Sofia Papagiannaki
    Extends the LocalUserCreationForm: adds an inviter readonly field.
235 4e30244e Sofia Papagiannaki
    """
236 4e30244e Sofia Papagiannaki
    inviter = forms.CharField(widget=forms.TextInput(), label=_('Inviter Real Name'))
237 4e30244e Sofia Papagiannaki
    
238 8f5a3a06 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
239 4e30244e Sofia Papagiannaki
        """
240 4e30244e Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
241 4e30244e Sofia Papagiannaki
        """
242 8f5a3a06 Sofia Papagiannaki
        super(InvitedThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
243 4e30244e Sofia Papagiannaki
244 8f5a3a06 Sofia Papagiannaki
        #set readonly form fields
245 4e30244e Sofia Papagiannaki
        ro = ('inviter', 'email',)
246 4e30244e Sofia Papagiannaki
        for f in ro:
247 4e30244e Sofia Papagiannaki
            self.fields[f].widget.attrs['readonly'] = True
248 4e30244e Sofia Papagiannaki
    
249 4e30244e Sofia Papagiannaki
    def save(self, commit=True):
250 4e30244e Sofia Papagiannaki
        user = super(InvitedThirdPartyUserCreationForm, self).save(commit=False)
251 4e30244e Sofia Papagiannaki
        level = user.invitation.inviter.level + 1
252 4e30244e Sofia Papagiannaki
        user.level = level
253 4e30244e Sofia Papagiannaki
        user.invitations = INVITATIONS_PER_LEVEL.get(level, 0)
254 4e30244e Sofia Papagiannaki
        user.email_verified = True
255 4e30244e Sofia Papagiannaki
        if commit:
256 4e30244e Sofia Papagiannaki
            user.save()
257 4e30244e Sofia Papagiannaki
        return user
258 8f5a3a06 Sofia Papagiannaki
259 18ffbee1 Sofia Papagiannaki
class ShibbolethUserCreationForm(ThirdPartyUserCreationForm):
260 18ffbee1 Sofia Papagiannaki
    def clean_email(self):
261 18ffbee1 Sofia Papagiannaki
        email = self.cleaned_data['email']
262 0a569195 Sofia Papagiannaki
        for user in AstakosUser.objects.filter(email = email):
263 0a569195 Sofia Papagiannaki
            if user.provider == 'shibboleth':
264 18ffbee1 Sofia Papagiannaki
                raise forms.ValidationError(_("This email is already associated with another shibboleth account."))
265 ab8f7956 Sofia Papagiannaki
        super(ShibbolethUserCreationForm, self).clean_email()
266 0a569195 Sofia Papagiannaki
        return email
267 4e30244e Sofia Papagiannaki
268 0a569195 Sofia Papagiannaki
class InvitedShibbolethUserCreationForm(ShibbolethUserCreationForm, InvitedThirdPartyUserCreationForm):
269 4e30244e Sofia Papagiannaki
    pass
270 18ffbee1 Sofia Papagiannaki
    
271 5ed6816e Sofia Papagiannaki
class LoginForm(AuthenticationForm):
272 5ed6816e Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
273 672d445a Sofia Papagiannaki
    recaptcha_challenge_field = forms.CharField(widget=DummyWidget)
274 672d445a Sofia Papagiannaki
    recaptcha_response_field = forms.CharField(widget=RecaptchaWidget, label='')
275 672d445a Sofia Papagiannaki
    
276 672d445a Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
277 672d445a Sofia Papagiannaki
        was_limited = kwargs.get('was_limited', False)
278 672d445a Sofia Papagiannaki
        request = kwargs.get('request', None)
279 672d445a Sofia Papagiannaki
        if request:
280 672d445a Sofia Papagiannaki
            self.ip = request.META.get('REMOTE_ADDR',
281 672d445a Sofia Papagiannaki
                                       request.META.get('HTTP_X_REAL_IP', None))
282 672d445a Sofia Papagiannaki
        
283 672d445a Sofia Papagiannaki
        t = ('request', 'was_limited')
284 672d445a Sofia Papagiannaki
        for elem in t:
285 672d445a Sofia Papagiannaki
            if elem in kwargs.keys():
286 672d445a Sofia Papagiannaki
                kwargs.pop(elem)
287 672d445a Sofia Papagiannaki
        super(LoginForm, self).__init__(*args, **kwargs)
288 672d445a Sofia Papagiannaki
        
289 672d445a Sofia Papagiannaki
        self.fields.keyOrder = ['username', 'password']
290 672d445a Sofia Papagiannaki
        if was_limited and RECAPTCHA_ENABLED:
291 672d445a Sofia Papagiannaki
            self.fields.keyOrder.extend(['recaptcha_challenge_field',
292 672d445a Sofia Papagiannaki
                                         'recaptcha_response_field',])
293 672d445a Sofia Papagiannaki
    
294 672d445a Sofia Papagiannaki
    def clean_recaptcha_response_field(self):
295 672d445a Sofia Papagiannaki
        if 'recaptcha_challenge_field' in self.cleaned_data:
296 672d445a Sofia Papagiannaki
            self.validate_captcha()
297 672d445a Sofia Papagiannaki
        return self.cleaned_data['recaptcha_response_field']
298 672d445a Sofia Papagiannaki
299 672d445a Sofia Papagiannaki
    def clean_recaptcha_challenge_field(self):
300 672d445a Sofia Papagiannaki
        if 'recaptcha_response_field' in self.cleaned_data:
301 672d445a Sofia Papagiannaki
            self.validate_captcha()
302 672d445a Sofia Papagiannaki
        return self.cleaned_data['recaptcha_challenge_field']
303 672d445a Sofia Papagiannaki
304 672d445a Sofia Papagiannaki
    def validate_captcha(self):
305 672d445a Sofia Papagiannaki
        rcf = self.cleaned_data['recaptcha_challenge_field']
306 672d445a Sofia Papagiannaki
        rrf = self.cleaned_data['recaptcha_response_field']
307 672d445a Sofia Papagiannaki
        check = captcha.submit(rcf, rrf, RECAPTCHA_PRIVATE_KEY, self.ip)
308 672d445a Sofia Papagiannaki
        if not check.is_valid:
309 672d445a Sofia Papagiannaki
            raise forms.ValidationError(_('You have not entered the correct words'))
310 64cd4730 Antony Chazapis
311 890b0eaf Sofia Papagiannaki
class ProfileForm(forms.ModelForm):
312 890b0eaf Sofia Papagiannaki
    """
313 890b0eaf Sofia Papagiannaki
    Subclass of ``ModelForm`` for permiting user to edit his/her profile.
314 890b0eaf Sofia Papagiannaki
    Most of the fields are readonly since the user is not allowed to change them.
315 18ffbee1 Sofia Papagiannaki

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

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