__init__.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. from django import forms
  2. from django.utils.translation import ugettext_lazy as _
  3. from misago.forms.layouts import *
  4. from misago.security.models import QATest
  5. from recaptcha.client.captcha import submit as recaptcha_submit
  6. class Form(forms.Form):
  7. """
  8. Custom form implementation extending Django Forms functionality
  9. """
  10. validate_repeats = []
  11. repeats_errors = []
  12. dont_strip = []
  13. allow_nl = []
  14. error_source = None
  15. def __init__(self, data=None, request=None, *args, **kwargs):
  16. self.request = request
  17. # Kill captcha fields
  18. try:
  19. if self.request.settings['bots_registration'] != 'recaptcha' or self.request.session.get('captcha_passed'):
  20. del self.base_fields['recaptcha']
  21. except KeyError:
  22. pass
  23. try:
  24. if self.request.settings['bots_registration'] != 'qa' or self.request.session.get('captcha_passed'):
  25. del self.base_fields['captcha_qa']
  26. else:
  27. # Make sure we have any questions loaded
  28. self.base_fields['captcha_qa'].label = self.request.settings['qa_test']
  29. self.base_fields['captcha_qa'].help_text = self.request.session['qa_test_help']
  30. except KeyError:
  31. pass
  32. # Extract request from first argument
  33. if data != None:
  34. # Clean bad data
  35. data = self._strip_badchars(data.copy())
  36. super(Form, self).__init__(data, *args, **kwargs)
  37. else:
  38. super(Form, self).__init__(*args, **kwargs)
  39. def _strip_badchars(self, data):
  40. """
  41. Trim inputs and strip newlines
  42. """
  43. for key, field in self.base_fields.iteritems():
  44. try:
  45. if field.__class__.__name__ not in ['DateField', 'DateTimeField']:
  46. if not key in self.dont_strip:
  47. if field.__class__.__name__ in ['MultipleChoiceField', 'TypedMultipleChoiceField']:
  48. data[key] = [x.strip() for x in data.getlist(key.html_name, [])]
  49. else:
  50. data[key] = data[key.html_name].strip()
  51. if not key in self.allow_nl:
  52. if field.__class__.__name__ in ['MultipleChoiceField', 'TypedMultipleChoiceField']:
  53. data[key] = [x.replace("\n", '') for x in data.getlist(key.html_name, [])]
  54. else:
  55. data[key] = data[key.html_name].replace("\n", '')
  56. except (KeyError, AttributeError):
  57. pass
  58. return data
  59. def clean(self):
  60. """
  61. Clean data, do magic checks and stuff
  62. """
  63. cleaned_data = super(Form, self).clean()
  64. self._check_all()
  65. return cleaned_data
  66. def clean_recaptcha(self):
  67. """
  68. Test reCaptcha, scream if it went wrong
  69. """
  70. response = recaptcha_submit(
  71. self.request.POST.get('recaptcha_challenge_field'),
  72. self.request.POST.get('recaptcha_response_field'),
  73. self.request.settings['recaptcha_private'],
  74. self.request.session.get_ip(self.request)
  75. ).is_valid
  76. if not response:
  77. raise forms.ValidationError(_("Entered words are incorrect. Please try again."))
  78. self.request.session['captcha_passed'] = True
  79. return ''
  80. def clean_captcha_qa(self):
  81. """
  82. Test QA Captcha, scream if it went wrong
  83. """
  84. if not unicode(self.cleaned_data['captcha_qa']).lower() in (name.lower() for name in unicode(self.request.settings['qa_test_answers']).splitlines()):
  85. raise forms.ValidationError(_("The answer you entered is incorrect."))
  86. self.request.session['captcha_passed'] = True
  87. return self.cleaned_data['captcha_qa']
  88. def _check_all(self):
  89. # Check repeated fields
  90. self._check_repeats()
  91. # Check CSRF, we dont allow un-csrf'd forms in Misago
  92. self._check_csrf()
  93. # Check if we have any errors from fields, if we do, we will set fancy form-wide error message
  94. self._check_fields_errors()
  95. def _check_repeats(self):
  96. for index, repeat in enumerate(self.validate_repeats):
  97. # Check empty fields
  98. for field in repeat:
  99. if not self.data[field]:
  100. try:
  101. if len(repeat) == 2:
  102. self.errors['_'.join(repeat)] = [self.repeats_errors[index]['fill_both']]
  103. else:
  104. self.errors['_'.join(repeat)] = [self.repeats_errors[index]['fill_all']]
  105. except (IndexError, KeyError):
  106. if len(repeat) == 2:
  107. self.errors['_'.join(repeat)] = [_("You have to fill in both fields.")]
  108. else:
  109. self.errors['_'.join(repeat)] = [_("You have to fill in all fields.")]
  110. break
  111. else:
  112. # Check different fields
  113. past_field = self.data[repeat[0]]
  114. for field in repeat:
  115. if self.data[field] != past_field:
  116. try:
  117. self.errors['_'.join(repeat)] = [self.repeats_errors[index]['different']]
  118. except (IndexError, KeyError):
  119. self.errors['_'.join(repeat)] = [_("Entered values differ from each other.")]
  120. break
  121. past_field = self.data[field]
  122. def _check_csrf(self):
  123. if not self.request.csrf.request_secure(self.request):
  124. raise forms.ValidationError('invalid_request')
  125. def _check_fields_errors(self):
  126. if self.errors:
  127. if self.error_source and self.error_source in self.errors:
  128. field_error, self.errors[self.error_source] = self.errors[self.error_source][0], []
  129. raise forms.ValidationError(field_error)
  130. raise forms.ValidationError('form_contains_errors')
  131. class YesNoSwitch(forms.CheckboxInput):
  132. """
  133. Custom Yes-No switch as fancier alternative to checkboxes
  134. """
  135. pass