Skip to content

Commit ed9e56b

Browse files
github-actions[bot]mattiagiupponiafabiani
authored
[Fixes #10214] metadata_only filter not working properly (#10215) (#10269)
* [Fixes #10214] metadata_only filter not working properly * [Fixes #10214] metadata_only filter not working properly * [Fixes #10214] metadata_only filter not working properly Co-authored-by: Alessio Fabiani <alessio.fabiani@geosolutionsgroup.com> Co-authored-by: mattiagiupponi <51856725+mattiagiupponi@users.noreply.github.com> Co-authored-by: Alessio Fabiani <alessio.fabiani@geosolutionsgroup.com>
1 parent e707b6a commit ed9e56b

File tree

4 files changed

+83
-43
lines changed

4 files changed

+83
-43
lines changed

geonode/base/api/permissions.py

+16-19
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,17 @@
1717
#
1818
#########################################################################
1919
import logging
20+
from django.conf import settings
2021
from django.contrib.auth import get_user_model
2122
from django.shortcuts import get_object_or_404
2223

2324
from rest_framework import permissions
2425
from rest_framework.filters import BaseFilterBackend
2526
from geonode.security.permissions import BASIC_MANAGE_PERMISSIONS, DOWNLOAD_PERMISSIONS, EDIT_PERMISSIONS, VIEW_PERMISSIONS
26-
27+
from distutils.util import strtobool
2728
from geonode.security.utils import (
2829
get_users_with_perms,
29-
get_resources_with_perms)
30+
get_visible_resources)
3031
from geonode.groups.models import GroupProfile
3132
from rest_framework.permissions import DjangoModelPermissions
3233
from guardian.shortcuts import get_objects_for_user
@@ -194,26 +195,22 @@ class ResourceBasePermissionsFilter(BaseFilterBackend):
194195
A filter backend that limits results to those where the requesting user
195196
has read object level permissions.
196197
"""
197-
shortcut_kwargs = {
198-
'accept_global_perms': True,
199-
}
200198

201199
def filter_queryset(self, request, queryset, view):
202-
# We want to defer this import until runtime, rather than import-time.
203-
# See https://github.com/encode/django-rest-framework/issues/4608
204-
# (Also see #1624 for why we need to make this import explicitly)
205-
206-
user = request.user
207-
# perm_format = '%(app_label)s.view_%(model_name)s'
208-
# permission = self.perm_format % {
209-
# 'app_label': queryset.model._meta.app_label,
210-
# 'model_name': queryset.model._meta.model_name,
211-
# }
212-
213-
obj_with_perms = get_resources_with_perms(user, shortcut_kwargs=self.shortcut_kwargs)
214-
logger.debug(f" user: {user} -- obj_with_perms: {obj_with_perms}")
215200

216-
return queryset.filter(id__in=obj_with_perms.values('id'))
201+
try:
202+
metadata_only = strtobool(request.query_params.get("filter{metadata_only}", "None"))
203+
except Exception:
204+
metadata_only = None
205+
206+
return get_visible_resources(
207+
queryset,
208+
request.user,
209+
metadata_only=metadata_only,
210+
admin_approval_required=settings.ADMIN_MODERATE_UPLOADS,
211+
unpublished_not_visible=settings.RESOURCE_PUBLISHING,
212+
private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES
213+
)
217214

218215

219216
class UserHasPerms(DjangoModelPermissions):

geonode/base/api/tests.py

+30-21
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,13 @@ def test_base_resources(self):
436436
response = self.client.get(url, format='json')
437437
self.assertEqual(response.status_code, 200)
438438
self.assertEqual(len(response.data), 5)
439+
self.assertEqual(response.data['total'], 28)
440+
441+
url = "{base_url}?{params}".format(base_url=reverse('base-resources-list'), params="filter{metadata_only}=false")
442+
# Anonymous
443+
response = self.client.get(url, format='json')
444+
self.assertEqual(response.status_code, 200)
445+
self.assertEqual(len(response.data), 5)
439446
self.assertEqual(response.data['total'], 26)
440447
response.data['resources'][0].get('executions')
441448
# Pagination
@@ -494,7 +501,7 @@ def test_base_resources(self):
494501
# Admin
495502
self.assertTrue(self.client.login(username='admin', password='admin'))
496503

497-
response = self.client.get(f"{url}?page_size=17", format='json')
504+
response = self.client.get(f"{url}&page_size=17", format='json')
498505
self.assertEqual(response.status_code, 200)
499506
self.assertEqual(len(response.data), 5)
500507
self.assertEqual(response.data['total'], 26)
@@ -505,25 +512,27 @@ def test_base_resources(self):
505512
resource = ResourceBase.objects.filter(owner__username='bobby').first()
506513
self.assertEqual(resource.owner.username, 'bobby')
507514
# Admin
508-
response = self.client.get(f"{url}/{resource.id}/", format='json')
515+
url_with_id = "{base_url}/{res_id}?{params}".format(base_url=reverse('base-resources-list'), res_id=resource.id, params="filter{metadata_only}=false")
516+
517+
response = self.client.get(f"{url_with_id}", format='json')
509518
self.assertEqual(response.data['resource']['state'], enumerations.STATE_PROCESSED)
510519
self.assertEqual(response.data['resource']['sourcetype'], enumerations.SOURCE_TYPE_LOCAL)
511520
self.assertTrue('change_resourcebase' in list(response.data['resource']['perms']))
512521
# Annonymous
513522
self.assertIsNone(self.client.logout())
514-
response = self.client.get(f"{url}/{resource.id}/", format='json')
523+
response = self.client.get(f"{url_with_id}", format='json')
515524
self.assertFalse('change_resourcebase' in list(response.data['resource']['perms']))
516525
# user owner
517526
self.assertTrue(self.client.login(username='bobby', password='bob'))
518-
response = self.client.get(f"{url}/{resource.id}/", format='json')
527+
response = self.client.get(f"{url_with_id}", format='json')
519528
self.assertTrue('change_resourcebase' in list(response.data['resource']['perms']))
520529
# user not owner and not assigned
521530
self.assertTrue(self.client.login(username='norman', password='norman'))
522-
response = self.client.get(f"{url}/{resource.id}/", format='json')
531+
response = self.client.get(f"{url_with_id}", format='json')
523532
self.assertFalse('change_resourcebase' in list(response.data['resource']['perms']))
524533
# Check executions are returned when deffered
525534
# all resources
526-
response = self.client.get(f'{url}?include[]=executions', format='json')
535+
response = self.client.get(f'{url}&include[]=executions', format='json')
527536
self.assertEqual(response.status_code, 200)
528537
self.assertIsNotNone(response.data['resources'][0].get('executions'))
529538
# specific resource
@@ -555,7 +564,7 @@ def test_base_resources(self):
555564
)
556565
}]
557566
self.assertTrue(self.client.login(username='bobby', password='bob'))
558-
response = self.client.get(f'{url}/{resource.id}?include[]=executions', format='json')
567+
response = self.client.get(f'{url_with_id}&include[]=executions', format='json')
559568
self.assertEqual(response.status_code, 200)
560569
self.assertIsNotNone(response.data['resource'].get('executions'))
561570
self.assertEqual(response.data['resource'].get('executions'), expected_executions_results)
@@ -567,7 +576,7 @@ def test_base_resources(self):
567576
self.assertEqual(6, resource.tkeywords.count())
568577
# Admin
569578
self.assertTrue(self.client.login(username='admin', password='admin'))
570-
response = self.client.get(f"{url}/{resource.id}/", format='json')
579+
response = self.client.get(f"{url_with_id}", format='json')
571580
self.assertIsNotNone(response.data['resource']['tkeywords'])
572581
self.assertEqual(6, len(response.data['resource']['tkeywords']))
573582
self.assertListEqual(
@@ -721,15 +730,15 @@ def test_filter_resources(self):
721730
self.assertTrue(self.client.login(username='admin', password='admin'))
722731

723732
# Filter by owner == bobby
724-
response = self.client.get(f"{url}?filter{{owner.username}}=bobby", format='json')
733+
response = self.client.get(f"{url}?filter{{owner.username}}=bobby&filter{{metadata_only}}=false", format='json')
725734
self.assertEqual(response.status_code, 200)
726735
self.assertEqual(len(response.data), 5)
727736
self.assertEqual(response.data['total'], 3)
728737
# Pagination
729738
self.assertEqual(len(response.data['resources']), 3)
730739

731740
# Filter by resource_type == document
732-
response = self.client.get(f"{url}?filter{{resource_type}}=document", format='json')
741+
response = self.client.get(f"{url}?filter{{resource_type}}=document&filter{{metadata_only}}=false", format='json')
733742
self.assertEqual(response.status_code, 200)
734743
self.assertEqual(len(response.data), 5)
735744
self.assertEqual(response.data['total'], 9)
@@ -738,7 +747,7 @@ def test_filter_resources(self):
738747

739748
# Filter by resource_type == layer and title like 'common morx'
740749
response = self.client.get(
741-
f"{url}?filter{{resource_type}}=dataset&filter{{title.icontains}}=common morx", format='json')
750+
f"{url}?filter{{resource_type}}=dataset&filter{{title.icontains}}=common morx&filter{{metadata_only}}=false", format='json')
742751
self.assertEqual(response.status_code, 200)
743752
self.assertEqual(len(response.data), 5)
744753
self.assertEqual(response.data['total'], 1)
@@ -747,7 +756,7 @@ def test_filter_resources(self):
747756

748757
# Filter by Keywords
749758
response = self.client.get(
750-
f"{url}?filter{{keywords.name}}=here", format='json')
759+
f"{url}?filter{{keywords.name}}=here&filter{{metadata_only}}=false", format='json')
751760
self.assertEqual(response.status_code, 200)
752761
self.assertEqual(len(response.data), 5)
753762
self.assertEqual(response.data['total'], 1)
@@ -756,7 +765,7 @@ def test_filter_resources(self):
756765

757766
# Filter by Metadata Regions
758767
response = self.client.get(
759-
f"{url}?filter{{regions.name.icontains}}=Italy", format='json')
768+
f"{url}?filter{{regions.name.icontains}}=Italy&filter{{metadata_only}}=false", format='json')
760769
self.assertEqual(response.status_code, 200)
761770
self.assertEqual(len(response.data), 5)
762771
self.assertEqual(response.data['total'], 0)
@@ -765,29 +774,29 @@ def test_filter_resources(self):
765774

766775
# Filter by Metadata Categories
767776
response = self.client.get(
768-
f"{url}?filter{{category.identifier}}=elevation", format='json')
777+
f"{url}?filter{{category.identifier}}=elevation&filter{{metadata_only}}=false", format='json')
769778
self.assertEqual(response.status_code, 200)
770779
self.assertEqual(len(response.data), 5)
771780
self.assertEqual(response.data['total'], 6)
772781
# Pagination
773782
self.assertEqual(len(response.data['resources']), 6)
774783

775784
# Extent Filter
776-
response = self.client.get(f"{url}?page_size=26&extent=-180,-90,180,90", format='json')
785+
response = self.client.get(f"{url}?page_size=26&extent=-180,-90,180,90&filter{{metadata_only}}=false", format='json')
777786
self.assertEqual(response.status_code, 200)
778787
self.assertEqual(len(response.data), 5)
779788
self.assertEqual(response.data['total'], 26)
780789
# Pagination
781790
self.assertEqual(len(response.data['resources']), 26)
782791

783-
response = self.client.get(f"{url}?page_size=26&extent=0,0,100,100", format='json')
792+
response = self.client.get(f"{url}?page_size=26&extent=0,0,100,100&filter{{metadata_only}}=false", format='json')
784793
self.assertEqual(response.status_code, 200)
785794
self.assertEqual(len(response.data), 5)
786795
self.assertEqual(response.data['total'], 26)
787796
# Pagination
788797
self.assertEqual(len(response.data['resources']), 26)
789798

790-
response = self.client.get(f"{url}?page_size=26&extent=-10,-10,-1,-1", format='json')
799+
response = self.client.get(f"{url}?page_size=26&extent=-10,-10,-1,-1&filter{{metadata_only}}=false", format='json')
791800
self.assertEqual(response.status_code, 200)
792801
self.assertEqual(len(response.data), 5)
793802
self.assertEqual(response.data['total'], 12)
@@ -797,7 +806,7 @@ def test_filter_resources(self):
797806
# Extent Filter: Crossing Dateline
798807
extent = "-180.0000,56.9689,-162.5977,70.7435,155.9180,56.9689,180.0000,70.7435"
799808
response = self.client.get(
800-
f"{url}?page_size=26&extent={extent}", format='json')
809+
f"{url}?page_size=26&extent={extent}&filter{{metadata_only}}=false", format='json')
801810
self.assertEqual(response.status_code, 200)
802811
self.assertEqual(len(response.data), 5)
803812
self.assertEqual(response.data['total'], 12)
@@ -816,7 +825,7 @@ def test_sort_resources(self):
816825
f"{url}?sort[]=title", format='json')
817826
self.assertEqual(response.status_code, 200)
818827
self.assertEqual(len(response.data), 5)
819-
self.assertEqual(response.data['total'], 26)
828+
self.assertEqual(response.data['total'], 28)
820829
# Pagination
821830
self.assertEqual(len(response.data['resources']), 10)
822831

@@ -830,7 +839,7 @@ def test_sort_resources(self):
830839
f"{url}?sort[]=-title", format='json')
831840
self.assertEqual(response.status_code, 200)
832841
self.assertEqual(len(response.data), 5)
833-
self.assertEqual(response.data['total'], 26)
842+
self.assertEqual(response.data['total'], 28)
834843
# Pagination
835844
self.assertEqual(len(response.data['resources']), 10)
836845

@@ -1663,7 +1672,7 @@ def test_embed_urls(self):
16631672

16641673
resources = ResourceBase.objects.all()
16651674
for resource in resources:
1666-
url = reverse('base-resources-detail', kwargs={'pk': resource.pk})
1675+
url = "{base_url}?{params}".format(base_url=reverse('base-resources-detail', kwargs={'pk': resource.pk}), params="filter{metadata_only}=false")
16671676
response = self.client.get(url, format='json')
16681677
if resource.title.endswith('metadata true'):
16691678
self.assertEqual(response.status_code, 404)

geonode/security/tests.py

+32
Original file line numberDiff line numberDiff line change
@@ -1505,6 +1505,38 @@ def test_get_visible_resources_should_return_updated_resource_with_metadata_only
15051505
actual = get_visible_resources(queryset=layers, user=get_user_model().objects.get(username=self.user))
15061506
self.assertEqual(layers.filter(dirty_state=False).count(), len(actual))
15071507

1508+
def test_get_visible_resources_should_return_resource_with_metadata_only_true(self):
1509+
'''
1510+
If metadata only is provided, it should return only the metadata resources
1511+
'''
1512+
try:
1513+
dataset = create_single_dataset("dataset_with_metadata_only_True")
1514+
dataset.metadata_only = True
1515+
dataset.save()
1516+
1517+
layers = Dataset.objects.all()
1518+
actual = get_visible_resources(queryset=layers, metadata_only=True, user=get_user_model().objects.get(username=self.user))
1519+
self.assertEqual(1, actual.count())
1520+
finally:
1521+
if dataset:
1522+
dataset.delete()
1523+
1524+
def test_get_visible_resources_should_return_resource_with_metadata_only_none(self):
1525+
'''
1526+
If metadata only is provided, it should return only the metadata resources
1527+
'''
1528+
try:
1529+
dataset = create_single_dataset("dataset_with_metadata_only_True")
1530+
dataset.metadata_only = True
1531+
dataset.save()
1532+
1533+
layers = Dataset.objects.all()
1534+
actual = get_visible_resources(queryset=layers, metadata_only=None, user=get_user_model().objects.get(username=self.user))
1535+
self.assertEqual(layers.count(), actual.count())
1536+
finally:
1537+
if dataset:
1538+
dataset.delete()
1539+
15081540
@override_settings(
15091541
ADMIN_MODERATE_UPLOADS=True,
15101542
RESOURCE_PUBLISHING=True,

geonode/security/utils.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,11 @@ def get_visible_resources(queryset,
7878
except Exception:
7979
pass
8080

81-
# Hide Dirty State Resources
82-
filter_set = queryset.filter(
83-
Q(dirty_state=False) & Q(metadata_only=metadata_only))
81+
filter_set = queryset.filter(dirty_state=False)
82+
83+
if metadata_only is not None:
84+
# Hide Dirty State Resources
85+
filter_set = filter_set.filter(metadata_only=metadata_only)
8486

8587
if not is_admin:
8688
if user:

0 commit comments

Comments
 (0)