Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / forms.py @ 76c68fd6

History | View | Annotate | Download (21.2 kB)

1 aba1e498 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 18ffbee1 Sofia Papagiannaki
#
3 64cd4730 Antony Chazapis
# Redistribution and use in source and binary forms, with or
4 64cd4730 Antony Chazapis
# without modification, are permitted provided that the following
5 64cd4730 Antony Chazapis
# conditions are met:
6 18ffbee1 Sofia Papagiannaki
#
7 64cd4730 Antony Chazapis
#   1. Redistributions of source code must retain the above
8 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
9 64cd4730 Antony Chazapis
#      disclaimer.
10 18ffbee1 Sofia Papagiannaki
#
11 64cd4730 Antony Chazapis
#   2. Redistributions in binary form must reproduce the above
12 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
13 64cd4730 Antony Chazapis
#      disclaimer in the documentation and/or other materials
14 64cd4730 Antony Chazapis
#      provided with the distribution.
15 18ffbee1 Sofia Papagiannaki
#
16 64cd4730 Antony Chazapis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 64cd4730 Antony Chazapis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 64cd4730 Antony Chazapis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 64cd4730 Antony Chazapis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 64cd4730 Antony Chazapis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 64cd4730 Antony Chazapis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 64cd4730 Antony Chazapis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 64cd4730 Antony Chazapis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 64cd4730 Antony Chazapis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 64cd4730 Antony Chazapis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 64cd4730 Antony Chazapis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 64cd4730 Antony Chazapis
# POSSIBILITY OF SUCH DAMAGE.
28 18ffbee1 Sofia Papagiannaki
#
29 64cd4730 Antony Chazapis
# The views and conclusions contained in the software and
30 64cd4730 Antony Chazapis
# documentation are those of the authors and should not be
31 64cd4730 Antony Chazapis
# interpreted as representing official policies, either expressed
32 64cd4730 Antony Chazapis
# or implied, of GRNET S.A.
33 8f378756 Sofia Papagiannaki
from urlparse import urljoin
34 270dd48d Sofia Papagiannaki
from datetime import datetime
35 64cd4730 Antony Chazapis
36 64cd4730 Antony Chazapis
from django import forms
37 64cd4730 Antony Chazapis
from django.utils.translation import ugettext as _
38 1039bab1 Sofia Papagiannaki
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, \
39 1039bab1 Sofia Papagiannaki
    PasswordResetForm, PasswordChangeForm
40 e2125441 Sofia Papagiannaki
from django.core.mail import send_mail
41 e2125441 Sofia Papagiannaki
from django.contrib.auth.tokens import default_token_generator
42 e2125441 Sofia Papagiannaki
from django.template import Context, loader
43 e2125441 Sofia Papagiannaki
from django.utils.http import int_to_base36
44 374611bc Sofia Papagiannaki
from django.core.urlresolvers import reverse
45 270dd48d Sofia Papagiannaki
from django.utils.functional import lazy
46 18ffbee1 Sofia Papagiannaki
from django.utils.safestring import mark_safe
47 0a569195 Sofia Papagiannaki
from django.contrib import messages
48 49790d9d Sofia Papagiannaki
from django.utils.encoding import smart_str
49 8e45d6fd Sofia Papagiannaki
from django.forms.extras.widgets import SelectDateWidget
50 8e45d6fd Sofia Papagiannaki
from django.db.models import Q
51 5ed6816e Sofia Papagiannaki
52 8e45d6fd Sofia Papagiannaki
from astakos.im.models import *
53 111f3da6 Sofia Papagiannaki
from astakos.im.settings import INVITATIONS_PER_LEVEL, DEFAULT_FROM_EMAIL, \
54 111f3da6 Sofia Papagiannaki
    BASEURL, SITENAME, RECAPTCHA_PRIVATE_KEY, DEFAULT_CONTACT_EMAIL, \
55 111f3da6 Sofia Papagiannaki
    RECAPTCHA_ENABLED, LOGGING_LEVEL
56 45f8d9ff Sofia Papagiannaki
from astakos.im.widgets import DummyWidget, RecaptchaWidget
57 49790d9d Sofia Papagiannaki
from astakos.im.functions import send_change_email
58 270dd48d Sofia Papagiannaki
59 270dd48d Sofia Papagiannaki
# since Django 1.4 use django.core.urlresolvers.reverse_lazy instead
60 09e7393c Sofia Papagiannaki
from astakos.im.util import reverse_lazy, reserved_email, get_query
61 64cd4730 Antony Chazapis
62 3bf924ec Sofia Papagiannaki
import logging
63 49790d9d Sofia Papagiannaki
import hashlib
64 db7fecd9 Sofia Papagiannaki
import recaptcha.client.captcha as captcha
65 49790d9d Sofia Papagiannaki
from random import random
66 64cd4730 Antony Chazapis
67 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
68 e015e9e6 Sofia Papagiannaki
69 15efc749 Sofia Papagiannaki
class LocalUserCreationForm(UserCreationForm):
70 890b0eaf Sofia Papagiannaki
    """
71 890b0eaf Sofia Papagiannaki
    Extends the built in UserCreationForm in several ways:
72 18ffbee1 Sofia Papagiannaki

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

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

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