Skip to content

Commit a8a2534

Browse files
committed
feat: short link back end
1 parent 2d3fb8c commit a8a2534

File tree

7 files changed

+85
-4
lines changed

7 files changed

+85
-4
lines changed

infographics/urls.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
from web import urls as web_urls
2424
from api import urls as api_urls
25+
from shortlink import urls as shortlink_urls
2526

2627
redirect_to_infographics = RedirectView.as_view(url="/web/infographics/")
2728

@@ -30,4 +31,6 @@
3031
path("", redirect_to_infographics),
3132
path("web/", include(web_urls)),
3233
path("api/", include(api_urls)),
34+
path("api2/", include(api_urls)),
35+
path("s/", include(shortlink_urls)),
3336
]

shortlink/admin.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
from django.contrib import admin
2+
from django.utils.html import format_html
3+
24

35
from shortlink.models import ShortLink
46

7+
58
@admin.register(ShortLink)
69
class ShortLinkAdmin(admin.ModelAdmin):
7-
list_display = ["id", "query"]
10+
list_display = ["id", "url", "query"]
11+
12+
def url(self, obj):
13+
encoded = obj.encoded_id()
14+
link = f"/s/{encoded}/"
15+
return format_html(f'<a href="{link}">{link}/</a>')

shortlink/models.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ def encoded_id_from_query(self, query):
1717
return self.encode(short_link.id)
1818

1919
def query_from_encoded_id(self, encoded):
20+
"""
21+
Can raise
22+
23+
- ShortLink.DoesNotExist
24+
- IndexError
25+
"""
2026
id = self.decode(encoded)
2127
return self.get(id=id).query
2228

@@ -25,3 +31,6 @@ class ShortLink(models.Model):
2531
query = models.TextField()
2632

2733
objects = ShortLinkManager()
34+
35+
def encoded_id(self):
36+
return ShortLink.objects.encode(self.id)

shortlink/tests.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,31 @@ def test_existant_query(self):
3232
ShortLink.objects.decode(encoded),
3333
ShortLink.objects.decode(encoded2),
3434
)
35+
36+
def test_url(self):
37+
encoded = ShortLink.objects.encoded_id_from_query("abc def\nghi")
38+
res = self.client.get(f"/s/{encoded}/")
39+
self.assertEqual(res.status_code, 302)
40+
self.assertEqual(
41+
res.headers["Location"],
42+
"/web/infographics/?query=abc%20def%0Aghi",
43+
)
44+
res = self.client.get("/s/abc/")
45+
self.assertEqual(res.status_code, 404)
46+
ShortLink.objects.all().delete()
47+
res = self.client.get(f"/s/{encoded}/")
48+
self.assertEqual(res.status_code, 404)
49+
50+
def test_generate(self):
51+
query = "SELECT\n?abc"
52+
res = self.client.post("/s/generate/", {"query": query})
53+
self.assertEqual(res.status_code, 201)
54+
encoded = ShortLink.objects.encoded_id_from_query(query)
55+
url = f"/s/{encoded}/"
56+
self.assertEqual(res.json(), {"url": url})
57+
res = self.client.get(url)
58+
self.assertEqual(res.status_code, 302)
59+
self.assertEqual(
60+
res.headers["Location"],
61+
"/web/infographics/?query=SELECT%0A?abc",
62+
)

shortlink/urls.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from django.urls import path
2+
3+
from .views import redirect_to_query
4+
from .views import get_short_link
5+
6+
urlpatterns = [
7+
path("generate/", get_short_link, name="get_short_link"),
8+
path("<str:encoded_id>/", redirect_to_query, name="shortlink"),
9+
]

shortlink/views.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
1-
from django.shortcuts import render
1+
from django.shortcuts import redirect
2+
from django.shortcuts import reverse
3+
from django.http import HttpResponse
4+
from django.http import JsonResponse
5+
from django.views.decorators.http import require_POST
6+
from django.views.decorators.http import require_safe
7+
from django.views.decorators.csrf import csrf_exempt
28

3-
# Create your views here.
9+
from shortlink.models import ShortLink
10+
11+
@require_safe
12+
def redirect_to_query(request, encoded_id: str):
13+
try:
14+
query = ShortLink.objects.query_from_encoded_id(encoded_id)
15+
except (ShortLink.DoesNotExist, IndexError):
16+
return HttpResponse(status=404)
17+
url = reverse("main")
18+
return redirect(url + f"?query={query}")
19+
20+
21+
@csrf_exempt
22+
@require_POST
23+
def get_short_link(request):
24+
query = request.POST["query"]
25+
encoded = ShortLink.objects.encoded_id_from_query(query)
26+
url = reverse("shortlink", kwargs={"encoded_id": encoded})
27+
return JsonResponse({"url": url}, status=201)

web/urls.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44

55
urlpatterns = [
66
path("", render_react_index),
7-
path("infographics/", render_react_index),
7+
path("infographics/", render_react_index, name="main"),
88
]

0 commit comments

Comments
 (0)