Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / forms.py @ 4abc7b29

History | View | Annotate | Download (10.6 kB)

1 aba1e498 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
35 64cd4730 Antony Chazapis
from django import forms
36 64cd4730 Antony Chazapis
from django.utils.translation import ugettext as _
37 e2125441 Sofia Papagiannaki
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, PasswordResetForm
38 e2125441 Sofia Papagiannaki
from django.core.mail import send_mail
39 e2125441 Sofia Papagiannaki
from django.contrib.auth.tokens import default_token_generator
40 e2125441 Sofia Papagiannaki
from django.template import Context, loader
41 e2125441 Sofia Papagiannaki
from django.utils.http import int_to_base36
42 374611bc Sofia Papagiannaki
from django.core.urlresolvers import reverse
43 5ed6816e Sofia Papagiannaki
44 0905ccd2 Sofia Papagiannaki
from astakos.im.models import AstakosUser
45 db7fecd9 Sofia Papagiannaki
from astakos.im.settings import INVITATIONS_PER_LEVEL, DEFAULT_FROM_EMAIL, BASEURL, SITENAME, RECAPTCHA_PRIVATE_KEY
46 db7fecd9 Sofia Papagiannaki
from astakos.im.widgets import DummyWidget, RecaptchaWidget
47 64cd4730 Antony Chazapis
48 3bf924ec Sofia Papagiannaki
import logging
49 db7fecd9 Sofia Papagiannaki
import recaptcha.client.captcha as captcha
50 64cd4730 Antony Chazapis
51 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
52 e015e9e6 Sofia Papagiannaki
53 15efc749 Sofia Papagiannaki
class LocalUserCreationForm(UserCreationForm):
54 890b0eaf Sofia Papagiannaki
    """
55 890b0eaf Sofia Papagiannaki
    Extends the built in UserCreationForm in several ways:
56 64cd4730 Antony Chazapis
    
57 8316698a Sofia Papagiannaki
    * Adds email, first_name, last_name, recaptcha_challenge_field, recaptcha_response_field field.
58 5ed6816e Sofia Papagiannaki
    * The username field isn't visible and it is assigned a generated id.
59 af4eb974 Sofia Papagiannaki
    * User created is not active. 
60 890b0eaf Sofia Papagiannaki
    """
61 db7fecd9 Sofia Papagiannaki
    recaptcha_challenge_field = forms.CharField(widget=DummyWidget)
62 db7fecd9 Sofia Papagiannaki
    recaptcha_response_field = forms.CharField(widget=RecaptchaWidget, label='')
63 890b0eaf Sofia Papagiannaki
    
64 794852f2 Sofia Papagiannaki
    class Meta:
65 794852f2 Sofia Papagiannaki
        model = AstakosUser
66 5ed6816e Sofia Papagiannaki
        fields = ("email", "first_name", "last_name")
67 64cd4730 Antony Chazapis
    
68 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
69 64cd4730 Antony Chazapis
        """
70 890b0eaf Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
71 64cd4730 Antony Chazapis
        """
72 db7fecd9 Sofia Papagiannaki
        if 'ip' in kwargs:
73 db7fecd9 Sofia Papagiannaki
            self.ip = kwargs['ip']
74 db7fecd9 Sofia Papagiannaki
            kwargs.pop('ip')
75 15efc749 Sofia Papagiannaki
        super(LocalUserCreationForm, self).__init__(*args, **kwargs)
76 890b0eaf Sofia Papagiannaki
        self.fields.keyOrder = ['email', 'first_name', 'last_name',
77 db7fecd9 Sofia Papagiannaki
                                'password1', 'password2',
78 db7fecd9 Sofia Papagiannaki
                                'recaptcha_challenge_field',
79 db7fecd9 Sofia Papagiannaki
                                'recaptcha_response_field']
80 64cd4730 Antony Chazapis
    
81 af4eb974 Sofia Papagiannaki
    def clean_email(self):
