Skip to content

Commit

Permalink
[Backport to 3.3.x][Fixes #9101] Keywords filter only returns the roo…
Browse files Browse the repository at this point in the history
…t nodes of the tree (#9111) (#9121) (#9124)

* [Fixes #9101] Keywords filter only returns the root nodes of the tree

* [CircleCi] Testing Hierarchical Keywords tree

Co-authored-by: Alessio Fabiani <[email protected]>
  • Loading branch information
Alessio Fabiani authored Apr 15, 2022
1 parent e32e904 commit f6c5b71
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 6 deletions.
85 changes: 81 additions & 4 deletions geonode/base/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1074,27 +1074,104 @@ def test_keywords_list(self):
# Anonymous
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data['total'], HierarchicalKeyword.objects.count())
self.assertEqual(response.data['total'], len(HierarchicalKeyword.resource_keywords_tree(None)))

# Admin
self.assertTrue(self.client.login(username='admin', password='admin'))
admin = get_user_model().objects.get(username='admin')
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data['total'], HierarchicalKeyword.objects.count())
self.assertEqual(response.data['total'], len(HierarchicalKeyword.resource_keywords_tree(admin)))
# response has link to the response
self.assertTrue('link' in response.data['keywords'][0].keys())
if response.data['total'] > 0:
self.assertTrue('link' in response.data['keywords'][0].keys())

# Authenticated user
self.assertTrue(self.client.login(username='bobby', password='bob'))
bobby = get_user_model().objects.get(username='bobby')
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data['total'], HierarchicalKeyword.objects.count())
self.assertEqual(response.data['total'], len(HierarchicalKeyword.resource_keywords_tree(bobby)))

# Keywords Filtering
response = self.client.get(f"{url}?filter{{name.icontains}}=Africa", format='json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data['total'], 0)

# Testing Hierarchical Keywords tree
try:
HierarchicalKeyword.objects.filter(slug__in=['a', 'a1', 'a2', 'b', 'b1']).delete()
HierarchicalKeyword.add_root(name='a')
HierarchicalKeyword.add_root(name='b')
a = HierarchicalKeyword.objects.get(slug='a')
b = HierarchicalKeyword.objects.get(slug='b')
a.add_child(name='a1')
a.add_child(name='a2')
b.add_child(name='b1')
resources = ResourceBase.objects.filter(owner__username='bobby')
res1 = resources.first()
res2 = resources.last()
self.assertNotEqual(res1, res2)
res1.keywords.add(HierarchicalKeyword.objects.get(slug='a1'))
res1.keywords.add(HierarchicalKeyword.objects.get(slug='a2'))
res2.keywords.add(HierarchicalKeyword.objects.get(slug='b1'))
resource_keywords = HierarchicalKeyword.resource_keywords_tree(bobby)
logger.error(resource_keywords)

"""
Final api outcome will be something like
[
{
'id': 116,
'text': 'a',
'href': 'a',
'tags': [],
'nodes': [
{
'id': 118,
'text': 'a1',
'href': 'a1',
'tags': [1]
},
{
'id': 119,
'text': 'a2',
'href': 'a2',
'tags': [1]
}
]
},
{
'id': 117,
'text': 'b',
'href': 'b',
'tags': [],
'nodes': [
{
'id': 120,
'text': 'b1',
'href': 'b1',
'tags': [1]
}
]
},
...
]
"""
url = reverse('keywords-list')
# Authenticated user
self.assertTrue(self.client.login(username='bobby', password='bob'))
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, 200)
for _kw in response.data["keywords"]:
if _kw.get('href') in ['a', 'b']:
self.assertListEqual(_kw.get('tags'), [], _kw.get('tags'))
self.assertEqual(len(_kw.get('nodes')), 2)
for _kw_child in _kw.get('nodes'):
self.assertEqual(_kw_child.get('tags')[0], 1)
finally:
HierarchicalKeyword.objects.filter(slug__in=['a', 'a1', 'a2', 'b', 'b1']).delete()

def test_tkeywords_list(self):
"""
Ensure we can access the list of thasaurus keywords.
Expand Down
17 changes: 15 additions & 2 deletions geonode/base/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@
TopicCategorySerializer,
RegionSerializer,
ThesaurusKeywordSerializer,
ExtraMetadataSerializer
)
from .pagination import GeoNodeApiPagination
from geonode.base.api.serializers import ExtraMetadataSerializer
from geonode.base.utils import validate_extra_metadata

import logging
Expand Down Expand Up @@ -193,11 +193,24 @@ class HierarchicalKeywordViewSet(WithDynamicViewSetMixin, ListModelMixin, Retrie
"""
API endpoint that lists hierarchical keywords.
"""

def get_queryset(self):
resource_keywords = HierarchicalKeyword.resource_keywords_tree(self.request.user)

def _get_kw_hrefs(keywords, slugs: list = []):
for obj in keywords:
if obj.get('tags', []):
slugs.append(obj.get('href'))
_get_kw_hrefs(obj.get('nodes', []), slugs)
return slugs

slugs = _get_kw_hrefs(resource_keywords)
return HierarchicalKeyword.objects.filter(slug__in=slugs)

permission_classes = [AllowAny, ]
filter_backends = [
DynamicFilterBackend, DynamicSortingFilter, DynamicSearchFilter
]
queryset = HierarchicalKeyword.objects.all()
serializer_class = HierarchicalKeywordSerializer
pagination_class = GeoNodeApiPagination

Expand Down
1 change: 1 addition & 0 deletions geonode/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ def _keywords_tree_of_a_child(cls, child, tree, newobj):
node = node["nodes"][-1]
else:
node = item_found
node["nodes"] = getattr(node, "nodes", [])

# All leaves appended but a child which is not a leaf may not be added
# again, as a leaf, but only its tag count be updated
Expand Down

0 comments on commit f6c5b71

Please sign in to comment.