utils.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. from datetime import datetime, timedelta
  2. import six
  3. from unidecode import unidecode
  4. from django.http import Http404
  5. from django.template.defaultfilters import slugify as django_slugify
  6. from django.urls import resolve, reverse
  7. from django.utils import html, timezone
  8. from django.utils.encoding import force_text
  9. from django.utils.translation import ugettext_lazy as _
  10. from django.utils.translation import ungettext_lazy
  11. def slugify(string):
  12. string = six.text_type(string)
  13. string = unidecode(string)
  14. return django_slugify(string.replace('_', ' ').strip())
  15. def format_plaintext_for_html(string):
  16. return html.linebreaks(html.urlize(html.escape(string)))
  17. """
  18. Turn ISO 8601 string into datetime object
  19. """
  20. ISO8601_FORMATS = (
  21. "%Y-%m-%dT%H:%M:%S",
  22. "%Y-%m-%dT%H:%M:%S.%f",
  23. )
  24. def parse_iso8601_string(value):
  25. value = force_text(value, strings_only=True).rstrip('Z')
  26. for format in ISO8601_FORMATS:
  27. try:
  28. parsed_value = datetime.strptime(value, format)
  29. break
  30. except ValueError:
  31. try:
  32. parsed_value = datetime.strptime(value[:-6], format)
  33. break
  34. except ValueError:
  35. pass
  36. else:
  37. raise ValueError('failed to hydrate the %s timestamp' % value)
  38. offset_str = value[-6:]
  39. if offset_str and offset_str[0] in ('-', '+'):
  40. tz_offset = timedelta(hours=int(offset_str[1:3]), minutes=int(offset_str[4:6]))
  41. tz_offset = tz_offset.seconds // 60
  42. if offset_str[0] == '-':
  43. tz_offset *= -1
  44. else:
  45. tz_offset = 0
  46. tz_correction = timezone.get_fixed_timezone(tz_offset)
  47. return timezone.make_aware(parsed_value, tz_correction)
  48. """
  49. Mark request as having sensitive parameters
  50. We can't use decorator because of DRF uses custom HttpRequest
  51. that is incompatibile with Django's decorator
  52. """
  53. def hide_post_parameters(request):
  54. request.sensitive_post_parameters = '__ALL__'
  55. """
  56. Return path utility
  57. """
  58. def clean_return_path(request):
  59. if request.method == 'POST' and 'return_path' in request.POST:
  60. return _get_return_path_from_post(request)
  61. else:
  62. return _get_return_path_from_referer(request)
  63. def _get_return_path_from_post(request):
  64. return_path = request.POST.get('return_path')
  65. try:
  66. if not return_path:
  67. raise ValueError()
  68. if not return_path.startswith('/'):
  69. raise ValueError()
  70. resolve(return_path)
  71. return return_path
  72. except (Http404, ValueError):
  73. return None
  74. def _get_return_path_from_referer(request):
  75. referer = request.META.get('HTTP_REFERER')
  76. try:
  77. if not referer:
  78. raise ValueError()
  79. if not referer.startswith(request.scheme):
  80. raise ValueError()
  81. referer = referer[len(request.scheme) + 3:]
  82. if not referer.startswith(request.META['HTTP_HOST']):
  83. raise ValueError()
  84. referer = referer[len(request.META['HTTP_HOST'].rstrip('/')):]
  85. if not referer.startswith('/'):
  86. raise ValueError()
  87. resolve(referer)
  88. return referer
  89. except (Http404, KeyError, ValueError):
  90. return None
  91. """
  92. Utils for resolving requests destination
  93. """
  94. def _is_request_path_under_misago(request):
  95. # We are assuming that forum_index link is root of all Misago links
  96. forum_index = reverse('misago:index')
  97. path_info = request.path_info
  98. if len(forum_index) > len(path_info):
  99. return False
  100. return path_info[:len(forum_index)] == forum_index
  101. def is_request_to_misago(request):
  102. try:
  103. return request._request_to_misago
  104. except AttributeError:
  105. request._request_to_misago = _is_request_path_under_misago(request)
  106. return request._request_to_misago
  107. def is_referer_local(request):
  108. referer = request.META.get('HTTP_REFERER')
  109. if not referer:
  110. return False
  111. if not referer.startswith(request.scheme):
  112. return False
  113. referer = referer[len(request.scheme) + 3:]
  114. if not referer.startswith(request.META['HTTP_HOST']):
  115. return False
  116. referer = referer[len(request.META['HTTP_HOST'].rstrip('/')):]
  117. if not referer.startswith('/'):
  118. return False
  119. return True