from datetime import datetime, timedelta from django.conf import settings from django.http import Http404 from django.urls import resolve, reverse from django.utils import html, timezone from django.utils.encoding import force_text from django.utils.module_loading import import_string MISAGO_SLUGIFY = getattr(settings, 'MISAGO_SLUGIFY', 'misago.core.slugify.default') slugify = import_string(MISAGO_SLUGIFY) def format_plaintext_for_html(string): return html.linebreaks(html.urlize(html.escape(string))) def encode_json_html(string): return string.replace('<', r'\u003C') ISO8601_FORMATS = ("%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M:%S.%f", ) def parse_iso8601_string(value): """turns ISO 8601 string into datetime object""" value = force_text(value, strings_only=True).rstrip('Z') for format in ISO8601_FORMATS: try: parsed_value = datetime.strptime(value, format) break except ValueError: try: parsed_value = datetime.strptime(value[:-6], format) break except ValueError: pass else: raise ValueError('failed to hydrate the %s timestamp' % value) offset_str = value[-6:] if offset_str and offset_str[0] in ('-', '+'): tz_offset = timedelta(hours=int(offset_str[1:3]), minutes=int(offset_str[4:6])) tz_offset = tz_offset.seconds // 60 if offset_str[0] == '-': tz_offset *= -1 else: tz_offset = 0 tz_correction = timezone.get_fixed_timezone(tz_offset) return timezone.make_aware(parsed_value, tz_correction) def hide_post_parameters(request): """ Mark request as having sensitive parameters We can't use decorator because of DRF uses custom HttpRequest that is incompatibile with Django's decorator """ request.sensitive_post_parameters = '__ALL__' def clean_return_path(request): """return path utility that returns return path from referer or POST""" if request.method == 'POST' and 'return_path' in request.POST: return _get_return_path_from_post(request) else: return _get_return_path_from_referer(request) def _get_return_path_from_post(request): return_path = request.POST.get('return_path') try: if not return_path: raise ValueError() if not return_path.startswith('/'): raise ValueError() resolve(return_path) return return_path except (Http404, ValueError): return None def _get_return_path_from_referer(request): referer = request.META.get('HTTP_REFERER') try: if not referer: raise ValueError() if not referer.startswith(request.scheme): raise ValueError() referer = referer[len(request.scheme) + 3:] if not referer.startswith(request.META['HTTP_HOST']): raise ValueError() referer = referer[len(request.META['HTTP_HOST'].rstrip('/')):] if not referer.startswith('/'): raise ValueError() resolve(referer) return referer except (Http404, KeyError, ValueError): return None def is_request_to_misago(request): try: return request._request_to_misago except AttributeError: request._request_to_misago = _is_request_path_under_misago(request) return request._request_to_misago def _is_request_path_under_misago(request): # We are assuming that forum_index link is root of all Misago links forum_index = reverse('misago:index') path_info = request.path_info if len(forum_index) > len(path_info): return False return path_info[:len(forum_index)] == forum_index def is_referer_local(request): referer = request.META.get('HTTP_REFERER') if not referer: return False if not referer.startswith(request.scheme): return False referer = referer[len(request.scheme) + 3:] if not referer.startswith(request.META['HTTP_HOST']): return False referer = referer[len(request.META['HTTP_HOST'].rstrip('/')):] if not referer.startswith('/'): return False return True def get_exception_message(exception=None, default_message=None): if not exception: return default_message try: return exception.args[0] except IndexError: return default_message