mise-en-production
[auf_framonde.git] / project / cmsplugin_contact_plus / simplemathcaptcha / widgets.py
1 from __future__ import absolute_import
2 from __future__ import unicode_literals
3
4 from django import forms
5 from django.template.defaultfilters import mark_safe
6 from django.utils.translation import ugettext_lazy as _
7
8 from .utils import hash_answer, get_operator, get_numbers, calculate
9
10
11 class MathCaptchaWidget(forms.MultiWidget):
12 def __init__(self, start_int=1, end_int=10, question_tmpl=None,
13 question_class=None, attrs=None):
14 self.start_int, self.end_int = self.verify_numbers(start_int, end_int)
15 self.question_class = question_class or 'captcha-question'
16 self.question_tmpl = (
17 question_tmpl or _('What is %(num1)i %(operator)s %(num2)i? '))
18 self.question_html = None
19 widget_attrs = {'size': '5'}
20 widget_attrs.update(attrs or {})
21 widgets = (
22 # this is the answer input field
23 forms.TextInput(attrs=widget_attrs),
24
25 # this is the hashed answer field to compare to
26 forms.HiddenInput()
27 )
28 super(MathCaptchaWidget, self).__init__(widgets, attrs)
29
30 def decompress(self, value):
31 return [None, None]
32
33 def format_output(self, rendered_widgets):
34 output = super(MathCaptchaWidget, self).format_output(rendered_widgets)
35 output = '%s%s' % (self.question_html, output)
36 return output
37
38 def render(self, name, value, attrs=None):
39 # hash answer and set as the hidden value of form
40 hashed_answer = self.generate_captcha()
41 value = ['', hashed_answer]
42
43 return super(MathCaptchaWidget, self).render(name, value, attrs=attrs)
44
45 def generate_captcha(self):
46 # get operator for calculation
47 operator = get_operator()
48
49 # get integers for calculation
50 x, y = get_numbers(self.start_int, self.end_int, operator)
51
52 # set question to display in output
53 self.set_question(x, y, operator)
54
55 # preform the calculation
56 total = calculate(x, y, operator)
57
58 return hash_answer(total)
59
60 def set_question(self, x, y, operator):
61 # make multiplication operator more human-readable
62 operator_for_label = '×' if operator == '*' else operator
63 question = self.question_tmpl % {
64 'num1': x,
65 'operator': operator_for_label,
66 'num2': y
67 }
68
69 html = '<span class="%s">%s</span>' % (self.question_class, question)
70 self.question_html = mark_safe(html)
71
72 def verify_numbers(self, start_int, end_int):
73 start_int, end_int = int(start_int), int(end_int)
74 if start_int < 0 or end_int < 0:
75 raise Warning('MathCaptchaWidget requires positive integers '
76 'for start_int and end_int.')
77 elif end_int < start_int:
78 raise Warning('MathCaptchaWidget requires end_int be greater '
79 'than start_int.')
80 return start_int, end_int