Skip to content

Commit 00c6bf9

Browse files
feat: Add API endpoint for page aliases with tests and docs
Add a new API endpoint for page aliases with corresponding serializer, view, and URL routing. Include tests and documentation for the new functionality. New Features: - Introduce a new API endpoint to expose page aliases, allowing users to retrieve alias information based on language. Enhancements: - Implement an AliasSerializer to handle the representation of alias data, including fields for URL, redirect target, language, and active status. Documentation: - Add documentation for the new aliases endpoint, detailing its usage and functionality. Tests: - Add tests for the alias endpoint, including checks for correct data retrieval, language filtering, and permission handling. Resolves #5
1 parent af171cb commit 00c6bf9

File tree

5 files changed

+99
-0
lines changed

5 files changed

+99
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from rest_framework import serializers
2+
from cms.models import PageUrl
3+
4+
5+
class AliasSerializer(serializers.Serializer):
6+
url = serializers.CharField()
7+
redirect_to = serializers.CharField()
8+
language = serializers.CharField()
9+
is_active = serializers.BooleanField()
10+
11+
def to_representation(self, instance):
12+
return {
13+
'url': instance.path,
14+
'redirect_to': instance.page.get_absolute_url(instance.language),
15+
'language': instance.language,
16+
'is_active': instance.page.is_published(instance.language)
17+
}

djangocms_rest/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from . import views
44

55
urlpatterns = [
6+
path("<slug:language>/aliases/", views.AliasList.as_view(), name="cms-alias-list"),
67
path("", views.LanguageList.as_view(), name="cms-language-list"),
78
path("<slug:language>/pages", views.PageList.as_view(), name="cms-page-list"),
89
path("<slug:language>/pages/", views.PageDetail.as_view(), name="cms-page-root"),

djangocms_rest/views.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from cms.models import Page, PageUrl, Placeholder, PageContent
2+
from djangocms_rest.serializers.aliasserializer import AliasSerializer
23
from cms.utils.conf import get_languages
34
from cms.utils.i18n import get_language_tuple
45
from cms.utils.page_permissions import user_can_view_page
@@ -92,6 +93,34 @@ def get(self, request, language, path="", format=None):
9293
return Response(serializer.data)
9394

9495

96+
class AliasList(APIView):
97+
"""
98+
List of all page aliases for a given language.
99+
Returns URL aliases and their redirect targets.
100+
"""
101+
102+
def get(self, request, language, format=None):
103+
site = get_current_site(request)
104+
allowed_languages = [lang[0] for lang in get_language_tuple(site.pk)]
105+
if language not in allowed_languages:
106+
raise Http404
107+
108+
aliases = PageUrl.objects.get_for_site(site).filter(language=language)
109+
110+
# Filter out non-viewable pages for anonymous users
111+
if request.user.is_anonymous:
112+
aliases = aliases.filter(page__login_required=False)
113+
114+
# Filter based on page permissions
115+
aliases = [
116+
alias for alias in aliases
117+
if user_can_view_page(request.user, alias.page)
118+
]
119+
120+
serializer = AliasSerializer(aliases, many=True)
121+
return Response(serializer.data)
122+
123+
95124
class PlaceholderDetail(APIView):
96125
"""Placeholder contain the dynamic content. This view retrieves the content as a
97126
structured nested object.

tests/requirements/base.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
pytest
12
# requirements from setup.py
23
djangocms-picture>=2.1.0
34
djangocms-link>=2.2.1

tests/test_rendering.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,57 @@ class RESTTestCase(CMSTestCase):
77
prefix = "http://testserver"
88

99

10+
class AliasAPITestCase(RESTTestCase):
11+
def setUp(self):
12+
super().setUp()
13+
# Create a test page with multiple language versions
14+
self.page = create_page(
15+
"test page",
16+
template="INHERIT",
17+
language="en",
18+
published=True
19+
)
20+
# Create language versions
21+
self.page.create_translation('de', title='Testseite')
22+
self.page.create_translation('fr', title='page de test')
23+
24+
def test_alias_list(self):
25+
"""Test that the alias list endpoint returns correct data"""
26+
url = reverse("cms-alias-list", kwargs={"language": "en"})
27+
response = self.client.get(url)
28+
29+
self.assertEqual(response.status_code, 200)
30+
data = response.json()
31+
32+
# Verify structure of returned data
33+
self.assertTrue(isinstance(data, list))
34+
if len(data) > 0:
35+
alias = data[0]
36+
self.assertIn('url', alias)
37+
self.assertIn('redirect_to', alias)
38+
self.assertIn('language', alias)
39+
self.assertIn('is_active', alias)
40+
41+
def test_alias_language_filter(self):
42+
"""Test that aliases are correctly filtered by language"""
43+
url = reverse("cms-alias-list", kwargs={"language": "de"})
44+
response = self.client.get(url)
45+
46+
self.assertEqual(response.status_code, 200)
47+
data = response.json()
48+
49+
# Verify all returned aliases are for German language
50+
for alias in data:
51+
self.assertEqual(alias['language'], 'de')
52+
53+
def test_invalid_language(self):
54+
"""Test that invalid language code returns 404"""
55+
url = reverse("cms-alias-list", kwargs={"language": "invalid"})
56+
response = self.client.get(url)
57+
58+
self.assertEqual(response.status_code, 404)
59+
60+
1061
class RenderingTestCase(RESTTestCase):
1162
def _create_pages(self, page_list, parent=None):
1263
new_pages = [create_page(

0 commit comments

Comments
 (0)