Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (10.4 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 af4eb974 Sofia Papagiannaki
    * Adds email, first_name and last_name 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 5ed6816e Sofia Papagiannaki
                                'last_name', 'password1', 'password2']
138 64cd4730 Antony Chazapis
        #set readonly form fields
139 64cd4730 Antony Chazapis
        self.fields['inviter'].widget.attrs['readonly'] = True
140 794852f2 Sofia Papagiannaki
        self.fields['email'].widget.attrs['readonly'] = True
141 794852f2 Sofia Papagiannaki
        self.fields['username'].widget.attrs['readonly'] = True
142 9fb8e808 Sofia Papagiannaki
    
143 9fb8e808 Sofia Papagiannaki
    def save(self, commit=True):
144 15efc749 Sofia Papagiannaki
        user = super(InvitedLocalUserCreationForm, self).save(commit=False)
145 881c856c Sofia Papagiannaki
        level = user.invitation.inviter.level + 1
146 881c856c Sofia Papagiannaki
        user.level = level
147 92defad4 Sofia Papagiannaki
        user.invitations = INVITATIONS_PER_LEVEL[level]
148 9fb8e808 Sofia Papagiannaki
        if commit:
149 9fb8e808 Sofia Papagiannaki
            user.save()
150 9fb8e808 Sofia Papagiannaki
        return user
151 5ed6816e Sofia Papagiannaki
152 5ed6816e Sofia Papagiannaki
class LoginForm(AuthenticationForm):
153 5ed6816e Sofia Papagiannaki
    username = forms.EmailField(label=_("Email"))
154 64cd4730 Antony Chazapis
155 890b0eaf Sofia Papagiannaki
class ProfileForm(forms.ModelForm):
156 890b0eaf Sofia Papagiannaki
    """
157 890b0eaf Sofia Papagiannaki
    Subclass of ``ModelForm`` for permiting user to edit his/her profile.
158 890b0eaf Sofia Papagiannaki
    Most of the fields are readonly since the user is not allowed to change them.
159 890b0eaf Sofia Papagiannaki
    
160 890b0eaf Sofia Papagiannaki
    The class defines a save method which sets ``is_verified`` to True so as the user
161 890b0eaf Sofia Papagiannaki
    during the next login will not to be redirected to profile page.
162 890b0eaf Sofia Papagiannaki
    """
163 c301698f Sofia Papagiannaki
    renew = forms.BooleanField(label='Renew token', required=False)
164 c301698f Sofia Papagiannaki
    
165 890b0eaf Sofia Papagiannaki
    class Meta:
166 890b0eaf Sofia Papagiannaki
        model = AstakosUser
167 a196eb7e Sofia Papagiannaki
        fields = ('email', 'first_name', 'last_name', 'auth_token', 'auth_token_expires')
168 64cd4730 Antony Chazapis
    
169 64cd4730 Antony Chazapis
    def __init__(self, *args, **kwargs):
170 890b0eaf Sofia Papagiannaki
        super(ProfileForm, self).__init__(*args, **kwargs)
171 890b0eaf Sofia Papagiannaki
        instance = getattr(self, 'instance', None)
172 a196eb7e Sofia Papagiannaki
        ro_fields = ('auth_token', 'auth_token_expires', 'email')
173 890b0eaf Sofia Papagiannaki
        if instance and instance.id:
174 890b0eaf Sofia Papagiannaki
            for field in ro_fields:
175 890b0eaf Sofia Papagiannaki
                self.fields[field].widget.attrs['readonly'] = True
176 890b0eaf Sofia Papagiannaki
    
177 890b0eaf Sofia Papagiannaki
    def save(self, commit=True):
178 890b0eaf Sofia Papagiannaki
        user = super(ProfileForm, self).save(commit=False)
179 890b0eaf Sofia Papagiannaki
        user.is_verified = True
180 c301698f Sofia Papagiannaki
        if self.cleaned_data.get('renew'):
181 c301698f Sofia Papagiannaki
            user.renew_token()
182 890b0eaf Sofia Papagiannaki
        if commit:
183 890b0eaf Sofia Papagiannaki
            user.save()
184 890b0eaf Sofia Papagiannaki
        return user
185 64cd4730 Antony Chazapis
186 15efc749 Sofia Papagiannaki
class ThirdPartyUserCreationForm(ProfileForm):
187 15efc749 Sofia Papagiannaki
    class Meta:
188 15efc749 Sofia Papagiannaki
        model = AstakosUser
189 15efc749 Sofia Papagiannaki
        fields = ('email', 'last_name', 'first_name', 'affiliation', 'provider', 'third_party_identifier')
190 15efc749 Sofia Papagiannaki
    
191 15efc749 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
192 db7fecd9 Sofia Papagiannaki
        if 'ip' in kwargs:
193 db7fecd9 Sofia Papagiannaki
            self.ip = kwargs['ip']
194 db7fecd9 Sofia Papagiannaki
            kwargs.pop('ip')
