Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 48 additions & 2 deletions pontoon/api/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,19 @@ def test_locale(django_assert_num_queries):
} in localizations


@pytest.mark.django_db
def test_locale_renamed_code_redirects():
"""Requesting a locale by its old code redirects to the new code."""
locale = Locale.objects.get(code="af")
locale.code = "af-renamed"
locale.save()

response = APIClient().get("/api/v2/locales/af/", HTTP_ACCEPT="application/json")

assert response.status_code == 302
assert response["Location"] == "/api/v2/locales/af-renamed/"


@pytest.mark.django_db
def test_locales(django_assert_num_queries):
project_a = ProjectFactory(
Expand Down Expand Up @@ -477,6 +490,24 @@ def test_project(django_assert_num_queries):
} in localizations


@pytest.mark.django_db
def test_project_locale_renamed_redirects():
"""Requesting a project locale by an old code and old slug redirects to the new URL."""
locale = Locale.objects.get(code="af")
locale.code = "af-renamed"
locale.save()
project = Project.objects.get(slug="terminology")
project.slug = "terminology-renamed"
project.save()

response = APIClient().get(
"/api/v2/af/terminology/", HTTP_ACCEPT="application/json"
)

assert response.status_code == 302
assert response["Location"] == "/api/v2/af-renamed/terminology-renamed/"


@pytest.mark.django_db
def test_system_project(django_assert_num_queries):
project = Project.objects.get(slug="tutorial")
Expand All @@ -495,8 +526,8 @@ def test_system_project(django_assert_num_queries):
@pytest.mark.django_db
def test_disabled_project(django_assert_num_queries):
project = ProjectFactory.create(slug="disabled-1", disabled=True)

with django_assert_num_queries(1):
# 1 project lookup + 1 ProjectSlugHistory fallback lookup on the 404 path
with django_assert_num_queries(2):
response = APIClient().get(
f"/api/v2/projects/{project.slug}/", HTTP_ACCEPT="application/json"
)
Expand Down Expand Up @@ -1010,6 +1041,21 @@ def test_project_locale(django_assert_num_queries):
}


@pytest.mark.django_db
def test_project_renamed_slug_redirects():
"""Requesting a project by its old slug redirects to the new slug."""
project = Project.objects.get(slug="terminology")
project.slug = "terminology-renamed"
project.save()

response = APIClient().get(
"/api/v2/projects/terminology/", HTTP_ACCEPT="application/json"
)

assert response.status_code == 302
assert response["Location"] == "/api/v2/projects/terminology-renamed/"


@pytest.mark.django_db
def test_terminology_search(django_assert_num_queries):
locale_a = LocaleFactory(
Expand Down
57 changes: 56 additions & 1 deletion pontoon/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
from rest_framework.views import APIView

from django.db.models import Prefetch, Q
from django.shortcuts import get_object_or_404
from django.http import Http404
from django.shortcuts import get_object_or_404, redirect
from django.utils.timezone import make_aware

from pontoon.actionlog.models import ActionLog
Expand All @@ -23,8 +24,10 @@
from pontoon.base.models import (
Entity,
Locale,
LocaleCodeHistory,
Project,
ProjectLocale,
ProjectSlugHistory,
Resource,
Translation,
TranslationMemoryEntry,
Expand Down Expand Up @@ -198,6 +201,19 @@ def get_queryset(self):

return qs

def retrieve(self, request, *args, **kwargs):
try:
return super().retrieve(request, *args, **kwargs)
except Http404:
code_history = (
LocaleCodeHistory.objects.filter(old_code=self.kwargs["code"])
.order_by("-created_at")
.first()
)
if code_history is None:
raise
return redirect("locale-individual", code=code_history.locale.code)


class ProjectListView(RequestFieldsMixin, generics.ListAPIView):
serializer_class = NestedProjectSerializer
Expand Down Expand Up @@ -282,6 +298,19 @@ def get_queryset(self):

return qs.distinct()

def retrieve(self, request, *args, **kwargs):
try:
return super().retrieve(request, *args, **kwargs)
except Http404:
slug_history = (
ProjectSlugHistory.objects.filter(old_slug=self.kwargs["slug"])
.order_by("-created_at")
.first()
)
if slug_history is None:
raise
return redirect("project-individual", slug=slug_history.project.slug)


class EntityListView(RequestFieldsMixin, generics.ListAPIView):
serializer_class = EntitySerializer
Expand Down Expand Up @@ -374,6 +403,32 @@ def get_object(self):

return obj

def retrieve(self, request, *args, **kwargs):
try:
return super().retrieve(request, *args, **kwargs)
except Http404:
code = self.kwargs["code"]
slug = self.kwargs["slug"]

code_history = (
LocaleCodeHistory.objects.filter(old_code=code)
.order_by("-created_at")
.first()
)
slug_history = (
ProjectSlugHistory.objects.filter(old_slug=slug)
.order_by("-created_at")
.first()
)
if code_history is None and slug_history is None:
raise

if code_history is not None:
code = code_history.locale.code
if slug_history is not None:
slug = slug_history.project.slug
return redirect("project-locale-individual", code=code, slug=slug)


class TermSearchListView(RequestFieldsMixin, generics.ListAPIView):
serializer_class = TermSerializer
Expand Down
Loading