From 0bb04fec4b26ac0b45ddc84d1e65d20489d19a57 Mon Sep 17 00:00:00 2001 From: etj Date: Thu, 6 Jul 2023 17:49:15 +0200 Subject: [PATCH] [Fixes #11101] Faceting: keywords --- geonode/facets/models.py | 1 + geonode/facets/providers/keyword.py | 96 +++++++++++++++++++++++++++++ geonode/facets/tests.py | 6 +- geonode/settings.py | 1 + 4 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 geonode/facets/providers/keyword.py diff --git a/geonode/facets/models.py b/geonode/facets/models.py index c7f9fbd0813..4beffbb1ac6 100644 --- a/geonode/facets/models.py +++ b/geonode/facets/models.py @@ -29,6 +29,7 @@ FACET_TYPE_THESAURUS = "thesaurus" FACET_TYPE_CATEGORY = "category" FACET_TYPE_BASE = "base" +FACET_TYPE_KEYWORD = "keyword" logger = logging.getLogger(__name__) diff --git a/geonode/facets/providers/keyword.py b/geonode/facets/providers/keyword.py new file mode 100644 index 00000000000..4a82e9a3dbc --- /dev/null +++ b/geonode/facets/providers/keyword.py @@ -0,0 +1,96 @@ +######################################################################### +# +# Copyright (C) 2023 Open Source Geospatial Foundation - all rights reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +######################################################################### + +import logging + +from django.db.models import Count + +from geonode.base.models import HierarchicalKeyword +from geonode.facets.models import FacetProvider, DEFAULT_FACET_PAGE_SIZE, FACET_TYPE_KEYWORD + +logger = logging.getLogger(__name__) + + +class KeywordFacetProvider(FacetProvider): + """ + Implements faceting for resource's keywords + """ + + @property + def name(self) -> str: + return "keyword" + + def get_info(self, lang="en") -> dict: + return { + "name": self.name, + "key": "filter{keywords.slug.in}", + "label": "Keyword", + "type": FACET_TYPE_KEYWORD, + "order": 2, + } + + def get_facet_items( + self, + queryset=None, + start: int = 0, + end: int = DEFAULT_FACET_PAGE_SIZE, + lang="en", + topic_contains: str = None, + ) -> (int, list): + logger.debug("Retrieving facets for %s", self.name) + + q = queryset.values("keywords__slug", "keywords__name").filter(keywords__isnull=False) + if topic_contains: + q = q.filter(keywords__name=topic_contains) + q = q.annotate(count=Count("keywords__slug")).order_by("-count") + + cnt = q.count() + + logger.info("Found %d facets for %s", cnt, self.name) + logger.debug(" ---> %s\n\n", q.query) + logger.debug(" ---> %r\n\n", q.all()) + + topics = [ + { + "key": r["keywords__slug"], + "label": r["keywords__name"], + "count": r["count"], + } + for r in q[start:end].all() + ] + + return cnt, topics + + def get_topics(self, keys: list, lang="en", **kwargs) -> list: + q = HierarchicalKeyword.objects.filter(slug__in=keys).values("slug", "name") + + logger.debug(" ---> %s\n\n", q.query) + logger.debug(" ---> %r\n\n", q.all()) + + return [ + { + "key": r["slug"], + "label": r["name"], + } + for r in q.all() + ] + + @classmethod + def register(cls, registry, **kwargs) -> None: + registry.register_facet_provider(KeywordFacetProvider()) diff --git a/geonode/facets/tests.py b/geonode/facets/tests.py index 156c4908e50..cc6d9a8e0ec 100644 --- a/geonode/facets/tests.py +++ b/geonode/facets/tests.py @@ -166,9 +166,9 @@ def test_facets_base(self): obj = json.loads(res.content) self.assertIn("facets", obj) facets_list = obj["facets"] - self.assertEqual(7, len(facets_list)) + self.assertEqual(8, len(facets_list)) fmap = self._facets_to_map(facets_list) - for name in ("category", "owner", "t_0", "t_1", "featured", "resourcetype"): + for name in ("category", "owner", "t_0", "t_1", "featured", "resourcetype", "keyword"): self.assertIn(name, fmap) def test_facets_rich(self): @@ -186,7 +186,7 @@ def test_facets_rich(self): obj = json.loads(res.content) facets_list = obj["facets"] - self.assertEqual(7, len(facets_list)) + self.assertEqual(8, len(facets_list)) fmap = self._facets_to_map(facets_list) for expected in ( { diff --git a/geonode/settings.py b/geonode/settings.py index 9d6a270f138..8afedc72c17 100644 --- a/geonode/settings.py +++ b/geonode/settings.py @@ -2323,6 +2323,7 @@ def get_geonode_catalogue_service(): "geonode.facets.providers.baseinfo.ResourceTypeFacetProvider", "geonode.facets.providers.baseinfo.FeaturedFacetProvider", "geonode.facets.providers.category.CategoryFacetProvider", + "geonode.facets.providers.keyword.KeywordFacetProvider", "geonode.facets.providers.users.OwnerFacetProvider", "geonode.facets.providers.thesaurus.ThesaurusFacetProvider", "geonode.facets.providers.region.RegionFacetProvider",