Skip to content

Commit

Permalink
Add tests for third-party app endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
fsbraun committed Oct 27, 2024
1 parent 3d538e3 commit cbe4266
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 9 deletions.
17 changes: 10 additions & 7 deletions djangocms_link/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from django.apps import apps
from django.conf import settings
from django.contrib import admin
from django.core.exceptions import FieldError, PermissionDenied
from django.db.models import Q
from django.http import JsonResponse
from django.urls import path
from django.views.generic.list import BaseListView
Expand All @@ -22,13 +24,7 @@
class GrouperModelAdmin:
pass

REGISTERED_ADMIN = []

for _admin in admin.site._registry.values():
if _admin.model._meta.app_label == "cms":
continue
if getattr(_admin, "search_fields", []) and hasattr(_admin.model, "get_absolute_url"):
REGISTERED_ADMIN.append(_admin)
REGISTERED_ADMIN = getattr(settings, "DJANGOCMS_LINK_URL_ADMINS", "auto")


class AdminUrlsView(BaseListView):
Expand Down Expand Up @@ -133,12 +129,19 @@ def get_queryset(self):
return list(qs)

def add_admin_querysets(self, qs):
if REGISTERED_ADMIN == "auto":
return qs

Check warning on line 133 in djangocms_link/admin.py

View check run for this annotation

Codecov / codecov/patch

djangocms_link/admin.py#L133

Added line #L133 was not covered by tests

for model_admin in REGISTERED_ADMIN:
try:
# hack: GrouperModelAdmin expects a language to be temporarily set
if isinstance(model_admin, GrouperModelAdmin):
model_admin.language = self.language

Check warning on line 139 in djangocms_link/admin.py

View check run for this annotation

Codecov / codecov/patch

djangocms_link/admin.py#L139

Added line #L139 was not covered by tests
new_qs = model_admin.get_queryset(self.request)
if hasattr(model_admin.model, "site") and self.site:
new_qs = new_qs.filter(Q(site_id=self.site) | Q(site__isnull=True))
elif hasattr(model_admin.model, "sites") and self.site:
new_qs = new_qs.filter(sites__id=self.site)

Check warning on line 144 in djangocms_link/admin.py

View check run for this annotation

Codecov / codecov/patch

djangocms_link/admin.py#L144

Added line #L144 was not covered by tests
new_qs, search_use_distinct = model_admin.get_search_results(
self.request, new_qs, self.term
)
Expand Down
19 changes: 19 additions & 0 deletions djangocms_link/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,22 @@
class DjangoCmsLinkConfig(AppConfig):
name = "djangocms_link"
verbose_name = _("django CMS Link")

def ready(self):
# Only scan admins after all apps are loaded

from django.contrib import admin

from djangocms_link import admin as link_admin

if link_admin.REGISTERED_ADMIN == "auto":
# Autoconfig? Check the admin registry for suitable admins
link_admin.REGISTERED_ADMIN = []
for _admin in admin.site._registry.values():
if _admin.model._meta.app_label == "cms":
# Skip CMS models
continue
# search_fields need to be defined in the ModelAdmin class, and the model needs to have
# a get_absolute_url method.
if getattr(_admin, "search_fields", []) and hasattr(_admin.model, "get_absolute_url"):
link_admin.REGISTERED_ADMIN.append(_admin)
123 changes: 121 additions & 2 deletions tests/test_endpoint.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
from django.contrib import admin
from django.contrib.sites.models import Site

from cms.api import create_page
from cms.models import Page
from cms.test_utils.testcases import CMSTestCase
from cms.utils.urlutils import admin_reverse

from djangocms_link.models import Link
from tests.utils.models import ThirdPartyModel


