Repository: django-cms/djangocms-alias (language: python)

Issue:
Remove trailing new line character from test text plugin template



Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 4bd22c51..33861695 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -5,6 +5,7 @@ Changelog
 Unreleased
 ==========
 * fix: Moved category list filter after site
+* fix: Ordering category filter by name
 
 1.6.0 (2022-04-29)
 ==================
diff --git a/djangocms_alias/admin.py b/djangocms_alias/admin.py
index 036ce77a..ba42c771 100644
--- a/djangocms_alias/admin.py
+++ b/djangocms_alias/admin.py
@@ -9,7 +9,7 @@
 
 from .cms_config import AliasCMSConfig
 from .constants import USAGE_ALIAS_URL_NAME
-from .filters import LanguageFilter, SiteFilter
+from .filters import CategoryFilter, LanguageFilter, SiteFilter
 from .forms import AliasContentForm
 from .models import Alias, AliasContent, Category
 from .urls import urlpatterns
@@ -28,7 +28,7 @@
 
 alias_content_admin_classes = [admin.ModelAdmin]
 alias_content_admin_list_display = ('name', 'get_category',)
-alias_content_admin_list_filter = (SiteFilter, LanguageFilter, 'alias__category', )
+alias_content_admin_list_filter = (SiteFilter, CategoryFilter, LanguageFilter,)
 djangocms_versioning_enabled = AliasCMSConfig.djangocms_versioning_enabled
 
 if djangocms_versioning_enabled:
@@ -37,8 +37,7 @@
     from .filters import UnpublishedFilter
     alias_content_admin_classes.insert(0, ExtendedVersionAdminMixin)
     alias_content_admin_list_display = ('name', 'get_category',)
-    alias_content_admin_list_filter = (SiteFilter, LanguageFilter, UnpublishedFilter)
-    alias_content_admin_list_filter = (SiteFilter, 'alias__category', LanguageFilter, UnpublishedFilter)
+    alias_content_admin_list_filter = (SiteFilter, CategoryFilter, LanguageFilter, UnpublishedFilter)
 
 
 @admin.register(Category)
diff --git a/djangocms_alias/constants.py b/djangocms_alias/constants.py
index 413b4f48..43884cf0 100644
--- a/djangocms_alias/constants.py
+++ b/djangocms_alias/constants.py
@@ -19,3 +19,4 @@
 SITE_FILTER_URL_PARAM = "site"
 SITE_FILTER_NO_SITE_VALUE = "no_site"
 UNPUBLISHED_FILTER_URL_PARAM = "unpublished"
+CATEGORY_FILTER_PARAM = "category"
diff --git a/djangocms_alias/filters.py b/djangocms_alias/filters.py
index 02975f0c..4d399d4d 100644
--- a/djangocms_alias/filters.py
+++ b/djangocms_alias/filters.py
@@ -1,4 +1,5 @@
 from django.contrib import admin
+from django.utils.encoding import smart_str
 from django.utils.translation import gettext_lazy as _
 
 from cms.forms.utils import get_sites
@@ -6,10 +7,12 @@
 
 from .cms_config import AliasCMSConfig
 from .constants import (
+    CATEGORY_FILTER_PARAM,
     LANGUAGE_FILTER_URL_PARAM,
     SITE_FILTER_NO_SITE_VALUE,
     SITE_FILTER_URL_PARAM,
 )
+from .models import Category
 
 
 djangocms_versioning_enabled = AliasCMSConfig.djangocms_versioning_enabled
@@ -82,6 +85,38 @@ def choices(self, changelist):
             }
 
 
+class CategoryFilter(admin.SimpleListFilter):
+    title = _("Category")
+    parameter_name = CATEGORY_FILTER_PARAM
+
+    def lookups(self, request, model_admin):
+        qs = model_admin.get_queryset(request)
+        cat_id = qs.values_list('alias__category', flat=True).distinct()
+        # Ensure the category is ordered by the name alphabetically by default
+        cat = Category.objects.filter(pk__in=cat_id).order_by('translations__name')
+        for obj in cat:
+            yield str(obj.pk), smart_str(obj)
+
+    def queryset(self, request, queryset):
+        if self.value():
+            return queryset.filter(alias__category=self.value()).distinct()
+
+    def choices(self, changelist):
+        yield {
+            "selected": self.value() is None,
+            "query_string": changelist.get_query_string(remove=[self.parameter_name]),
+            "display": _("All"),
+        }
+        for lookup, title in self.lookup_choices:
+            yield {
+                "selected": self.value() == str(lookup),
+                "query_string": changelist.get_query_string(
+                    {self.parameter_name: lookup}
+                ),
+                "display": title,
+            }
+
+
 if djangocms_versioning_enabled:
     from djangocms_versioning.constants import UNPUBLISHED
 


