Revision 5ce3ce4f snf-astakos-app/astakos/im/forms.py

b/snf-astakos-app/astakos/im/forms.py
35 35
from django import forms
36 36
from django.utils.translation import ugettext as _
37 37
from django.contrib.auth.forms import (UserCreationForm, AuthenticationForm,
38
    PasswordResetForm, PasswordChangeForm
39
)
38
                                       PasswordResetForm, PasswordChangeForm
39
                                       )
40 40
from django.core.mail import send_mail
41 41
from django.contrib.auth.tokens import default_token_generator
42 42
from django.template import Context, loader
......
47 47
from django.forms.extras.widgets import SelectDateWidget
48 48
from django.conf import settings
49 49

  
50
from astakos.im.models import (AstakosUser, EmailChange, AstakosGroup, Invitation,
50
from astakos.im.models import (
51
    AstakosUser, EmailChange, AstakosGroup, Invitation,
51 52
    Membership, GroupKind, get_latest_terms
52 53
)
53 54
from astakos.im.settings import (INVITATIONS_PER_LEVEL, BASEURL, SITENAME,
54
    RECAPTCHA_PRIVATE_KEY, RECAPTCHA_ENABLED, DEFAULT_CONTACT_EMAIL,
55
    LOGGING_LEVEL
56
)
55
                                 RECAPTCHA_PRIVATE_KEY, RECAPTCHA_ENABLED, DEFAULT_CONTACT_EMAIL,
56
                                 LOGGING_LEVEL
57
                                 )
57 58
from astakos.im.widgets import DummyWidget, RecaptchaWidget
58 59
from astakos.im.functions import send_change_email
59 60

  
......
66 67

  
67 68
logger = logging.getLogger(__name__)
68 69

  
70

  
69 71
class LocalUserCreationForm(UserCreationForm):
70 72
    """
71 73
    Extends the built in UserCreationForm in several ways:
......
75 77
    * User created is not active.
76 78
    """
77 79
    recaptcha_challenge_field = forms.CharField(widget=DummyWidget)
78
    recaptcha_response_field = forms.CharField(widget=RecaptchaWidget, label='')
80
    recaptcha_response_field = forms.CharField(
81
        widget=RecaptchaWidget, label='')
79 82

  
80 83
    class Meta:
81 84
        model = AstakosUser
82
        fields = ("email", "first_name", "last_name", "has_signed_terms", "has_signed_terms")
85
        fields = ("email", "first_name", "last_name",
86
                  "has_signed_terms", "has_signed_terms")
83 87

  
84 88
    def __init__(self, *args, **kwargs):
85 89
        """
......
90 94
            kwargs.pop('request')
91 95
            self.ip = request.META.get('REMOTE_ADDR',
92 96
                                       request.META.get('HTTP_X_REAL_IP', None))
93
        
97

  
94 98
        super(LocalUserCreationForm, self).__init__(*args, **kwargs)
95 99
        self.fields.keyOrder = ['email', 'first_name', 'last_name',
96 100
                                'password1', 'password2']
97 101

  
98 102
        if RECAPTCHA_ENABLED:
99 103
            self.fields.keyOrder.extend(['recaptcha_challenge_field',
100
                                         'recaptcha_response_field',])
104
                                         'recaptcha_response_field', ])
101 105
        if get_latest_terms():
102 106
            self.fields.keyOrder.append('has_signed_terms')
103
            
107

  
104 108
        if 'has_signed_terms' in self.fields:
105 109
            # Overriding field label since we need to apply a link
106 110
            # to the terms within the label
107 111
            terms_link_html = '<a href="%s" target="_blank">%s</a>' \
108
                    % (reverse('latest_terms'), _("the terms"))
112
                % (reverse('latest_terms'), _("the terms"))
109 113
            self.fields['has_signed_terms'].label = \
110
                    mark_safe("I agree with %s" % terms_link_html)
114
                mark_safe("I agree with %s" % terms_link_html)
111 115

  
112 116
    def clean_email(self):
113 117
        email = self.cleaned_data['email']
......
138 142
        rrf = self.cleaned_data['recaptcha_response_field']
139 143
        check = captcha.submit(rcf, rrf, RECAPTCHA_PRIVATE_KEY, self.ip)
140 144
        if not check.is_valid:
141
            raise forms.ValidationError(_('You have not entered the correct words'))
145
            raise forms.ValidationError(
146
                _('You have not entered the correct words'))
142 147

  
143 148
    def save(self, commit=True):
144 149
        """
