1 from urllib.parse import urlparse, urlunparse, parse_qs
3 from django.shortcuts import redirect, render
4 from django.views.generic.base import TemplateView
6 from rest_framework import status, viewsets
7 from rest_framework.response import Response
10 from . import serializers
12 def _remove_utm(link):
13 parsed_link = urlparse(link)
14 parsed_link = parsed_link._replace(
18 for p in parsed_link.query.split('&')
19 if not p.startswith('utm_')
25 parsed_link.scheme + '://' if parsed_link.scheme else '',
28 ';' + parsed_link.params if parsed_link.params else '',
29 '?' + parsed_link.query if parsed_link.query else '',
30 '#' + parsed_link.fragment if parsed_link.fragment else '',
33 def _follow_redirects(link, remove_utm):
34 redirect_sequence = []
37 redirect_sequence.append(link)
40 link = _remove_utm(link)
42 # TODO Do this in an async call so it doesn't block the main thread
43 response = requests.head(link, timeout=10)
45 # TODO Handle timeouts
47 if 301 <= response.status_code and response.status_code <= 308:
48 # TODO Handle the different kinds of redirects correctly
50 link = response.headers.get('Location')
56 # TODO Handle error responses
60 'status': response.status_code,
62 # TODO Handle different capitalizations of "Content-Type"
63 'content_type': response.headers.get('Content-Type'),
64 'redirect_sequence': redirect_sequence,
67 class IndexView(TemplateView):
68 template_name = 'bigly/index.html'
70 index = IndexView.as_view()
72 class FAQView(TemplateView):
73 template_name = 'bigly/faq.html'
75 faq = FAQView.as_view()
77 def embiggen(request):
78 serializer = serializers.FollowRedirectsSerializer(data=request.GET)
80 if not serializer.is_valid():
85 'errors': serializer.errors,
90 result = _follow_redirects(
91 link = serializer.data['link'],
92 remove_utm = serializer.data['remove_utm'],
95 if serializer.data['handler'] == 'redirect':
96 return redirect(result['link'])
101 'bigly/link_info.html',
105 class FollowRedirectsViewSet(viewsets.ViewSet):
106 serializer_class = serializers.FollowRedirectsSerializer
108 def follow_redirects(self, request):
109 serializer = serializers.FollowRedirectsSerializer(data=request.query_params)
111 if not serializer.is_valid():
114 status=status.HTTP_400_BAD_REQUEST,
117 result = _follow_redirects(
118 link = serializer.data['link'],
119 remove_utm = serializer.data['remove_utm'],
124 status=status.HTTP_200_OK,
127 api_follow_redirects = FollowRedirectsViewSet.as_view({
128 'get': 'follow_redirects',