Skip to content
Draft
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
64 changes: 64 additions & 0 deletions geonode/api/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#########################################################################
#
# Copyright (C) 2016 OSGeo
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#########################################################################

from django_filters import rest_framework as filters
from geonode.groups.models import GroupCategory, GroupProfile
from django.contrib.auth.models import Group

TEXT_LOOKUPS = (
"exact",
"contains",
"icontains",
"startswith",
"istartswith",
"endswith",
"iendswith",
"in",
"isnull",
)


class GroupCategoryFilter(filters.FilterSet):
class Meta:
model = GroupCategory
fields = {
"slug": TEXT_LOOKUPS,
"name": TEXT_LOOKUPS,
}


class GroupProfileFilter(filters.FilterSet):
class Meta:
model = GroupProfile
fields = {
"title": TEXT_LOOKUPS,
"slug": TEXT_LOOKUPS,
"categories__slug": TEXT_LOOKUPS,
"categories__name": TEXT_LOOKUPS,
}


class GroupFilter(filters.FilterSet):
class Meta:
model = Group
fields = {
"name": TEXT_LOOKUPS,
"groupprofile__title": TEXT_LOOKUPS,
"groupprofile__slug": TEXT_LOOKUPS,
}
122 changes: 122 additions & 0 deletions geonode/api/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#########################################################################
#
# Copyright (C) 2016 OSGeo
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#########################################################################
from rest_framework import serializers
from dynamic_rest.serializers import DynamicModelSerializer

from geonode.groups.models import GroupCategory, GroupProfile
from django.contrib.auth.models import Group
from django.db.models import Q
from .api import _get_resource_counts
from django.urls import reverse


class GroupCategorySerializer(DynamicModelSerializer):
detail_url = serializers.SerializerMethodField()
member_count = serializers.SerializerMethodField()
resource_counts = serializers.SerializerMethodField()

class Meta:
model = GroupCategory
fields = ["id", "slug", "name", "detail_url", "member_count", "resource_counts"]

def get_detail_url(self, obj):
return obj.get_absolute_url()

def get_member_count(self, obj):
request = self.context.get("request")
if not request:
return 0
user = request.user
filtered = obj.groups.all()

if not user.is_authenticated:
filtered = filtered.exclude(access="private")
elif not user.is_superuser:
filtered = filtered.filter(Q(id__in=user.group_list_all()) | ~Q(access="private"))

return filtered.count()
Comment thread
nrjadkry marked this conversation as resolved.

def get_resource_counts(self, obj):
request = self.context.get("request")
if not request:
return {}
return _get_resource_counts(
request,
resourcebase_filter_kwargs={"group__groupprofile__categories": obj},
)
Comment thread
nrjadkry marked this conversation as resolved.


class GroupProfileSerializer(DynamicModelSerializer):
categories = GroupCategorySerializer(many=True, read_only=True)
member_count = serializers.SerializerMethodField()
manager_count = serializers.SerializerMethodField()
logo_url = serializers.CharField(read_only=True)
detail_url = serializers.CharField(source="get_absolute_url", read_only=True)
resource_uri = serializers.SerializerMethodField()

class Meta:
model = GroupProfile
fields = [
"id",
"resource_uri",
"title",
"slug",
"description",
"email",
"access",
"created",
"last_modified",
"categories",
"member_count",
"manager_count",
"logo_url",
"detail_url",
]

def get_resource_uri(self, obj):
return reverse("group-profile-detail", args=[obj.pk])

def get_member_count(self, obj):
return obj.member_queryset().count()

def get_manager_count(self, obj):
return obj.get_managers().count()


class GroupSerializer(DynamicModelSerializer):
group_profile = GroupProfileSerializer(source="groupprofile", read_only=True, allow_null=True)
resource_counts = serializers.SerializerMethodField()

class Meta:
model = Group
fields = [
"id",
"name",
"group_profile",
"resource_counts",
]

def get_resource_counts(self, obj):
request = self.context.get("request")
if not request:
return {}
return _get_resource_counts(
request,
resourcebase_filter_kwargs={"group": obj, "metadata_only": False},
)
Comment thread
nrjadkry marked this conversation as resolved.
90 changes: 65 additions & 25 deletions geonode/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
)
from geonode.utils import check_ogc_backend
from geonode.decorators import on_ogc_backend
from geonode.groups.models import GroupProfile
from geonode.groups.models import GroupProfile, GroupCategory
from geonode.base.auth import get_or_create_token
from geonode.tests.base import GeoNodeBaseTestSupport
from geonode.base.populate_test_data import all_public, create_models, remove_models
Expand Down Expand Up @@ -382,19 +382,17 @@ def test_owners_lockdown(self):

@override_settings(API_LOCKDOWN=True)
def test_groups_lockdown(self):
groups_list_url = reverse("api_dispatch_list", kwargs={"api_name": "api", "resource_name": "groups"})
groups_list_url = reverse("groups-list")

filter_url = groups_list_url

resp = self.api_client.get(filter_url)
self.assertValidJSONResponse(resp)
self.assertEqual(len(self.deserialize(resp)["objects"]), 0)
resp = self.api_client.get(groups_list_url)
self.assertEqual(resp.status_code, 200)
self.assertEqual(resp.json()["total"], 0)

# now test with logged in user
self.api_client.client.login(username="bobby", password="bob")
resp = self.api_client.get(filter_url)
self.assertValidJSONResponse(resp)
self.assertEqual(len(self.deserialize(resp)["objects"]), 1)
resp = self.api_client.get(groups_list_url)
self.assertEqual(resp.status_code, 200)
self.assertEqual(len(resp.json()["groups"]), 1)