......
152 157
            logger.log(LOGGING_LEVEL, 'Created user %s' % user.email)
153 158
        return user
154 159

  
160

  
155 161
class InvitedLocalUserCreationForm(LocalUserCreationForm):
156 162
    """
157 163
    Extends the LocalUserCreationForm: email is readonly.
......
170 176
        ro = ('email', 'username',)
171 177
        for f in ro:
172 178
            self.fields[f].widget.attrs['readonly'] = True
173
        
174 179

  
175 180
    def save(self, commit=True):
176 181
        user = super(InvitedLocalUserCreationForm, self).save(commit=False)
......
182 187
            user.save()
183 188
        return user
184 189

  
190

  
185 191
class ThirdPartyUserCreationForm(forms.ModelForm):
186 192
    class Meta:
187 193
        model = AstakosUser
188
        fields = ("email", "first_name", "last_name", "third_party_identifier", "has_signed_terms")
189
    
194
        fields = ("email", "first_name", "last_name",
195
                  "third_party_identifier", "has_signed_terms")
196

  
190 197
    def __init__(self, *args, **kwargs):
191 198
        """
192 199
        Changes the order of fields, and removes the username field.
......
195 202
        if self.request:
196 203
            kwargs.pop('request')
197 204
        super(ThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
198
        self.fields.keyOrder = ['email', 'first_name', 'last_name', 'third_party_identifier']
205
        self.fields.keyOrder = ['email', 'first_name', 'last_name',
206
                                'third_party_identifier']
199 207
        if get_latest_terms():
200 208
            self.fields.keyOrder.append('has_signed_terms')
201 209
        #set readonly form fields
202 210
        ro = ["third_party_identifier"]
203 211
        for f in ro:
204 212
            self.fields[f].widget.attrs['readonly'] = True
205
        
213

  
206 214
        if 'has_signed_terms' in self.fields:
207 215
            # Overriding field label since we need to apply a link
208 216
            # to the terms within the label
209 217
            terms_link_html = '<a href="%s" target="_blank">%s</a>' \
210
                    % (reverse('latest_terms'), _("the terms"))
218
                % (reverse('latest_terms'), _("the terms"))
211 219
            self.fields['has_signed_terms'].label = \
212
                    mark_safe("I agree with %s" % terms_link_html)
213
    
220
                mark_safe("I agree with %s" % terms_link_html)
221

  
214 222
    def clean_email(self):
215 223
        email = self.cleaned_data['email']
216 224
        if not email:
217 225
            raise forms.ValidationError(_("This field is required"))
218 226
        return email
219
    
227

  
220 228
    def clean_has_signed_terms(self):
221 229
        has_signed_terms = self.cleaned_data['has_signed_terms']
222 230
        if not has_signed_terms:
223 231
            raise forms.ValidationError(_('You have to agree with the terms'))
224 232
        return has_signed_terms
225
    
233

  
226 234
    def save(self, commit=True):
227 235
        user = super(ThirdPartyUserCreationForm, self).save(commit=False)
228 236
        user.set_unusable_password()
......
233 241
            logger.log(LOGGING_LEVEL, 'Created user %s' % user.email)
234 242
        return user
235 243

  
244

  
236 245
class InvitedThirdPartyUserCreationForm(ThirdPartyUserCreationForm):
237 246
    """
238 247
    Extends the ThirdPartyUserCreationForm: email is readonly.
......
241 250
        """
242 251
        Changes the order of fields, and removes the username field.
243 252
        """
244
        super(InvitedThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
253
        super(
254
            InvitedThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
245 255

  
246 256
        #set readonly form fields
247 257
        ro = ('email',)
248 258
        for f in ro:
249 259
            self.fields[f].widget.attrs['readonly'] = True
250
    
260

  
251 261
    def save(self, commit=True):
252
        user = super(InvitedThirdPartyUserCreationForm, self).save(commit=False)
262
        user = super(
263
            InvitedThirdPartyUserCreationForm, self).save(commit=False)
253 264
        level = user.invitation.inviter.level + 1
254 265
        user.level = level
255 266
        user.invitations = INVITATIONS_PER_LEVEL.get(level, 0)
......
258 269
            user.save()
259 270
        return user
260 271

  
272

  
261 273
class ShibbolethUserCreationForm(ThirdPartyUserCreationForm):
262
    additional_email = forms.CharField(widget=forms.HiddenInput(), label='', required = False)
263
    
274
    additional_email = forms.CharField(
275
        widget=forms.HiddenInput(), label='', required=False)
276

  
264 277
    def __init__(self, *args, **kwargs):
265 278
        super(ShibbolethUserCreationForm, self).__init__(*args, **kwargs)
266 279
        self.fields.keyOrder.append('additional_email')
267 280
        # copy email value to additional_mail in case user will change it
268 281
        name = 'email'
269 282
        field = self.fields[name]
270
        self.initial['additional_email'] = self.initial.get(name, field.initial)
271
    
283
        self.initial['additional_email'] = self.initial.get(name,
284
                                                            field.initial)
285

  
272 286
    def clean_email(self):
273 287
        email = self.cleaned_data['email']
274
        for user in AstakosUser.objects.filter(email = email):
288
        for user in AstakosUser.objects.filter(email=email):
275 289
            if user.provider == 'shibboleth':
276 290
                raise forms.ValidationError(_("This email is already associated with another shibboleth account."))
277 291
            elif not user.is_active:
......
280 294
        super(ShibbolethUserCreationForm, self).clean_email()
281 295
        return email
282 296

  
297

  
283 298
class InvitedShibbolethUserCreationForm(ShibbolethUserCreationForm, InvitedThirdPartyUserCreationForm):
284 299
    pass
285
    
300

  
301

  
286 302
class LoginForm(AuthenticationForm):
287 303
    username = forms.EmailField(label=_("Email"))
288 304
    recaptcha_challenge_field = forms.CharField(widget=DummyWidget)
289
    recaptcha_response_field = forms.CharField(widget=RecaptchaWidget, label='')
290
    
305
    recaptcha_response_field = forms.CharField(
306
        widget=RecaptchaWidget, label='')
307

  
291 308
    def __init__(self, *args, **kwargs):
292 309
        was_limited = kwargs.get('was_limited', False)
293 310
        request = kwargs.get('request', None)
294 311
        if request:
295 312
            self.ip = request.META.get('REMOTE_ADDR',
296 313
                                       request.META.get('HTTP_X_REAL_IP', None))
297
        
314

  
298 315
        t = ('request', 'was_limited')
299 316
        for elem in t:
300 317
            if elem in kwargs.keys():
301 318
                kwargs.pop(elem)
302 319
        super(LoginForm, self).__init__(*args, **kwargs)
303
        
320

  
304 321
        self.fields.keyOrder = ['username', 'password']
305 322
        if was_limited and RECAPTCHA_ENABLED:
306 323
            self.fields.keyOrder.extend(['recaptcha_challenge_field',
307
                                         'recaptcha_response_field',])
308
    
324
                                         'recaptcha_response_field', ])
325

  
309 326
    def clean_recaptcha_response_field(self):
310 327
        if 'recaptcha_challenge_field' in self.cleaned_data:
311 328
            self.validate_captcha()
......
321 338
        rrf = self.cleaned_data['recaptcha_response_field']
322 339
        check = captcha.submit(rcf, rrf, RECAPTCHA_PRIVATE_KEY, self.ip)
323 340
        if not check.is_valid:
324
            raise forms.ValidationError(_('You have not entered the correct words'))
325
    
341
            raise forms.ValidationError(
342
                _('You have not entered the correct words'))
343

  
326 344
    def clean(self):
327 345
        super(LoginForm, self).clean()
328 346
        if self.user_cache and self.user_cache.provider not in ('local', ''):
329 347
            raise forms.ValidationError(_('Local login is not the current authentication method for this account.'))
330 348
        return self.cleaned_data
331 349

  
350

  
332 351
class ProfileForm(forms.ModelForm):
333 352
    """
334 353
    Subclass of ``ModelForm`` for permiting user to edit his/her profile.
......
341 360

  
342 361
    class Meta:
343 362
        model = AstakosUser
344
        fields = ('email', 'first_name', 'last_name', 'auth_token', 'auth_token_expires')
363
        fields = ('email', 'first_name', 'last_name', 'auth_token',
364
                  'auth_token_expires')
345 365

  
346 366
    def __init__(self, *args, **kwargs):
347 367
        super(ProfileForm, self).__init__(*args, **kwargs)
......
360 380
            user.save()
361 381
        return user
362 382

  
383

  
363 384
class FeedbackForm(forms.Form):
364 385
    """
365 386
    Form for writing feedback.
......
368 389
    feedback_data = forms.CharField(widget=forms.HiddenInput(), label='',
369 390
                                    required=False)
370 391

  
392

  
371 393
class SendInvitationForm(forms.Form):
372 394
    """
373 395
    Form for sending an invitations
374 396
    """
375 397

  
376
    email = forms.EmailField(required = True, label = 'Email address')
377
    first_name = forms.EmailField(label = 'First name')
378
    last_name = forms.EmailField(label = 'Last name')
398
    email = forms.EmailField(required=True, label='Email address')
399
    first_name = forms.EmailField(label='First name')
400
    last_name = forms.EmailField(label='Last name')
401

  
379 402

  
380 403
class ExtendedPasswordResetForm(PasswordResetForm):
381 404
    """
......
390 413
        try:
391 414
            user = AstakosUser.objects.get(email=email, is_active=True)
392 415
            if not user.has_usable_password():
393
                raise forms.ValidationError(_("This account has not a usable password."))
416
                raise forms.ValidationError(
417
                    _("This account has not a usable password."))
394 418
        except AstakosUser.DoesNotExist:
395 419
            raise forms.ValidationError(_('That e-mail address doesn\'t have an associated user account. Are you sure you\'ve registered?'))
396 420
        return email
397
    
398
    def save(self, domain_override=None, email_template_name='registration/password_reset_email.html',
399
             use_https=False, token_generator=default_token_generator, request=None):
421

  
422
    def save(
423
        self, domain_override=None, email_template_name='registration/password_reset_email.html',
424
            use_https=False, token_generator=default_token_generator, request=None):
400 425
        """
401 426
        Generates a one-use only link for resetting password and sends to the user.
402 427
        """
403 428
        for user in self.users_cache:
404 429
            url = reverse('django.contrib.auth.views.password_reset_confirm',
405
                kwargs={'uidb36':int_to_base36(user.id),
406
                    'token':token_generator.make_token(user)
407
                }
408
            )
430
                          kwargs={'uidb36': int_to_base36(user.id),
431
                                  'token': token_generator.make_token(user)
432
                                  }
433
                          )
