Skip to content

Commit

Permalink
[Backport to 3.2.x][Fixes #8610] API v2 does not return keywords belo… (
Browse files Browse the repository at this point in the history
#8626) (#8632)

* [Backport to 3.3.x][Fixes #8610] API v2 does not return keywords belonging to thesauri

* [CircleCI] Fix and improve tests

(cherry picked from commit 70cfe23)

# Conflicts:
#	geonode/base/api/serializers.py
  • Loading branch information
Alessio Fabiani authored Jan 18, 2022
1 parent 900a679 commit 25a3265
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 17 deletions.
62 changes: 49 additions & 13 deletions geonode/base/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#########################################################################
from slugify import slugify
from urllib.parse import urljoin

from django.conf import settings
Expand All @@ -43,6 +44,7 @@
TopicCategory,
SpatialRepresentationType,
ThesaurusKeyword,
ThesaurusKeywordLabel
)
from geonode.groups.models import (
GroupCategory,
Expand All @@ -61,14 +63,15 @@ class BaseDynamicModelSerializer(DynamicModelSerializer):

def to_representation(self, instance):
data = super(BaseDynamicModelSerializer, self).to_representation(instance)
try:
path = reverse(self.Meta.view_name)
if not path.endswith('/'):
path = f"{path}/"
url = urljoin(path, str(instance.pk))
data['link'] = build_absolute_uri(url)
except NoReverseMatch as e:
logger.exception(e)
if not isinstance(data, int):
try:
path = reverse(self.Meta.view_name)
if not path.endswith('/'):
path = f"{path}/"
url = urljoin(path, str(instance.pk))
data['link'] = build_absolute_uri(url)
except (TypeError, NoReverseMatch) as e:
logger.exception(e)
return data


Expand Down Expand Up @@ -162,6 +165,33 @@ def to_representation(self, value):
return {'name': value.name, 'slug': value.slug}


class _ThesaurusKeywordSerializerMixIn:

def to_representation(self, value):
_i18n = {}
for _i18n_label in ThesaurusKeywordLabel.objects.filter(keyword__id=value.id).iterator():
_i18n[_i18n_label.lang] = _i18n_label.label
return {
'name': value.alt_label,
'slug': slugify(value.about),
'uri': value.about,
'thesaurus': {
'name': value.thesaurus.title,
'slug': value.thesaurus.identifier,
'uri': value.thesaurus.about
},
'i18n': _i18n
}


class SimpleThesaurusKeywordSerializer(_ThesaurusKeywordSerializerMixIn, DynamicModelSerializer):

class Meta:
model = ThesaurusKeyword
name = 'ThesaurusKeyword'
fields = ('alt_label', )


class SimpleRegionSerializer(DynamicModelSerializer):

class Meta:
Expand Down Expand Up @@ -339,6 +369,8 @@ def __init__(self, *args, **kwargs):
self.fields['thumbnail_url'] = ThumbnailUrlField()
self.fields['keywords'] = DynamicRelationField(
SimpleHierarchicalKeywordSerializer, embed=False, many=True)
self.fields['tkeywords'] = DynamicRelationField(
SimpleThesaurusKeywordSerializer, embed=False, many=True)
self.fields['regions'] = DynamicRelationField(
SimpleRegionSerializer, embed=True, many=True, read_only=True)
self.fields['category'] = DynamicRelationField(
Expand All @@ -357,7 +389,7 @@ class Meta:
fields = (
'pk', 'uuid', 'resource_type', 'polymorphic_ctype_id', 'perms',
'owner', 'poc', 'metadata_author',
'keywords', 'regions', 'category',
'keywords', 'tkeywords', 'regions', 'category',
'title', 'abstract', 'attribution', 'doi', 'alternate', 'bbox_polygon', 'll_bbox_polygon', 'srid',
'date', 'date_type', 'edition', 'purpose', 'maintenance_frequency',
'restriction_code_type', 'constraints_other', 'license', 'language',
Expand Down Expand Up @@ -402,9 +434,13 @@ def to_representation(self, instance):
'title_filter': request.query_params.get('title__icontains')
}
data = super(BaseResourceCountSerializer, self).to_representation(instance)
count_filter = {self.Meta.count_type: instance}
data['count'] = get_resources_with_perms(
request.user, filter_options).filter(**count_filter).count()
if not isinstance(data, int):
try:
count_filter = {self.Meta.count_type: instance}
data['count'] = get_resources_with_perms(
request.user, filter_options).filter(**count_filter).count()
except (TypeError, NoReverseMatch) as e:
logger.exception(e)
return data


Expand All @@ -418,7 +454,7 @@ class Meta:
fields = '__all__'


class ThesaurusKeywordSerializer(BaseResourceCountSerializer):
class ThesaurusKeywordSerializer(_ThesaurusKeywordSerializerMixIn, BaseResourceCountSerializer):

class Meta:
model = ThesaurusKeyword
Expand Down
92 changes: 90 additions & 2 deletions geonode/base/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,94 @@ def test_base_resources(self):
response = self.client.get(f"{url}/{layer.id}/", format='json')
self.assertTrue('links' in response.data['resource'].keys())

# test 'tkeywords'
try:
for _tkw in ThesaurusKeyword.objects.filter(pk__gte=34):
resource.tkeywords.add(_tkw)
self.assertEqual(6, resource.tkeywords.count())
# Admin
self.assertTrue(self.client.login(username='admin', password='admin'))
response = self.client.get(f"{url}/{resource.id}/", format='json')
self.assertIsNotNone(response.data['resource']['tkeywords'])
self.assertEqual(6, len(response.data['resource']['tkeywords']))
self.assertListEqual(
[
{
'name': '',
'slug': 'http-inspire-ec-europa-eu-theme-37',
'uri': 'http://inspire.ec.europa.eu/theme#37',
'thesaurus': {
'name': 'GEMET - INSPIRE themes, version 1.0',
'slug': 'inspire-theme',
'uri': 'http://inspire.ec.europa.eu/theme'
},
'i18n': {}
},
{
'name': '',
'slug': 'http-localhost-8001-thesaurus-no-about-thesauro-38',
'uri': 'http://localhost:8001//thesaurus/no-about-thesauro#38',
'thesaurus': {
'name': 'Thesauro without the about',
'slug': 'no-about-thesauro',
'uri': ''
},
'i18n': {}
},
{
'name': 'bar_keyword',
'slug': 'http-localhost-8001-thesaurus-no-about-thesauro-bar-keyword',
'uri': 'http://localhost:8001//thesaurus/no-about-thesauro#bar_keyword',
'thesaurus': {
'name': 'Thesauro without the about',
'slug': 'no-about-thesauro', 'uri': ''
},
'i18n': {}
},
{
'name': 'foo_keyword',
'slug': 'http-inspire-ec-europa-eu-theme-foo-keyword',
'uri': 'http://inspire.ec.europa.eu/theme#foo_keyword',
'thesaurus': {
'name': 'GEMET - INSPIRE themes, version 1.0',
'slug': 'inspire-theme',
'uri': 'http://inspire.ec.europa.eu/theme'
},
'i18n': {}
},
{
'name': 'mf',
'slug': 'http-inspire-ec-europa-eu-theme-mf',
'uri': 'http://inspire.ec.europa.eu/theme/mf',
'thesaurus': {
'name': 'GEMET - INSPIRE themes, version 1.0',
'slug': 'inspire-theme',
'uri': 'http://inspire.ec.europa.eu/theme'
},
'i18n': {
'en': 'Meteorological geographical features'
}
},
{
'name': 'us',
'slug': 'http-inspire-ec-europa-eu-theme-us',
'uri': 'http://inspire.ec.europa.eu/theme/us',
'thesaurus': {
'name': 'GEMET - INSPIRE themes, version 1.0',
'slug': 'inspire-theme',
'uri': 'http://inspire.ec.europa.eu/theme'
},
'i18n': {
'en': 'Utility and governmental services'
}
}
],
response.data['resource']['tkeywords']
)
finally:
resource.tkeywords.set(ThesaurusKeyword.objects.none())
self.assertEqual(0, resource.tkeywords.count())

def test_delete_user_with_resource(self):
owner, created = get_user_model().objects.get_or_create(username='delet-owner')
Layer(
Expand Down Expand Up @@ -799,8 +887,8 @@ def test_tkeywords_list(self):
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data['total'], ThesaurusKeyword.objects.count())
# response has link to the response
self.assertTrue('link' in response.data['tkeywords'][0].keys())
# response has uri to the response
self.assertTrue('uri' in response.data['tkeywords'][0].keys())

# Authenticated user
self.assertTrue(self.client.login(username='bobby', password='bob'))
Expand Down
3 changes: 1 addition & 2 deletions geonode/tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,7 @@ def get_web_page(url, username=None, password=None, login_url=None):
try:
pagehandle = urlopen(url)
except HTTPError as e:
msg = ('The server couldn\'t fulfill the request. '
'Error code: %s' % e.status_code)
msg = f'The server couldn\'t fulfill the request. Error code: {e.status_code}'
e.args = (msg,)
raise
except URLError as e:
Expand Down

0 comments on commit 25a3265

Please sign in to comment.