@override_settings(API_LOCKDOWN=True)
def test_regions_lockdown(self):
Expand Down Expand Up @@ -454,7 +452,8 @@ def setUp(self):
self.bar = GroupProfile.objects.get(slug="bar")
self.anonymous_user = get_anonymous_user()
self.profiles_list_url = reverse("api_dispatch_list", kwargs={"api_name": "api", "resource_name": "profiles"})
self.groups_list_url = reverse("api_dispatch_list", kwargs={"api_name": "api", "resource_name": "groups"})
self.groups_list_url = reverse("groups-list")
self.bar_category, _ = GroupCategory.objects.get_or_create(slug="bar", name="bar")

def test_profiles_filters(self):
"""Test profiles filtering"""
Expand Down Expand Up @@ -496,26 +495,67 @@ def test_groups_filters(self):
filter_url = self.groups_list_url

resp = self.api_client.get(filter_url)
self.assertValidJSONResponse(resp)
self.assertEqual(len(self.deserialize(resp)["objects"]), 1)
self.assertEqual(resp.status_code, 200)
self.assertEqual(len(resp.json()["groups"]), 1)

filter_url = f"{self.groups_list_url}?name__icontains=bar"
resp = self.api_client.get(f"{filter_url}?name__icontains=bar")
self.assertEqual(resp.status_code, 200)
self.assertEqual(len(resp.json()["groups"]), 1)

resp = self.api_client.get(filter_url)
self.assertValidJSONResponse(resp)
self.assertEqual(len(self.deserialize(resp)["objects"]), 1)
resp = self.api_client.get(f"{filter_url}?name__icontains=BaR")
self.assertEqual(resp.status_code, 200)
self.assertEqual(len(resp.json()["groups"]), 1)

filter_url = f"{self.groups_list_url}?name__icontains=BaR"
resp = self.api_client.get(f"{filter_url}?name__icontains=foo")
self.assertEqual(resp.status_code, 200)
self.assertEqual(len(resp.json()["groups"]), 0)

resp = self.api_client.get(filter_url)
self.assertValidJSONResponse(resp)
self.assertEqual(len(self.deserialize(resp)["objects"]), 1)
def test_group_categories_filters(self):
"""Test group categories filtering"""
with self.settings(API_LOCKDOWN=False):
group_categories_list_url = reverse("group-category-list")
resp = self.api_client.get(group_categories_list_url)
self.assertEqual(resp.status_code, 200)

filter_url = f"{self.groups_list_url}?name__icontains=foo"
resp = self.api_client.get(f"{group_categories_list_url}?name__icontains=bar")
self.assertEqual(resp.status_code, 200)
self.assertEqual(len(resp.json()["group_categories"]), 1)

resp = self.api_client.get(filter_url)
self.assertValidJSONResponse(resp)
self.assertEqual(len(self.deserialize(resp)["objects"]), 0)
resp = self.api_client.get(f"{group_categories_list_url}?name__icontains=BaR")
self.assertEqual(resp.status_code, 200)
self.assertEqual(len(resp.json()["group_categories"]), 1)

resp = self.api_client.get(f"{group_categories_list_url}?name__icontains=nonexistent")
self.assertEqual(resp.status_code, 200)
self.assertEqual(len(resp.json()["group_categories"]), 0)

resp = self.api_client.get(f"{group_categories_list_url}?slug=bar")
self.assertEqual(resp.status_code, 200)
self.assertEqual(len(resp.json()["group_categories"]), 1)

def test_group_profiles_filters(self):
"""Test group profiles filtering"""
with self.settings(API_LOCKDOWN=False):
group_profiles_list_url = reverse("group-profile-list")

resp = self.api_client.get(group_profiles_list_url)
self.assertEqual(resp.status_code, 200)

resp = self.api_client.get(f"{group_profiles_list_url}?title__icontains=bar")
self.assertEqual(resp.status_code, 200)
self.assertEqual(len(resp.json()["group_profiles"]), 1)

resp = self.api_client.get(f"{group_profiles_list_url}?title__icontains=BaR")
self.assertEqual(resp.status_code, 200)
self.assertEqual(len(resp.json()["group_profiles"]), 1)

resp = self.api_client.get(f"{group_profiles_list_url}?title__icontains=nonexistent")
self.assertEqual(resp.status_code, 200)
self.assertEqual(len(resp.json()["group_profiles"]), 0)

resp = self.api_client.get(f"{group_profiles_list_url}?slug=bar")
self.assertEqual(resp.status_code, 200)
self.assertEqual(len(resp.json()["group_profiles"]), 1)

def test_category_filters(self):
"""Test category filtering"""
Expand Down
14 changes: 12 additions & 2 deletions geonode/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@

from . import api as resources
from . import resourcebase_api as resourcebase_resources
from .views import UserInfoView
from .views import (
UserInfoView,
GroupCategoryViewSet,
GroupViewSet,
GroupProfileViewSet,
)

api = Api(api_name="api")

Expand All @@ -46,6 +51,11 @@

router = routers.DynamicRouter()


router.register(r"groupcategory", GroupCategoryViewSet, base_name="group-category")
router.register(r"group", GroupViewSet, base_name="groups")
router.register(r"group_profile", GroupProfileViewSet, base_name="group-profile")

urlpatterns = [
path("userinfo/", UserInfoView.as_view(), name="userinfo"),
]
] + router.urls
Loading
Loading