Skip to content

Commit

Permalink
[Backport #7057] ResourceBase for metadata-only resources (#7134)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattiagiupponi authored Mar 22, 2021
1 parent 65a279e commit 5b81328
Show file tree
Hide file tree
Showing 12 changed files with 253 additions and 24 deletions.
13 changes: 8 additions & 5 deletions geonode/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ def dehydrate_layers_count(self, bundle):
request = bundle.request
obj_with_perms = get_objects_for_user(request.user,
'base.view_resourcebase').filter(polymorphic_ctype__model='layer')
filter_set = bundle.obj.resourcebase_set.filter(id__in=obj_with_perms.values('id'))
filter_set = bundle.obj.resourcebase_set.filter(id__in=obj_with_perms.values('id')).filter(metadata_only=False)

if not settings.SKIP_PERMS_FILTER:
filter_set = get_visible_resources(
Expand Down Expand Up @@ -432,7 +432,7 @@ def dehydrate(self, bundle):
request = bundle.request
counts = _get_resource_counts(
request,
resourcebase_filter_kwargs={'group': bundle.obj}
resourcebase_filter_kwargs={'group': bundle.obj, 'metadata_only': False}
)

bundle.data.update(resource_counts=counts)
Expand Down Expand Up @@ -506,17 +506,20 @@ def dehydrate_email(self, bundle):
def dehydrate_layers_count(self, bundle):
obj_with_perms = get_objects_for_user(bundle.request.user,
'base.view_resourcebase').filter(polymorphic_ctype__model='layer')
return bundle.obj.resourcebase_set.filter(id__in=obj_with_perms.values('id')).distinct().count()
return bundle.obj.resourcebase_set.filter(id__in=obj_with_perms.values('id')).filter(metadata_only=False)\
.distinct().count()

def dehydrate_maps_count(self, bundle):
obj_with_perms = get_objects_for_user(bundle.request.user,
'base.view_resourcebase').filter(polymorphic_ctype__model='map')
return bundle.obj.resourcebase_set.filter(id__in=obj_with_perms.values('id')).distinct().count()
return bundle.obj.resourcebase_set.filter(id__in=obj_with_perms.values('id')).filter(metadata_only=False)\
.distinct().count()

def dehydrate_documents_count(self, bundle):
obj_with_perms = get_objects_for_user(bundle.request.user,
'base.view_resourcebase').filter(polymorphic_ctype__model='document')
return bundle.obj.resourcebase_set.filter(id__in=obj_with_perms.values('id')).distinct().count()
return bundle.obj.resourcebase_set.filter(id__in=obj_with_perms.values('id')).filter(metadata_only=False)\
.distinct().count()

def dehydrate_avatar_100(self, bundle):
return avatar_url(bundle.obj, 240)
Expand Down
23 changes: 23 additions & 0 deletions geonode/api/resourcebase_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ class CommonModelApi(ModelResource):
'is_approved',
'is_published',
'dirty_state',
'metadata_only'
]

def build_filters(self, filters=None, ignore_bad_filters=False, **kwargs):
Expand Down Expand Up @@ -722,6 +723,13 @@ class LayerResource(CommonModelApi):
null=True,
use_in='detail')

def build_filters(self, filters=None, ignore_bad_filters=False, **kwargs):
_filters = filters.copy()
metadata_only = _filters.pop('metadata_only', False)
orm_filters = super(LayerResource, self).build_filters(_filters)
orm_filters['metadata_only'] = False if not metadata_only else metadata_only[0]
return orm_filters

def format_objects(self, objects):
"""
Formats the object.
Expand Down Expand Up @@ -865,13 +873,21 @@ class Meta(CommonMetaApi):
'id': ALL,
'name': ALL,
'alternate': ALL,
'metadata_only': ALL
})


class MapResource(CommonModelApi):

"""Maps API"""

def build_filters(self, filters=None, ignore_bad_filters=False, **kwargs):
_filters = filters.copy()
metadata_only = _filters.pop('metadata_only', False)
orm_filters = super(MapResource, self).build_filters(_filters)
orm_filters['metadata_only'] = False if not metadata_only else metadata_only[0]
return orm_filters

def format_objects(self, objects):
"""
Formats the objects and provides reference to list of layers in map
Expand Down Expand Up @@ -1013,6 +1029,13 @@ class DocumentResource(CommonModelApi):

"""Documents API"""

def build_filters(self, filters=None, ignore_bad_filters=False, **kwargs):
_filters = filters.copy()
metadata_only = _filters.pop('metadata_only', False)
orm_filters = super(DocumentResource, self).build_filters(_filters)
orm_filters['metadata_only'] = False if not metadata_only else metadata_only[0]
return orm_filters