195 15efc749 Sofia Papagiannaki
        super(ThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
196 15efc749 Sofia Papagiannaki
        self.fields.keyOrder = ['email']
197 15efc749 Sofia Papagiannaki
    
198 15efc749 Sofia Papagiannaki
    def clean_email(self):
199 15efc749 Sofia Papagiannaki
        email = self.cleaned_data['email']
200 15efc749 Sofia Papagiannaki
        if not email:
201 15efc749 Sofia Papagiannaki
            raise forms.ValidationError(_("This field is required"))
202 15efc749 Sofia Papagiannaki
        try:
203 15efc749 Sofia Papagiannaki
            user = AstakosUser.objects.get(email = email)
204 15efc749 Sofia Papagiannaki
            raise forms.ValidationError(_("Email is reserved"))
205 15efc749 Sofia Papagiannaki
        except AstakosUser.DoesNotExist:
206 15efc749 Sofia Papagiannaki
            return email
207 15efc749 Sofia Papagiannaki
    
208 15efc749 Sofia Papagiannaki
    def save(self, commit=True):
209 15efc749 Sofia Papagiannaki
        user = super(ThirdPartyUserCreationForm, self).save(commit=False)
210 15efc749 Sofia Papagiannaki
        user.verified = False
211 15efc749 Sofia Papagiannaki
        user.renew_token()
212 15efc749 Sofia Papagiannaki
        if commit:
213 15efc749 Sofia Papagiannaki
            user.save()
214 e015e9e6 Sofia Papagiannaki
        logger.info('Created user %s', user)
215 15efc749 Sofia Papagiannaki
        return user
216 15efc749 Sofia Papagiannaki
217 15efc749 Sofia Papagiannaki
class InvitedThirdPartyUserCreationForm(ThirdPartyUserCreationForm):
218 15efc749 Sofia Papagiannaki
    def __init__(self, *args, **kwargs):
219 15efc749 Sofia Papagiannaki
        super(InvitedThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
220 15efc749 Sofia Papagiannaki
        #set readonly form fields
221 15efc749 Sofia Papagiannaki
        self.fields['email'].widget.attrs['readonly'] = True
222 64cd4730 Antony Chazapis
223 890b0eaf Sofia Papagiannaki
class FeedbackForm(forms.Form):
224 890b0eaf Sofia Papagiannaki
    """
225 890b0eaf Sofia Papagiannaki
    Form for writing feedback.
226 890b0eaf Sofia Papagiannaki
    """
227 890b0eaf Sofia Papagiannaki
    feedback_msg = forms.CharField(widget=forms.Textarea(),
228 890b0eaf Sofia Papagiannaki
                                label=u'Message', required=False)
229 92defad4 Sofia Papagiannaki
    feedback_data = forms.CharField(widget=forms.HiddenInput(),
230 92defad4 Sofia Papagiannaki
                                label='', required=False)
231 5ed6816e Sofia Papagiannaki
232 5ed6816e Sofia Papagiannaki
class SendInvitationForm(forms.Form):
233 5ed6816e Sofia Papagiannaki
    """
234 5ed6816e Sofia Papagiannaki
    Form for sending an invitations
235 5ed6816e Sofia Papagiannaki
    """
236 5ed6816e Sofia Papagiannaki
    
237 5ed6816e Sofia Papagiannaki
    email = forms.EmailField(required = True, label = 'Email address')
238 5ed6816e Sofia Papagiannaki
    first_name = forms.EmailField(label = 'First name')
239 5ed6816e Sofia Papagiannaki
    last_name = forms.EmailField(label = 'Last name')
240 e2125441 Sofia Papagiannaki
241 e2125441 Sofia Papagiannaki
class ExtendedPasswordResetForm(PasswordResetForm):
242 e2125441 Sofia Papagiannaki
    """
243 e2125441 Sofia Papagiannaki
    Extends PasswordResetForm by overriding save method:
244 e2125441 Sofia Papagiannaki
    passes a custom from_email in send_mail.
245 e2125441 Sofia Papagiannaki
    
246 e2125441 Sofia Papagiannaki
    Since Django 1.3 this is useless since ``django.contrib.auth.views.reset_password``
247 e2125441 Sofia Papagiannaki
    accepts a from_email argument.
248 e2125441 Sofia Papagiannaki
    """
249 e2125441 Sofia Papagiannaki
    def save(self, domain_override=None, email_template_name='registration/password_reset_email.html',
250 e2125441 Sofia Papagiannaki
             use_https=False, token_generator=default_token_generator, request=None):
251 e2125441 Sofia Papagiannaki
        """
252 e2125441 Sofia Papagiannaki
        Generates a one-use only link for resetting password and sends to the user.
253 e2125441 Sofia Papagiannaki
        """
254 e2125441 Sofia Papagiannaki
        for user in self.users_cache:
255 8f378756 Sofia Papagiannaki
            url = urljoin(BASEURL,
256 8f378756 Sofia Papagiannaki
                          '/im/local/reset/confirm/%s-%s' %(int_to_base36(user.id),
257 8f378756 Sofia Papagiannaki
                                                            token_generator.make_token(user)))
258 e2125441 Sofia Papagiannaki
            t = loader.get_template(email_template_name)
259 e2125441 Sofia Papagiannaki
            c = {
260 e2125441 Sofia Papagiannaki
                'email': user.email,
261 8f378756 Sofia Papagiannaki
                'url': url,
262 374611bc Sofia Papagiannaki
                'site_name': SITENAME,
263 e2125441 Sofia Papagiannaki
                'user': user,
264 8f378756 Sofia Papagiannaki
                'baseurl': BASEURL
265 e2125441 Sofia Papagiannaki
            }
266 d552ecb7 Antony Chazapis
            from_email = DEFAULT_FROM_EMAIL
267 374611bc Sofia Papagiannaki
            send_mail(_("Password reset on %s") % SITENAME,
268 e2125441 Sofia Papagiannaki
                t.render(Context(c)), from_email, [user.email])