validators.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. # -*- coding: utf-8 -*-
  2. import unicodedata
  3. import binascii
  4. from django.core.exceptions import ValidationError
  5. from django.utils.deconstruct import deconstructible
  6. from django.utils.encoding import force_str
  7. from django.utils.translation import gettext_lazy as _
  8. @deconstructible
  9. class NoControlCharactersValidator:
  10. message = _("Control Characters like new lines or tabs are not allowed.")
  11. code = "no_control_characters"
  12. whitelist = None
  13. def __init__(self, message=None, code=None, whitelist=None):
  14. if message:
  15. self.message = message
  16. if code:
  17. self.code = code
  18. if whitelist:
  19. self.whitelist = whitelist
  20. def __call__(self, value):
  21. value = force_str(value)
  22. whitelist = self.whitelist
  23. category = unicodedata.category
  24. for character in value:
  25. if whitelist and character in whitelist:
  26. continue
  27. if category(character)[0] == "C":
  28. params = {'value': value, 'whitelist': whitelist}
  29. raise ValidationError(self.message, code=self.code, params=params)
  30. def __eq__(self, other):
  31. return (
  32. isinstance(other, NoControlCharactersValidator) and
  33. (self.whitelist == other.whitelist) and
  34. (self.message == other.message) and
  35. (self.code == other.code)
  36. )
  37. @deconstructible
  38. class NoWhitespaceValidator:
  39. message = _("Leading and Trailing whitespaces are not allowed.")
  40. code = "no_whitespace"
  41. def __init__(self, message=None, code=None, whitelist=None):
  42. if message:
  43. self.message = message
  44. if code:
  45. self.code = code
  46. def __call__(self, value):
  47. value = force_str(value)
  48. if value != value.strip():
  49. params = {'value': value}
  50. raise ValidationError(self.message, code=self.code, params=params)
  51. def __eq__(self, other):
  52. return (
  53. isinstance(other, NoWhitespaceValidator) and
  54. (self.message == other.message) and
  55. (self.code == other.code)
  56. )
  57. @deconstructible
  58. class HexValidator:
  59. messages = {
  60. 'invalid': _("Only a hex string is allowed."),
  61. 'length': _("Invalid length. Must be %(length)d characters."),
  62. 'min_length': _("Ensure that there are more than %(min)s characters."),
  63. 'max_length': _("Ensure that there are no more than %(max)s characters."),
  64. }
  65. code = "hex_only"
  66. def __init__(self, length=None, min_length=None, max_length=None, message=None, code=None):
  67. self.length = length
  68. self.min_length = min_length
  69. self.max_length = max_length
  70. if message:
  71. self.message = message
  72. if code:
  73. self.code = code
  74. def __call__(self, value):
  75. value = force_str(value)
  76. if self.length and len(value) != self.length:
  77. raise ValidationError(self.messages['length'], code='hex_only_length', params={'length': self.length})
  78. if self.min_length and len(value) < self.min_length:
  79. raise ValidationError(self.messages['min_length'], code='hex_only_min_length', params={'min': self.min_length})
  80. if self.max_length and len(value) < self.max_length:
  81. raise ValidationError(self.messages['max_length'], code='hex_only_max_length', params={'max': self.max_length})
  82. try:
  83. binascii.unhexlify(value)
  84. except (TypeError, binascii.Error):
  85. raise ValidationError(self.messages['invalid'], code='hex_only')
  86. def __eq__(self, other):
  87. return (
  88. isinstance(other, HexValidator) and
  89. (self.message == other.message) and
  90. (self.code == other.code)
  91. )