409 434
            url = urljoin(BASEURL, url)
410 435
            t = loader.get_template(email_template_name)
411 436
            c = {
......
418 443
            }
419 444
            from_email = settings.SERVER_EMAIL
420 445
            send_mail(_("Password reset on %s alpha2 testing") % SITENAME,
421
                t.render(Context(c)), from_email, [user.email])
446
                      t.render(Context(c)), from_email, [user.email])
447

  
422 448

  
423 449
class EmailChangeForm(forms.ModelForm):
424 450
    class Meta:
425 451
        model = EmailChange
426 452
        fields = ('new_email_address',)
427
            
453

  
428 454
    def clean_new_email_address(self):
429 455
        addr = self.cleaned_data['new_email_address']
430 456
        if AstakosUser.objects.filter(email__iexact=addr):
431 457
            raise forms.ValidationError(_(u'This email address is already in use. Please supply a different email address.'))
432 458
        return addr
433
    
459

  
434 460
    def save(self, email_template_name, request, commit=True):
435 461
        ec = super(EmailChangeForm, self).save(commit=False)
436 462
        ec.user = request.user
437
        activation_key = hashlib.sha1(str(random()) + smart_str(ec.new_email_address))
438
        ec.activation_key=activation_key.hexdigest()
463
        activation_key = hashlib.sha1(
464
            str(random()) + smart_str(ec.new_email_address))