82 af4eb974 Sofia Papagiannaki
        email = self.cleaned_data['email']
83 881c856c Sofia Papagiannaki
        if not email:
84 881c856c Sofia Papagiannaki
            raise forms.ValidationError(_("This field is required"))
85 af4eb974 Sofia Papagiannaki
        try:
86 af4eb974 Sofia Papagiannaki
            AstakosUser.objects.get(email = email)
87 af4eb974 Sofia Papagiannaki
            raise forms.ValidationError(_("Email is reserved"))
88 af4eb974 Sofia Papagiannaki
        except AstakosUser.DoesNotExist:
89 af4eb974 Sofia Papagiannaki
            return email
90 af4eb974 Sofia Papagiannaki
    
91 db7fecd9 Sofia Papagiannaki
    def clean_recaptcha_response_field(self):
92 db7fecd9 Sofia Papagiannaki
        if 'recaptcha_challenge_field' in self.cleaned_data:
93 db7fecd9 Sofia Papagiannaki
            self.validate_captcha()
94 db7fecd9 Sofia Papagiannaki
        return self.cleaned_data['recaptcha_response_field']
95 db7fecd9 Sofia Papagiannaki
96 db7fecd9 Sofia Papagiannaki
    def clean_recaptcha_challenge_field(self):
97 db7fecd9 Sofia Papagiannaki
        if 'recaptcha_response_field' in self.cleaned_data:
98 db7fecd9 Sofia Papagiannaki
            self.validate_captcha()
99 db7fecd9 Sofia Papagiannaki
        return self.cleaned_data['recaptcha_challenge_field']
100 db7fecd9 Sofia Papagiannaki
101 db7fecd9 Sofia Papagiannaki
    def validate_captcha(self):
102 db7fecd9 Sofia Papagiannaki
        rcf = self.cleaned_data['recaptcha_challenge_field']
103 db7fecd9 Sofia Papagiannaki
        rrf = self.cleaned_data['recaptcha_response_field']
104 db7fecd9 Sofia Papagiannaki
        check = captcha.submit(rcf, rrf, RECAPTCHA_PRIVATE_KEY, self.ip)
105 db7fecd9 Sofia Papagiannaki
        if not check.is_valid:
106 db7fecd9 Sofia Papagiannaki
            raise forms.ValidationError(_('You have not entered the correct words'))
107 db7fecd9 Sofia Papagiannaki
    
108 890b0eaf Sofia Papagiannaki
    def save(self, commit=True):
109 64cd4730 Antony Chazapis
        """
110 890b0eaf Sofia Papagiannaki
        Saves the email, first_name and last_name properties, after the normal
111 890b0eaf Sofia Papagiannaki
        save behavior is complete.
112 890b0eaf Sofia Papagiannaki
        """
113 15efc749 Sofia Papagiannaki
        user = super(LocalUserCreationForm, self).save(commit=False)
114 3bf924ec Sofia Papagiannaki
        user.renew_token()
115 9fb8e808 Sofia Papagiannaki
        if commit:
116 9fb8e808 Sofia Papagiannaki
            user.save()
117 e015e9e6 Sofia Papagiannaki
        logger.info('Created user %s', user)
118 890b0eaf Sofia Papagiannaki
        return user
119 64cd4730 Antony Chazapis
120 15efc749 Sofia Papagiannaki
class InvitedLocalUserCreationForm(LocalUserCreationForm):
121 890b0eaf Sofia Papagiannaki
    """
122 15efc749 Sofia Papagiannaki
    Extends the LocalUserCreationForm: adds an inviter readonly field.
123 890b0eaf Sofia Papagiannaki
    """
124 3bf924ec Sofia Papagiannaki
    
125 3bf924ec Sofia Papagiannaki
    inviter = forms.CharField(widget=forms.TextInput(), label=_('Inviter Real Name'))
126 64cd4730 Antony Chazapis
    
