utils.py 4.1 KB

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