utils.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. from datetime import timedelta
  2. import bleach
  3. from markdown import Markdown
  4. from unidecode import unidecode
  5. from django.http import Http404
  6. from django.core.urlresolvers import resolve, reverse
  7. from django.template.defaultfilters import slugify as django_slugify
  8. from django.utils.translation import ugettext_lazy as _, ungettext_lazy
  9. def slugify(string):
  10. string = unicode(string)
  11. string = unidecode(string)
  12. return django_slugify(string.replace('_', ' '))
  13. """
  14. Return path utility
  15. """
  16. def clean_return_path(request):
  17. post_return_path = _get_return_path_from_post(request)
  18. if not post_return_path:
  19. return _get_return_path_from_referer(request)
  20. else:
  21. return post_return_path
  22. def _get_return_path_from_post(request):
  23. return_path = request.POST.get('return_path')
  24. try:
  25. if not return_path:
  26. raise ValueError()
  27. if not return_path.startswith('/'):
  28. raise ValueError()
  29. resolve(return_path)
  30. return return_path
  31. except (Http404, ValueError):
  32. return None
  33. def _get_return_path_from_referer(request):
  34. referer = request.META.get('HTTP_REFERER')
  35. try:
  36. if not referer:
  37. raise ValueError()
  38. if not referer.startswith(request.scheme):
  39. raise ValueError()
  40. referer = referer[len(request.scheme) + 3:]
  41. if not referer.startswith(request.META['HTTP_HOST']):
  42. raise ValueError()
  43. referer = referer[len(request.META['HTTP_HOST']):]
  44. if not referer.startswith('/'):
  45. raise ValueError()
  46. resolve(referer)
  47. return referer
  48. except (Http404, KeyError, ValueError):
  49. return None
  50. """
  51. Utils for resolving requests destination
  52. """
  53. def _is_request_path_under_misago(request):
  54. # We are assuming that forum_index link is root of all Misago links
  55. forum_index = reverse('misago:index')
  56. path_info = request.path_info
  57. if len(forum_index) > len(path_info):
  58. return False
  59. return path_info[:len(forum_index)] == forum_index
  60. def is_request_to_misago(request):
  61. try:
  62. return request._request_to_misago
  63. except AttributeError:
  64. request._request_to_misago = _is_request_path_under_misago(request)
  65. return request._request_to_misago
  66. """
  67. Utility that humanizes time amount.
  68. Expects number of seconds as first argument
  69. """
  70. def time_amount(value):
  71. delta = timedelta(seconds=value)
  72. units_dict = {
  73. 'd': delta.days,
  74. 'h': 0,
  75. 'm': 0,
  76. 's': delta.seconds,
  77. }
  78. if units_dict['s'] >= 3600:
  79. units_dict['h'] = units_dict['s'] / 3600
  80. units_dict['s'] -= units_dict['h'] * 3600
  81. if units_dict['s'] >= 60:
  82. units_dict['m'] = units_dict['s'] / 60
  83. units_dict['s'] -= units_dict['m'] * 60
  84. precisions = []
  85. if units_dict['d']:
  86. string = ungettext_lazy(
  87. '%(days)s day', '%(days)s days', units_dict['d'])
  88. precisions.append(string % {'days': units_dict['d']})
  89. if units_dict['h']:
  90. string = ungettext_lazy(
  91. '%(hours)s hour', '%(hours)s hours', units_dict['h'])
  92. precisions.append(string % {'hours': units_dict['h']})
  93. if units_dict['m']:
  94. string = ungettext_lazy(
  95. '%(minutes)s minute', '%(minutes)s minutes', units_dict['m'])
  96. precisions.append(string % {'minutes': units_dict['m']})
  97. if units_dict['s']:
  98. string = ungettext_lazy(
  99. '%(seconds)s second', '%(seconds)s seconds', units_dict['s'])
  100. precisions.append(string % {'seconds': units_dict['s']})
  101. if not precisions:
  102. precisions.append(_("0 seconds"))
  103. if len(precisions) == 1:
  104. return precisions[0]
  105. else:
  106. formats = {
  107. 'first_part': ', '.join(precisions[:-1]),
  108. 'and_part': precisions[-1],
  109. }
  110. return _("%(first_part)s and %(and_part)s") % formats
  111. """
  112. MD subset for use for enchancing items descriptions
  113. """
  114. MD_SUBSET_FORBID_SYNTAX = (
  115. # References are evil
  116. 'reference', 'reference', 'image_reference', 'short_reference',
  117. # Blocks are evil too
  118. 'hashheader', 'setextheader', 'code', 'quote', 'hr', 'olist', 'ulist',
  119. )
  120. def subset_markdown(text):
  121. if not text:
  122. return ''
  123. md = Markdown(safe_mode='escape', extensions=['nl2br'])
  124. for key in md.preprocessors.keys():
  125. if key in MD_SUBSET_FORBID_SYNTAX:
  126. del md.preprocessors[key]
  127. for key in md.inlinePatterns.keys():
  128. if key in MD_SUBSET_FORBID_SYNTAX:
  129. del md.inlinePatterns[key]
  130. for key in md.parser.blockprocessors.keys():
  131. if key in MD_SUBSET_FORBID_SYNTAX:
  132. del md.parser.blockprocessors[key]
  133. for key in md.treeprocessors.keys():
  134. if key in MD_SUBSET_FORBID_SYNTAX:
  135. del md.treeprocessors[key]
  136. for key in md.postprocessors.keys():
  137. if key in MD_SUBSET_FORBID_SYNTAX:
  138. del md.postprocessors[key]
  139. return bleach.linkify(md.convert(text))