127 794852f2 Sofia Papagiannaki
    class Meta:
128 794852f2 Sofia Papagiannaki
        model = AstakosUser
129 5ed6816e Sofia Papagiannaki
        fields = ("email", "first_name", "last_name")
130 64cd4730 Antony Chazapis
    
131 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
132 64cd4730 Antony Chazapis
        """
133 3bf924ec Sofia Papagiannaki
        Changes the order of fields, and removes the username field.
134 64cd4730 Antony Chazapis
        """
135 15efc749 Sofia Papagiannaki
        super(InvitedLocalUserCreationForm, self).__init__(*args, **kwargs)
136 9fb8e808 Sofia Papagiannaki
        self.fields.keyOrder = ['email', 'inviter', 'first_name',
137 8316698a Sofia Papagiannaki
                                'last_name', 'password1', 'password2',
138 8316698a Sofia Papagiannaki
                                'recaptcha_challenge_field',
139 8316698a Sofia Papagiannaki
                                'recaptcha_response_field']
140 64cd4730 Antony Chazapis
        #set readonly form fields
141 64cd4730 Antony Chazapis
        self.fields['inviter'].widget.attrs['readonly'] = True
142 794852f2 Sofia Papagiannaki
        self.fields['email'].widget.attrs['readonly'] = True
143 794852f2 Sofia Papagiannaki
        self.fields['username'].widget.attrs['readonly'] = True
144 9fb8e808 Sofia Papagiannaki
    
145 9fb8e808 Sofia Papagiannaki
    def save(self, commit=True):
146 15efc749 Sofia Papagiannaki
        user = super(InvitedLocalUserCreationForm, self).save(commit=False)
147 881c856c Sofia Papagiannaki
        level = user.invitation.inviter.level + 1
148 881c856c Sofia Papagiannaki
        user.level = level
149 8316698a Sofia Papagiannaki
        user.invitations = INVITATIONS_PER_LEVEL.get(level, 0)
150 8316698a Sofia Papagiannaki
        user.email_verified = True
151 9fb8e808 Sofia Papagiannaki
        if commit:
152 9fb8e808 Sofia Papagiannaki
            user.save()
153 9fb8e808 Sofia Papagiannaki
        return user
154 5ed6816e Sofia Papagiannaki
155 5ed6816e Sofia Papagiannaki
class LoginForm(AuthenticationForm):
156 5ed6816e Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
157 64cd4730 Antony Chazapis
158 890b0eaf Sofia Papagiannaki
class ProfileForm(forms.ModelForm):
159 890b0eaf Sofia Papagiannaki
    """
160 890b0eaf Sofia Papagiannaki
    Subclass of ``ModelForm`` for permiting user to edit his/her profile.
161 890b0eaf Sofia Papagiannaki
    Most of the fields are readonly since the user is not allowed to change them.
162 890b0eaf Sofia Papagiannaki
    
163 890b0eaf Sofia Papagiannaki
    The class defines a save method which sets ``is_verified`` to True so as the user
164 890b0eaf Sofia Papagiannaki
    during the next login will not to be redirected to profile page.
165 890b0eaf Sofia Papagiannaki
    """
166 c301698f Sofia Papagiannaki
    renew = forms.BooleanField(label='Renew token', required=False)
167 c301698f Sofia Papagiannaki
    
168 890b0eaf Sofia Papagiannaki
    class Meta:
169 890b0eaf Sofia Papagiannaki
        model = AstakosUser
170 a196eb7e Sofia Papagiannaki
        fields = ('email', 'first_name', 'last_name', 'auth_token', 'auth_token_expires')
171 64cd4730 Antony Chazapis
    
172 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
173 890b0eaf Sofia Papagiannaki
        super(ProfileForm, self).__init__(*args, **kwargs)
174 890b0eaf Sofia Papagiannaki
        instance = getattr(self, 'instance', None)
