cerberus_extend.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. '''
  2. @author: olivier.massot, 2018
  3. '''
  4. from datetime import datetime
  5. import locale
  6. import re
  7. import cerberus
  8. from core import gis, gis_
  9. def is_french_date(field, value, error):
  10. try:
  11. datetime.strptime(value, '%d/%m/%Y')
  12. except:
  13. error(field, 'Doit être une date au format jj/mm/aaaa: {}'.format(value))
  14. def is_modern_french_date(field, value, error):
  15. try:
  16. d = datetime.strptime(value, '%d/%m/%Y')
  17. if not d.year >= 2000:
  18. error(field, "La date ne peut pas être antérieure à l'an 2000: {}".format(value))
  19. except:
  20. error(field, 'Doit être une date au format jj/mm/aaaa: {}'.format(value))
  21. def is_int(field, value, error):
  22. try:
  23. if float(value) != int(value):
  24. error(field, 'Doit être un nombre entier: {}'.format(value))
  25. except (TypeError, ValueError):
  26. error(field, 'Doit être un nombre entier: {}'.format(value))
  27. def is_multi_int(field, value, error):
  28. if not re.match(r"\d(\s?-\s?\d)*", str(value)):
  29. error(field, 'Doit être un nombre entier, ou une liste de nombres séparés par des tirets: {}'.format(value))
  30. def is_float(field, value, error):
  31. try:
  32. value = locale.atof(str(value))
  33. if value != float(value):
  34. error(field, 'Doit être un nombre décimal ({})'.format(value))
  35. except ValueError:
  36. error(field, 'Doit être un nombre décimal ({})'.format(value))
  37. # Ref: http://docs.python-cerberus.org/en/stable/api.html#error-codes
  38. class ExtendedValidator(cerberus.validator.Validator):
  39. def __init__(self, *args, **kwargs):
  40. super(ExtendedValidator, self).__init__(*args, **kwargs)
  41. # Rends tous les champs requis par défaut, à moins que 'required' ait été défini dans le schéma
  42. for field in self.schema:
  43. if not 'required' in self.schema[field]:
  44. self.schema[field]['required'] = True
  45. def _validate_contains_any_of(self, iterable, field, value):
  46. """ Controle que la chaine contient l'une des substring contenue dans l'iterable
  47. The rule's arguments are validated against this schema:
  48. {'type': 'list'}
  49. """
  50. if not re.search(r".*{}.*".format("|".join(iterable)), value):
  51. self._error(field, "Doit contenir un de ces éléments: {} ('{}')".format(", ".join(iterable), value))
  52. def _validate_multiallowed(self, allowed, field, value):
  53. """ Comme 'allowed', mais autorise plusieurs valeurs séparées par un '-'
  54. The rule's arguments are validated against this schema:
  55. {'type': 'list'}
  56. """
  57. for item in re.split("\s?-\s?", value or ""):
  58. if not item in allowed:
  59. if item == '':
  60. self._error(field, "Le champs doit être renseigné")
  61. else:
  62. self._error(field, "Valeur non-autorisée: {}".format(item))
  63. class GeoValidator(ExtendedValidator):
  64. def _validate_inside_box(self, bounding_box, field, value):
  65. """ Contrôle l'inclusion de la bounding box de l'entité dans la box donneé
  66. The rule's arguments are validated against this schema:
  67. {'type': 'list'}
  68. """
  69. # geom_type, bounding_box = geom
  70. #
  71. # if value.geom_type != geom_type:
  72. # self._error(field, "Le type de géométrie est {} (attendu: {})".format(value.geom_name, gis_.GEOM_NAMES[geom_type]))
  73. xmin, ymin, xmax, ymax = bounding_box
  74. try:
  75. x1, y1, x2, y2 = value.bounding_box
  76. if any(x < xmin or x > xmax for x in (x1, x2)) or \
  77. any(y < ymin or y > ymax for y in (y1, y2)):
  78. self._error(field, "Certaines coordonnées hors de l'emprise autorisée")
  79. except AttributeError:
  80. pass
  81. def _translate_messages(message):
  82. message = message.replace("string", "texte")
  83. message = message.replace("integer", "nombre entier")
  84. message = message.replace("float", "nombre décimal")
  85. message = message.replace("boolean", "booléen")
  86. return message
  87. class CerberusErrorHandler(cerberus.errors.BasicErrorHandler):
  88. messages = {0x00: "{0}",
  89. 0x01: "Le document est manquant",
  90. 0x02: "Le champs est obligatoire",
  91. 0x03: "Champs inconnu",
  92. 0x04: "Le champs '{0}' est obligatoire",
  93. 0x05: "Dépends de ces valeurs: {constraint}",
  94. 0x06: "{0} ne doit pas être présent avec '{field}'",
  95. 0x21: "'{0}' is not a document, must be a dict",
  96. 0x22: "Le champs doit être renseigné",
  97. 0x23: "Les valeurs NULL ne sont pas autorisées",
  98. 0x24: "Doit être du type {constraint}: {value}",
  99. 0x25: "Doit être de type 'dictionnaire': {value}",
  100. 0x26: "La longueur de la liste doit être de {constraint}, elle est de {0}",
  101. 0x27: "La longueur minimum du champs est de {constraint}: {value}",
  102. 0x28: "Trop long, la longueur max. du champs est de {constraint}: {value}",
  103. 0x41: "La valeur n'est pas au bon format ('{constraint}')",
  104. 0x42: "La valeur minimum autorisée est {constraint}",
  105. 0x43: "La valeur maximum autorisée est {constraint}",
  106. 0x44: "Valeur non-autorisée: {value}",
  107. 0x45: "Valeurs non-autorisées: {0}",
  108. 0x46: "Valeur non-autorisée: {value}",
  109. 0x47: "Valeurs non-autorisées: {0}",
  110. 0x61: "Le champs '{field}' ne peut pas être converti: {0}",
  111. 0x62: "Le champs '{field}' ne peut pas être renommé: {0}",
  112. 0x63: "Le champs est en lecture seule",
  113. 0x64: "La valeur par défaut du champs '{field}' ne peut pas être appliquée: {0}",
  114. 0x81: "mapping doesn't validate subschema: {0}",
  115. 0x82: "one or more sequence-items don't validate: {0}",
  116. 0x83: "one or more keys of a mapping don't validate: {0}",
  117. 0x84: "one or more values in a mapping don't validate: {0}",
  118. 0x85: "one or more sequence-items don't validate: {0}",
  119. 0x91: "one or more definitions validate",
  120. 0x92: "none or more than one rule validate",
  121. 0x93: "no definitions validate",
  122. 0x94: "one or more definitions don't validate"
  123. }