465
        ec.activation_key = activation_key.hexdigest()
439 466
        if commit:
440 467
            ec.save()
441 468
        send_change_email(ec, request, email_template_name=email_template_name)
442 469

  
470

  
443 471
class SignApprovalTermsForm(forms.ModelForm):
444 472
    class Meta:
445 473
        model = AstakosUser
......
454 482
            raise forms.ValidationError(_('You have to agree with the terms'))
455 483
        return has_signed_terms
456 484

  
485

  
457 486
class InvitationForm(forms.ModelForm):
458 487
    username = forms.EmailField(label=_("Email"))
459
    
488

  
460 489
    def __init__(self, *args, **kwargs):
461 490
        super(InvitationForm, self).__init__(*args, **kwargs)
462
    
491

  
463 492
    class Meta:
464 493
        model = Invitation
465 494
        fields = ('username', 'realname')
466
    
495

  
467 496
    def clean_username(self):
468 497
        username = self.cleaned_data['username']
469 498
        try:
470
            Invitation.objects.get(username = username)
471
            raise forms.ValidationError(_('There is already invitation for this email.'))
499
            Invitation.objects.get(username=username)
500
            raise forms.ValidationError(
501
                _('There is already invitation for this email.'))
472 502
        except Invitation.DoesNotExist:
