root/plesonet_captcha/trunk/forms.py

Revision 1, 3.2 KB (checked in by 235, 4 years ago)

re-comminting after curios incident with same filenames in upper and lower case`

Line 
1# -*- coding:UTF-8 -*-
2# Copyright (c) 2007 Brandon Low
3# Licensed under the GPL v2
4from django import forms
5from django.forms.util import ValidationError #, flatatt
6from models import Captcha
7from settings import BASE_URL, MIN_LENGTH, MAX_LENGTH
8from util import get_string
9from django.utils.translation import ugettext_lazy as _
10
11class CaptchaWidget(forms.TextInput):
12
13    def __init__(self, captcha=None, *args, **kwargs):
14        self.captcha_id = captcha.id
15        super(CaptchaWidget, self).__init__(*args, **kwargs)
16
17    def render(self, *args, **kwargs):
18        value = super(CaptchaWidget, self).render(*args, **kwargs)
19
20        # I'd rather have this in the label, but they aren't per-instance
21        img_src = "/".join([BASE_URL, str(self.captcha_id),""])
22        image = "<img src='%s' alt='Captcha' /> <br/>" % img_src
23        return " ".join([image, value])
24   
25class CaptchaField(forms.CharField):
26
27    def __init__(self, captcha=None, *args, **kwargs):
28        self.captcha = captcha
29        self.widget = CaptchaWidget(captcha=captcha)
30        # CharField takes care of setting the max length onto the widget
31        super(CaptchaField, self).__init__(min_length=MIN_LENGTH,
32                max_length=MAX_LENGTH, label=_("Captcha"), *args, **kwargs)
33
34    def clean(self, value):
35        value = super(CaptchaField, self).clean(value)
36        if not self.captcha.text.lower() == value.lower():
37            raise ValidationError(u'Enter the string exactly as shown')
38        return value
39
40class CaptchaForm(forms.Form):
41    def __init__(self, *args, **kwargs):
42        super(CaptchaForm, self).__init__(*args, **kwargs)
43
44        # The super.__init__ call does not actually set the data or initial
45        # onto the fields/widgets, so we just need the captcha_id field and
46        # widget to exist before self.get_captcha() is called
47        self.fields['captcha_id'] = forms.IntegerField(label=_('ZZZZZZ'))
48        self.fields['captcha_id'].widget = forms.HiddenInput()
49
50        if not self.is_bound:
51            # New form, new captcha
52            c = Captcha(text=get_string())
53            c.save()
54            # Ensure that the hidden field is properly populated
55            self.initial['captcha_id'] = c.id
56        else:
57            c = self.get_captcha()
58
59        self.fields['captcha'] = CaptchaField(captcha=c)
60
61    # Only called on a bound form
62    def get_captcha(self):
63        # Somewhat hacky, but best way I had to get the captcha id
64        f = self.fields['captcha_id']
65        w = f.widget
66        value = w.value_from_datadict(self.data, None, self.add_prefix('captcha_id'))
67        captcha_id = f.clean(value)
68
69        try:
70            # Always clean expired captchas before getting one for validation
71            Captcha.clean_expired()
72            return Captcha.objects.get(pk=captcha_id)
73        except Captcha.DoesNotExist:
74            # The original captcha expired, make a new one for revalidation
75            c = Captcha(id=captcha_id,text=get_string())
76            c.save()
77            return c
78
79
80    def full_clean(self):
81        super(CaptchaForm, self).full_clean()
82
83        # Once the form has validated, the captcha is 'used up'
84        if self.is_valid():
85            self.fields['captcha'].captcha.delete()
Note: See TracBrowser for help on using the browser.