175 a196eb7e Sofia Papagiannaki
        ro_fields = ('auth_token', 'auth_token_expires', 'email')
176 890b0eaf Sofia Papagiannaki
        if instance and instance.id:
177 890b0eaf Sofia Papagiannaki
            for field in ro_fields:
178 890b0eaf Sofia Papagiannaki
                self.fields[field].widget.attrs['readonly'] = True
179 890b0eaf Sofia Papagiannaki
    
180 890b0eaf Sofia Papagiannaki
    def save(self, commit=True):
181 890b0eaf Sofia Papagiannaki
        user = super(ProfileForm, self).save(commit=False)
182 890b0eaf Sofia Papagiannaki
        user.is_verified = True
183 c301698f Sofia Papagiannaki
        if self.cleaned_data.get('renew'):
184 c301698f Sofia Papagiannaki
            user.renew_token()
185 890b0eaf Sofia Papagiannaki
        if commit:
186 890b0eaf Sofia Papagiannaki
            user.save()
187 890b0eaf Sofia Papagiannaki
        return user
188 64cd4730 Antony Chazapis
189 15efc749 Sofia Papagiannaki
class ThirdPartyUserCreationForm(ProfileForm):
190 15efc749 Sofia Papagiannaki
    class Meta:
191 15efc749 Sofia Papagiannaki
        model = AstakosUser
192 15efc749 Sofia Papagiannaki
        fields = ('email', 'last_name', 'first_name', 'affiliation', 'provider', 'third_party_identifier')
193 15efc749 Sofia Papagiannaki
    
194 15efc749 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
195 db7fecd9 Sofia Papagiannaki
        if 'ip' in kwargs:
196 db7fecd9 Sofia Papagiannaki
            self.ip = kwargs['ip']
197 db7fecd9 Sofia Papagiannaki
            kwargs.pop('ip')