class LinkModelTestCase(CMSTestCase):
class LinkEndpointTestCase(CMSTestCase):
def setUp(self):
self.root_page = create_page(
title="root",
Expand Down Expand Up @@ -40,7 +44,6 @@ def tearDown(self):
self.subling.delete()

def test_api_endpoint(self):

for query_params in ("", "?app_label=1"):
with self.subTest(query_params=query_params):
with self.login_user_context(self.get_superuser()):
Expand Down Expand Up @@ -115,3 +118,119 @@ def test_get_reference(self):
self.assertEqual(data["id"], "cms.page:1")
self.assertEqual(data["text"], "root")
self.assertEqual(data["url"], self.root_page.get_absolute_url())


class LinkEndpointThirdPartyTestCase(CMSTestCase):
def setUp(self):
LinkAdmin = admin.site._registry[Link]
self.endpoint = admin_reverse(LinkAdmin.link_url_name)

self.second_site = Site.objects.create(
domain="second",
name="second",
)

self.items = (
ThirdPartyModel.objects.create(name="First", path="/first", site_id=1),
ThirdPartyModel.objects.create(name="Second", path="/second", site=self.second_site),
ThirdPartyModel.objects.create(name="django CMS", path="/django-cms"),
ThirdPartyModel.objects.create(name="django CMS rocks", path="/django-cms-2"),
)

def test_auto_config(self):
from djangocms_link.admin import REGISTERED_ADMIN
from tests.utils.admin import ThirdPartyAdmin

for registered_admin in REGISTERED_ADMIN:
if isinstance(registered_admin, ThirdPartyAdmin):
break
else:
self.asserFail("ThirdPartyAdmin not found in REGISTERED_ADMIN")

def test_api_endpoint(self):
for query_params in ("", "?app_label=1"):
with self.subTest(query_params=query_params):
with self.login_user_context(self.get_superuser()):
response = self.client.get(self.endpoint + query_params)
self.assertEqual(response.status_code, 200)
data = response.json()

self.assertIn("results", data)
self.assertEqual(len(data["results"]), 1)
self.assertIn("pagination", data)
self.assertEqual(data["pagination"]["more"], False)
destinations = data["results"][0]
self.assertEqual(destinations["text"], "Third party models")
for destination in destinations["children"]:
self.assertIn("id", destination)
self.assertIn("text", destination)
self.assertIn("url", destination)
_, pk = destination["id"].split(":")
db_obj = ThirdPartyModel.objects.get(pk=pk)
self.assertEqual(destination["text"], str(db_obj))

def test_filter(self):
with self.login_user_context(self.get_superuser()):
response = self.client.get(self.endpoint + "?term=CMS")
self.assertEqual(response.status_code, 200)
data = response.json()

self.assertIn("results", data)
self.assertEqual(len(data["results"]), 1)
self.assertIn("pagination", data)
self.assertEqual(data["pagination"]["more"], False)

pages = data["results"][0]
self.assertEqual(len(pages["children"]), 2)

def test_site_selector(self):

for site_id in (1, 2):
with self.subTest(site_id=site_id):
with self.login_user_context(self.get_superuser()):
response = self.client.get(self.endpoint + f"?app_label={site_id}")
self.assertEqual(response.status_code, 200)
data = response.json()

self.assertIn("results", data)
self.assertEqual(len(data["results"]), 1)
self.assertIn("pagination", data)
self.assertEqual(data["pagination"]["more"], False)
destinations = data["results"][0]
self.assertEqual(destinations["text"], "Third party models")
# One site-specific item, two all-sites items
self.assertEqual(len(destinations["children"]), 3)

# Specific site item
if site_id == 1:
self.assertIn(
{'id': 'utils.thirdpartymodel:1', 'text': 'First', 'url': '/first'},
destinations["children"]
)
else:
self.assertIn(
{'id': 'utils.thirdpartymodel:2', 'text': 'Second', 'url': '/second'},
destinations["children"]
)
# All-sites items
self.assertIn(
{'id': 'utils.thirdpartymodel:3', 'text': 'django CMS', 'url': '/django-cms'},
destinations["children"]
)
self.assertIn(
{'id': 'utils.thirdpartymodel:4', 'text': 'django CMS rocks', 'url': '/django-cms-2'},
destinations["children"]
)

def test_get_reference(self):
with self.login_user_context(self.get_superuser()):
response = self.client.get(self.endpoint + "?g=utils.thirdpartymodel:1")
self.assertEqual(response.status_code, 200)
data = response.json()

self.assertIn("id", data)
self.assertIn("text", data)
self.assertIn("url", data)
self.assertEqual(data["id"], "utils.thirdpartymodel:1")
self.assertEqual(data["text"], "First")
self.assertEqual(data["url"], self.items[0].get_absolute_url())
8 changes: 8 additions & 0 deletions tests/utils/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.contrib import admin

from tests.utils.models import ThirdPartyModel


@admin.register(ThirdPartyModel)
class ThirdPartyAdmin(admin.ModelAdmin):
search_fields = ("name",)
13 changes: 13 additions & 0 deletions tests/utils/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from django.db import models


class ThirdPartyModel(models.Model):
name = models.CharField(max_length=255)
path = models.CharField(max_length=255)
site = models.ForeignKey("sites.Site", on_delete=models.SET_NULL, null=True)

def get_absolute_url(self):
return self.path

def __str__(self):
return self.name

0 comments on commit cbe4266

Please sign in to comment.