Test patch:
diff --git a/tests/test_admin_filters.py b/tests/test_admin_filters.py
index 379a90b2..6dfca0de 100644
--- a/tests/test_admin_filters.py
+++ b/tests/test_admin_filters.py
@@ -1,5 +1,6 @@
 from unittest import skipUnless
 
+from django.contrib import admin
 from django.contrib.sites.models import Site
 
 from cms.utils import get_current_site
@@ -9,6 +10,7 @@
     SITE_FILTER_URL_PARAM,
     UNPUBLISHED_FILTER_URL_PARAM,
 )
+from djangocms_alias.filters import CategoryFilter
 from djangocms_alias.models import Alias as AliasModel, AliasContent, Category
 from djangocms_alias.utils import is_versioning_enabled
 
@@ -252,9 +254,9 @@ def test_category_filter_no_verisoning(self):
         with self.login_user_context(self.superuser):
             response_default = self.client.get(base_url)
             # category one should have a result
-            category_one_filter_response = self.client.get(f"{base_url}?alias__category__id__exact={category_one.id}")
+            category_one_filter_response = self.client.get(f"{base_url}?category={category_one.id}")
             # category two should have a result
-            category_two_filter_response = self.client.get(f"{base_url}?alias__category__id__exact={category_two.id}")
+            category_two_filter_response = self.client.get(f"{base_url}?category={category_two.id}")
 
         # By default all alias contents are shown
         self.assertEqual(
@@ -310,9 +312,9 @@ def test_category_filter_with_verisoning(self):
         with self.login_user_context(self.superuser):
             response_default = self.client.get(base_url)
             # category one should have a result
-            category_one_filter_response = self.client.get(f"{base_url}?alias__category__id__exact={category_one.id}")
+            category_one_filter_response = self.client.get(f"{base_url}?category={category_one.id}")
             # categopry two should have a result
-            category_two_filter_response = self.client.get(f"{base_url}?alias__category__id__exact={category_two.id}")
+            category_two_filter_response = self.client.get(f"{base_url}?category={category_two.id}")
 
         # By default all alias contents are shown
         self.assertEqual(
@@ -332,3 +334,76 @@ def test_category_filter_with_verisoning(self):
             set(category_two_filter_response.context["cl"].queryset),
             set([expected_category_two_content])
         )
+
+    def test_category_filter_lookups_ordered_alphabetical(self):
+        """
+        Category filter lookup choices should be ordered in alphabetical order
+        """
+        category_one = Category.objects.create(name='b - category')
+        alias_one = AliasModel.objects.create(
+            category=category_one,
+            position=0,
+        )
+        AliasContent.objects.create(
+            alias=alias_one,
+            name="EN Alias Content one",
+            language="en",
+        )
+        category_two = Category.objects.create(name='a - category')
+        alias_two = AliasModel.objects.create(
+            category=category_two,
+            position=1,
+        )
+        AliasContent.objects.create(
+            alias=alias_two,
+            name="EN Alias Content two",
+            language="en",
+        )
+
+        version_admin = admin.site._registry[AliasContent]
+        category_filter = CategoryFilter(None, {"category": ""}, AliasContent, version_admin)
+        # Get the first choice in the filter lookup object
+        first_lookup_value = category_filter.lookup_choices[0][1]
+        # Lookup value should match the category name linked to alias content
+        self.assertEqual(
+            first_lookup_value, category_two.name
+        )
+        self.assertNotEqual(
+            first_lookup_value, category_one.name
+        )
+
+    def test_category_filter_lookup_should_only_show_aliases_linked_to_content(self):
+        """
+        Category not linked to content should not be listed in the category filter lookups
+        """
+        category_one = Category.objects.create(name='b - category')
+        alias_one = AliasModel.objects.create(
+            category=category_one,
+            position=0,
+        )
+        AliasContent.objects.create(
+            alias=alias_one,
+            name="EN Alias Content one",
+            language="en",
+        )
+        category_two = Category.objects.create(name='a - category')
+        AliasModel.objects.create(
+            category=category_two,
+            position=1,
+        )
+
+        version_admin = admin.site._registry[AliasContent]
+        category_filter = CategoryFilter(None, {"category": ""}, AliasContent, version_admin)
+
+        # Get the first choice in the filter lookup object
+        first_lookup_value = category_filter.lookup_choices[0][1]
+        # Lookup choices should only display the category linked to content
+        self.assertEqual(len(category_filter.lookup_choices), 1)
+        # Lookup value should match the category name linked to alias content
+        self.assertEqual(
+            first_lookup_value, category_one.name
+        )
+        # Category not linked to alias content should not be listed in the choices
+        self.assertNotEqual(
+            first_lookup_value, category_two.name
+        )