473 503
            pass
474 504
        return username
475 505

  
506

  
476 507
class ExtendedPasswordChangeForm(PasswordChangeForm):
477 508
    """
478 509
    Extends PasswordChangeForm by enabling user
479 510
    to optionally renew also the token.
480 511
    """
481 512
    renew = forms.BooleanField(label='Renew token', required=False)
482
    
513

  
483 514
    def __init__(self, user, *args, **kwargs):
484 515
        super(ExtendedPasswordChangeForm, self).__init__(user, *args, **kwargs)
485
    
516

  
486 517
    def save(self, commit=True):
487 518
        user = super(ExtendedPasswordChangeForm, self).save(commit=False)
488 519
        if self.cleaned_data.get('renew'):
......
491 522
            user.save()
492 523
        return user
493 524

  
525

  
494 526
class AstakosGroupCreationForm(forms.ModelForm):
495 527
#     issue_date = forms.DateField(widget=SelectDateWidget())
496 528
#     expiration_date = forms.DateField(widget=SelectDateWidget())
......
508 540
    
509 541
    class Meta:
510 542
        model = AstakosGroup
511
    
543

  
512 544
    def __init__(self, *args, **kwargs):
513 545
        try:
514 546
            resources = kwargs.pop('resources')
......
524 556
                required=False,
525 557
                help_text=_('Leave it blank for no additional quota.')
526 558
            )
527
        
559

  
528 560
    def resources(self):
529 561
        for name, value in self.cleaned_data.items():
530 562
            prefix, delimiter, suffix = name.partition('resource_')
......
534 566
                    continue
535 567
                yield (suffix, value)
536 568

  
569

  
537 570
class AstakosGroupSearchForm(forms.Form):
538
    q = forms.CharField(max_length=200, label='Search group')
571
    q = forms.CharField(max_length=200, label='Search group')

Also available in: Unified diff