198 15efc749 Sofia Papagiannaki
        super(ThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
199 15efc749 Sofia Papagiannaki
        self.fields.keyOrder = ['email']
200 15efc749 Sofia Papagiannaki
    
201 15efc749 Sofia Papagiannaki
    def clean_email(self):
202 15efc749 Sofia Papagiannaki
        email = self.cleaned_data['email']
203 15efc749 Sofia Papagiannaki
        if not email:
204 15efc749 Sofia Papagiannaki
            raise forms.ValidationError(_("This field is required"))
205 15efc749 Sofia Papagiannaki
        try:
206 15efc749 Sofia Papagiannaki
            user = AstakosUser.objects.get(email = email)
207 15efc749 Sofia Papagiannaki
            raise forms.ValidationError(_("Email is reserved"))
208 15efc749 Sofia Papagiannaki
        except AstakosUser.DoesNotExist:
209 15efc749 Sofia Papagiannaki
            return email
210 15efc749 Sofia Papagiannaki
    
211 15efc749 Sofia Papagiannaki
    def save(self, commit=True):
212 15efc749 Sofia Papagiannaki
        user = super(ThirdPartyUserCreationForm, self).save(commit=False)
213 15efc749 Sofia Papagiannaki
        user.verified = False
214 15efc749 Sofia Papagiannaki
        user.renew_token()
215 15efc749 Sofia Papagiannaki
        if commit:
216 15efc749 Sofia Papagiannaki
            user.save()
217 e015e9e6 Sofia Papagiannaki
        logger.info('Created user %s', user)
218 15efc749 Sofia Papagiannaki
        return user
219 15efc749 Sofia Papagiannaki
220 15efc749 Sofia Papagiannaki
class InvitedThirdPartyUserCreationForm(ThirdPartyUserCreationForm):
221 15efc749 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
222 15efc749 Sofia Papagiannaki
        super(InvitedThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
223 15efc749 Sofia Papagiannaki
        #set readonly form fields
224 15efc749 Sofia Papagiannaki
        self.fields['email'].widget.attrs['readonly'] = True
225 64cd4730 Antony Chazapis
226 890b0eaf Sofia Papagiannaki
class FeedbackForm(forms.Form):
227 890b0eaf Sofia Papagiannaki
    """
228 890b0eaf Sofia Papagiannaki
    Form for writing feedback.
229 890b0eaf Sofia Papagiannaki
    """
230 890b0eaf Sofia Papagiannaki
    feedback_msg = forms.CharField(widget=forms.Textarea(),
231 890b0eaf Sofia Papagiannaki
                                label=u'Message', required=False)
232 92defad4 Sofia Papagiannaki
    feedback_data = forms.CharField(widget=forms.HiddenInput(),
233 92defad4 Sofia Papagiannaki
                                label='', required=False)
234 5ed6816e Sofia Papagiannaki
235 5ed6816e Sofia Papagiannaki
class SendInvitationForm(forms.Form):
236 5ed6816e Sofia Papagiannaki
    """
237 5ed6816e Sofia Papagiannaki
    Form for sending an invitations
238 5ed6816e Sofia Papagiannaki
    """
239 5ed6816e Sofia Papagiannaki
    
240 5ed6816e Sofia Papagiannaki
    email = forms.EmailField(required = True, label = 'Email address')
241 5ed6816e Sofia Papagiannaki
    first_name = forms.EmailField(label = 'First name')
242 5ed6816e Sofia Papagiannaki
    last_name = forms.EmailField(label = 'Last name')
243 e2125441 Sofia Papagiannaki
244 e2125441 Sofia Papagiannaki
class ExtendedPasswordResetForm(PasswordResetForm):
245 e2125441 Sofia Papagiannaki
    """
246 e2125441 Sofia Papagiannaki
    Extends PasswordResetForm by overriding save method:
247 e2125441 Sofia Papagiannaki
    passes a custom from_email in send_mail.
248 e2125441 Sofia Papagiannaki
    
249 e2125441 Sofia Papagiannaki
    Since Django 1.3 this is useless since ``django.contrib.auth.views.reset_password``
250 e2125441 Sofia Papagiannaki
    accepts a from_email argument.
251 e2125441 Sofia Papagiannaki
    """
252 e2125441 Sofia Papagiannaki
    def save(self, domain_override=None, email_template_name='registration/password_reset_email.html',
253 e2125441 Sofia Papagiannaki
             use_https=False, token_generator=default_token_generator, request=None):
254 e2125441 Sofia Papagiannaki
        """
255 e2125441 Sofia Papagiannaki
        Generates a one-use only link for resetting password and sends to the user.
256 e2125441 Sofia Papagiannaki
        """
257 e2125441 Sofia Papagiannaki
        for user in self.users_cache:
258 8f378756 Sofia Papagiannaki
            url = urljoin(BASEURL,
259 8f378756 Sofia Papagiannaki
                          '/im/local/reset/confirm/%s-%s' %(int_to_base36(user.id),
260 8f378756 Sofia Papagiannaki
                                                            token_generator.make_token(user)))
261 e2125441 Sofia Papagiannaki
            t = loader.get_template(email_template_name)
262 e2125441 Sofia Papagiannaki
            c = {
263 e2125441 Sofia Papagiannaki
                'email': user.email,
264 8f378756 Sofia Papagiannaki
                'url': url,
265 374611bc Sofia Papagiannaki
                'site_name': SITENAME,
266 e2125441 Sofia Papagiannaki
                'user': user,
267 8f378756 Sofia Papagiannaki
                'baseurl': BASEURL
268 e2125441 Sofia Papagiannaki
            }
269 d552ecb7 Antony Chazapis
            from_email = DEFAULT_FROM_EMAIL
270 4abc7b29 Sofia Papagiannaki
            send_mail(_("Password reset on %s alpha2 testing") % SITENAME,
271 e2125441 Sofia Papagiannaki
                t.render(Context(c)), from_email, [user.email])