Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion geonode/base/api/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@


class DynamicSearchFilter(SearchFilter):
# search_fields from the request are restricted to the view's allow-list
def get_search_fields(self, view, request):
return request.GET.getlist("search_fields", [])
allowed = getattr(view, "search_fields", None) or []
return [f for f in request.GET.getlist("search_fields", []) if f in allowed]


class ExtentFilter(BaseFilterBackend):
Expand Down
38 changes: 38 additions & 0 deletions geonode/base/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,44 @@ def test_search_resources(self):
# Pagination
self.assertEqual(len(response.data["resources"]), 1)

def test_search_fields_allow_list(self):
"""
search_fields not allowed by the view are ignored.
"""
term = "no-such-value-b3wf"

def _check(url, allowed, rejected):
total = self.client.get(url, format="json").data["total"]
self.assertGreater(total, 0)
for field in allowed:
response = self.client.get(f"{url}?search={term}&search_fields={field}", format="json")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["total"], 0, field)
for field in rejected:
response = self.client.get(f"{url}?search={term}&search_fields={field}", format="json")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["total"], total, field)

resource_rejected = ["owner__password__startswith", "owner__email__regex", "owner__username", "uuid", "^title"]
# anonymous
for name in ("base-resources-list", "datasets-list", "maps-list", "documents-list"):
_check(reverse(name), allowed=["title", "abstract"], rejected=resource_rejected)

admin = get_user_model().objects.get(username="admin")
GeoApp.objects.create(title="search fields geoapp", owner=admin)
self.assertTrue(self.client.login(username="admin", password="admin"))
_check(reverse("geoapps-list"), allowed=["title", "abstract"], rejected=resource_rejected)
_check(
reverse("users-list"),
allowed=["username", "first_name", "last_name"],
rejected=["password__startswith", "email", "username__regex"],
)
_check(
reverse("group-profiles-list"),
allowed=["title", "slug"],
rejected=["group__user__password__startswith", "description"],
)

def test_filter_resources(self):
"""
Ensure we can filter across the Resource Base list.
Expand Down
2 changes: 2 additions & 0 deletions geonode/base/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ class GroupViewSet(DynamicModelViewSet):
IsManagerEditOrAdmin,
]
filter_backends = [DynamicFilterBackend, DynamicSortingFilter, DynamicSearchFilter]
search_fields = ["title", "slug"]
serializer_class = GroupProfileSerializer
pagination_class = GeoNodeApiPagination

Expand Down Expand Up @@ -307,6 +308,7 @@ class ResourceBaseViewSet(ApiPresetsInitializer, MultiLangViewMixin, DeprecatedE
FavoriteFilter,
]
queryset = ResourceBase.objects.select_related("owner").order_by("-created")
search_fields = ["title", "abstract"]
serializer_class = ResourceBaseSerializer
pagination_class = GeoNodeApiPagination

Expand Down
1 change: 1 addition & 0 deletions geonode/documents/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class DocumentViewSet(ApiPresetsInitializer, MultiLangViewMixin, DynamicModelVie
DocumentPermissionsFilter,
]
queryset = Document.objects.all().order_by("-created")
search_fields = ["title", "abstract"]
serializer_class = DocumentSerializer
pagination_class = GeoNodeApiPagination

Expand Down
1 change: 1 addition & 0 deletions geonode/geoapps/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class GeoAppViewSet(ApiPresetsInitializer, MultiLangViewMixin, DynamicModelViewS
GeoAppPermissionsFilter,
]
queryset = GeoApp.objects.all().order_by("-created")
search_fields = ["title", "abstract"]
serializer_class = GeoAppSerializer
pagination_class = GeoNodeApiPagination

Expand Down
1 change: 1 addition & 0 deletions geonode/layers/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class DatasetViewSet(ApiPresetsInitializer, MultiLangViewMixin, DynamicModelView
DatasetPermissionsFilter,
]
queryset = Dataset.objects.all().order_by("-created")
search_fields = ["title", "abstract"]
serializer_class = DatasetSerializer
pagination_class = GeoNodeApiPagination

Expand Down
1 change: 1 addition & 0 deletions geonode/maps/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class MapViewSet(ApiPresetsInitializer, MultiLangViewMixin, DynamicModelViewSet)
MapPermissionsFilter,
]
queryset = Map.objects.all().order_by("-created")
search_fields = ["title", "abstract"]
serializer_class = MapSerializer
pagination_class = GeoNodeApiPagination

Expand Down
1 change: 1 addition & 0 deletions geonode/people/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class UserViewSet(DynamicModelViewSet):
IsOwnerOrAdmin,
]
filter_backends = [DynamicFilterBackend, DynamicSortingFilter, DynamicSearchFilter]
search_fields = ["username", "first_name", "last_name"]
serializer_class = UserSerializer
pagination_class = GeoNodeApiPagination

Expand Down
Loading