def format_objects(self, objects):
"""
Formats the objects and provides reference to list of layers in map
Expand Down
146 changes: 145 additions & 1 deletion geonode/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#########################################################################
from geonode.maps.models import Map
from geonode.documents.models import Document
from unittest.mock import patch
from django.conf import settings

Expand Down Expand Up @@ -541,7 +543,7 @@ class ThesaurusKeywordResourceTests(ResourceTestCaseMixin, GeoNodeBaseTestSuppor

def setUp(self):
super(ThesaurusKeywordResourceTests, self).setUp()

all_public()
self.list_url = reverse("api_dispatch_list", kwargs={"api_name": "api", "resource_name": "thesaurus/keywords"})

def test_api_will_return_a_valid_json_response(self):
Expand Down Expand Up @@ -610,3 +612,145 @@ def test_will_return_default_keyword_label_for_not_existing_lang(self, lang):
actual_labels = [x["alt_label"] for x in self.deserialize(resp)["objects"]]
self.assertValidJSONResponse(resp)
self.assertListEqual(expected_labels, actual_labels)


class LayerResourceTests(ResourceTestCaseMixin, GeoNodeBaseTestSupport):
fixtures = [
'initial_data.json',
'group_test_data.json',
'default_oauth_apps.json'
]

def setUp(self):
super(LayerResourceTests, self).setUp()
self.user = get_user_model().objects.get(username="admin")
self.list_url = reverse(
'api_dispatch_list',
kwargs={
'api_name': 'api',
'resource_name': 'layers'})
all_public()
self.token = get_or_create_token(self.user)
self.auth_header = 'Bearer {}'.format(self.token)

def test_the_api_should_return_all_layers_with_metadata_false(self):
resp = self.api_client.get(self.list_url, authentication=self.auth_header)
self.assertValidJSONResponse(resp)
self.assertEqual(8, resp.json()["meta"]["total_count"])

def test_the_api_should_return_all_layers_with_metadata_true(self):
url = f"{self.list_url}?metadata_only=True"
resp = self.api_client.get(url, authentication=self.auth_header)
self.assertValidJSONResponse(resp)
self.assertEqual(1, resp.json()["meta"]["total_count"])


class DocumentResourceTests(ResourceTestCaseMixin, GeoNodeBaseTestSupport):
fixtures = [
'initial_data.json',
'group_test_data.json',
'default_oauth_apps.json'
]

def setUp(self):
super(DocumentResourceTests, self).setUp()
all_public()
self.user = get_user_model().objects.get(username="admin")
self.list_url = reverse(
'api_dispatch_list',
kwargs={
'api_name': 'api',
'resource_name': 'documents'})

def test_the_api_should_return_all_documents_with_metadata_false(self):
resp = self.api_client.get(self.list_url)
self.assertValidJSONResponse(resp)
self.assertEqual(resp.json()["meta"]["total_count"], 9)

def test_the_api_should_return_all_documents_with_metadata_true(self):
url = f"{self.list_url}?metadata_only=True"
resp = self.api_client.get(url)
self.assertValidJSONResponse(resp)
self.assertEqual(resp.json()["meta"]["total_count"], 1)


class MapResourceTests(ResourceTestCaseMixin, GeoNodeBaseTestSupport):
fixtures = [
'initial_data.json',
'group_test_data.json',
'default_oauth_apps.json'
]

def setUp(self):
super(MapResourceTests, self).setUp()
all_public()
self.user = get_user_model().objects.get(username="admin")
self.list_url = reverse(
'api_dispatch_list',
kwargs={
'api_name': 'api',
'resource_name': 'maps'})

def test_the_api_should_return_all_maps_with_metadata_false(self):
resp = self.api_client.get(self.list_url)
self.assertValidJSONResponse(resp)
self.assertEqual(resp.json()["meta"]["total_count"], 9)

def test_the_api_should_return_all_maps_with_metadata_true(self):
url = f"{self.list_url}?metadata_only=True"
resp = self.api_client.get(url)
self.assertValidJSONResponse(resp)
self.assertEqual(resp.json()["meta"]["total_count"], 1)


class TopicCategoryResourceTest(ResourceTestCaseMixin, GeoNodeBaseTestSupport):
fixtures = [
'initial_data.json',
'group_test_data.json',
'default_oauth_apps.json'
]

def setUp(self):
super(TopicCategoryResourceTest, self).setUp()
self.user = get_user_model().objects.get(username="admin")
self.list_url = reverse(
'api_dispatch_list',
kwargs={
'api_name': 'api',
'resource_name': 'categories'})

def test_the_api_should_return_all_maps_with_metadata_false(self):
url = f"{self.list_url}?type=map"
resp = self.api_client.get(url)
self.assertValidJSONResponse(resp)
actual = sum([x['count'] for x in resp.json()['objects']])
self.assertEqual(9, actual)

def test_the_api_should_return_all_maps_with_metadata_true(self):
x = Map.objects.get(title='map metadata true')
x.metadata_only = False
x.save()
url = f"{self.list_url}?type=map"
resp = self.api_client.get(url)
self.assertValidJSONResponse(resp)
# by adding a new layer, the total should increase
actual = sum([x['count'] for x in resp.json()['objects']])
self.assertEqual(10, actual)

def test_the_api_should_return_all_document_with_metadata_false(self):
url = f"{self.list_url}?type=document"
resp = self.api_client.get(url)
self.assertValidJSONResponse(resp)
actual = sum([x['count'] for x in resp.json()['objects']])
self.assertEqual(9, actual)

def test_the_api_should_return_all_document_with_metadata_true(self):
x = Document.objects.get(title='doc metadata true')
x.metadata_only = False
x.save()
url = f"{self.list_url}?type=document"
resp = self.api_client.get(url)
self.assertValidJSONResponse(resp)
# by adding a new layer, the total should increase
actual = sum([x['count'] for x in resp.json()['objects']])
self.assertEqual(10, actual)
3 changes: 2 additions & 1 deletion geonode/base/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ def __init__(self, *args, **kwargs):
self.fields['raw_constraints_other'] = serializers.CharField(read_only=True)
self.fields['raw_supplemental_information'] = serializers.CharField(read_only=True)
self.fields['raw_data_quality_statement'] = serializers.CharField(read_only=True)
self.fields['metadata_only'] = serializers.BooleanField()

self.fields['embed_url'] = EmbedUrlField()
self.fields['thumbnail_url'] = ThumbnailUrlField()
Expand Down Expand Up @@ -289,7 +290,7 @@ class Meta:
'popular_count', 'share_count', 'rating', 'featured', 'is_published', 'is_approved',
'detail_url', 'embed_url', 'created', 'last_updated',
'raw_abstract', 'raw_purpose', 'raw_constraints_other',
'raw_supplemental_information', 'raw_data_quality_statement'
'raw_supplemental_information', 'raw_data_quality_statement', 'metadata_only'
# TODO
# csw_typename, csw_schema, csw_mdsource, csw_insert_date, csw_type, csw_anytext, csw_wkt_geometry,
# metadata_uploaded, metadata_uploaded_preserve, metadata_xml,
Expand Down
25 changes: 14 additions & 11 deletions geonode/base/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,14 +533,17 @@ def test_embed_urls(self):
for resource in resources:
url = reverse('base-resources-detail', kwargs={'pk': resource.pk})
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, 200)
self.assertEqual(int(response.data['resource']['pk']), int(resource.pk))
embed_url = response.data['resource']['embed_url']
self.assertIsNotNone(embed_url)

instance = resource.get_real_instance()
if hasattr(instance, 'embed_url'):
if instance.embed_url != NotImplemented:
self.assertEqual(instance.embed_url, embed_url)
else:
self.assertEqual("", embed_url)
if resource.title.endswith('metadata true'):
self.assertEqual(response.status_code, 404)
else:
self.assertEqual(response.status_code, 200)
self.assertEqual(int(response.data['resource']['pk']), int(resource.pk))
embed_url = response.data['resource']['embed_url']
self.assertIsNotNone(embed_url)

instance = resource.get_real_instance()
if hasattr(instance, 'embed_url'):
if instance.embed_url != NotImplemented:
self.assertEqual(instance.embed_url, embed_url)
else:
self.assertEqual("", embed_url)
18 changes: 18 additions & 0 deletions geonode/base/migrations/0057_resourcebase_metadata_only.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.2.16 on 2021-03-10 11:03

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('base', '0056_resourcebase_ll_bbox_polygon'),
]

operations = [
migrations.AddField(
model_name='resourcebase',
name='metadata_only',
field=models.BooleanField(default=False, help_text='If true, will be excluded from search', verbose_name='Metadata'),
),
]
5 changes: 5 additions & 0 deletions geonode/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,11 @@ class ResourceBase(PolymorphicModel, PermissionLevelMixin, ItemBase):
blank=True,
null=True)

metadata_only = models.BooleanField(
_("Metadata"),
default=False,
help_text=_('If true, will be excluded from search'))

__is_approved = False
__is_published = False

Expand Down
Loading

0 comments on commit 5b81328

Please sign in to comment.