Skip to content

Commit

Permalink
[Fixes #10995] Faceting - Some implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
etj committed May 15, 2023
1 parent d479b58 commit bd4eb7b
Show file tree
Hide file tree
Showing 5 changed files with 542 additions and 0 deletions.
83 changes: 83 additions & 0 deletions geonode/facets/providers/category.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#########################################################################
#
# 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 <http://www.gnu.org/licenses/>.
#
#########################################################################

import logging

from django.db.models import Count

from geonode.facets.models import FacetProvider, DEFAULT_FACET_PAGE_SIZE, FACET_TYPE_CATEGORY

logger = logging.getLogger(__name__)


class CategoryFacetProvider(FacetProvider):
"""
Implements faceting for resource's topicCategory
"""

@property
def name(self) -> str:
return "category"

def get_info(self, lang="en") -> dict:
return {
"name": self.name,
"key": "filter{category__identifier}",
"label": "Category",
"type": FACET_TYPE_CATEGORY,
"hierarchical": False,
"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("category__identifier", "category__gn_description", "category__fa_class")
if topic_contains:
q = q.filter(category__gn_description=topic_contains)
q = q.annotate(count=Count("owner")).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["category__identifier"],
"label": r["category__gn_description"],
"count": r["count"],
"fa_class": r["category__fa_class"],
}
for r in q[start:end].all()
]

return cnt, topics

@classmethod
def register(cls, registry, **kwargs) -> None:
registry.register_facet_provider(CategoryFacetProvider())
127 changes: 127 additions & 0 deletions geonode/facets/providers/thesaurus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#########################################################################
#
# 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 <http://www.gnu.org/licenses/>.
#
#########################################################################

import logging

from django.db.models import Count

from geonode.facets.models import FacetProvider, DEFAULT_FACET_PAGE_SIZE, FACET_TYPE_THESAURUS

logger = logging.getLogger(__name__)


class ThesaurusFacetProvider(FacetProvider):
"""
Implements faceting for a given Thesaurus
"""

def __init__(self, identifier, title, order, labels: dict):
self._name = identifier
self.label = title
self.order = order
self.labels = labels

@property
def name(self) -> str:
return self._name

def get_info(self, lang="en") -> dict:
return {
"name": self._name,
"key": "filter{tkeywords}",
"label": self.labels.get(lang, self.label),
"is_localized": self.labels.get(lang, None) is not None,
"type": FACET_TYPE_THESAURUS,
"hierarchical": False,
"order": self.order,
}

def get_facet_items(
self,
queryset=None,
start: int = 0,
end: int = DEFAULT_FACET_PAGE_SIZE,
lang="en",
topic_contains: str = None,
**kwargs,
) -> (int, list):
logger.debug("Retrieving facets for %s", self._name)

filter = {
"tkeywords__thesaurus__identifier": self._name,
"tkeywords__keyword__lang": lang,
}

if topic_contains:
filter["tkeywords__keyword__label__icontains"] = topic_contains

q = (
queryset.filter(**filter)
.values("tkeywords", "tkeywords__keyword__label", "tkeywords__alt_label")
.annotate(count=Count("tkeywords"))
.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["tkeywords"],
"label": r["tkeywords__keyword__label"] or r["tkeywords__alt_label"],
"is_localized": r["tkeywords__keyword__label"] is not None,
"count": r["count"],
}
for r in q[start:end].all()
]

return cnt, topics

@classmethod
def register(cls, registry, **kwargs) -> None:
# registry.register_facet_provider(CategoryFacetProvider())
from geonode.base.models import Thesaurus

# this query return the list of thesaurus X the list of localized titles
q = (
Thesaurus.objects.filter(facet=True)
.values("identifier", "title", "order", "rel_thesaurus__label", "rel_thesaurus__lang")
.order_by("order")
)

# coalesce the localized labels
ret = {}
for r in q.all():
identifier = r["identifier"]
t = ret.get(identifier, None)
if not t:
t = {k: r[k] for k in ("identifier", "title", "order")}
t["labels"] = {}
if r["rel_thesaurus__lang"] and r["rel_thesaurus__label"]:
t["labels"][r["rel_thesaurus__lang"]] = r["rel_thesaurus__label"]
ret[identifier] = t

logger.info("Creating providers for %r", ret)
for t in ret.values():
registry.register_facet_provider(
ThesaurusFacetProvider(t["identifier"], t["title"], t["order"], t["labels"])
)
83 changes: 83 additions & 0 deletions geonode/facets/providers/users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#########################################################################
#
# 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 <http://www.gnu.org/licenses/>.
#
#########################################################################

import logging

from django.db.models import Count

from geonode.facets.models import FacetProvider, DEFAULT_FACET_PAGE_SIZE, FACET_TYPE_USER

logger = logging.getLogger(__name__)


class OwnerFacetProvider(FacetProvider):
"""
Implements faceting for users owner of the resources
"""

@property
def name(self) -> str:
return "owner"

def get_info(self, lang="en") -> dict:
return {
"name": "owner",
"key": "owner",
"label": "Owner",
"type": FACET_TYPE_USER,
"hierarchical": False,
"order": 5,
}

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 OWNER")

q = queryset.values("owner", "owner__username")
if topic_contains:
q = q.filter(owner__username__icontains=topic_contains)
q = q.annotate(count=Count("owner")).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["owner"],
"label": r["owner__username"],
"localized_label": r["owner__username"],
"count": r["count"],
}
for r in q[start:end]
]

return cnt, topics

@classmethod
def register(cls, registry, **kwargs) -> None:
registry.register_facet_provider(OwnerFacetProvider())
Loading

0 comments on commit bd4eb7b

Please sign in to comment.