Commit e5a025df by Zia Fazal Committed by Jonathan Piacenti

added has_organizations filter to users api

parent f384d6e3
...@@ -7,6 +7,8 @@ from api_manager.utils import get_client_ip_address, address_exists_in_network ...@@ -7,6 +7,8 @@ from api_manager.utils import get_client_ip_address, address_exists_in_network
from rest_framework import permissions, generics, filters, pagination, serializers from rest_framework import permissions, generics, filters, pagination, serializers
from rest_framework.views import APIView from rest_framework.views import APIView
from api_manager.utils import str2bool
from api_manager.models import APIUser as User
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -97,6 +99,24 @@ class IdsInFilterBackend(filters.BaseFilterBackend): ...@@ -97,6 +99,24 @@ class IdsInFilterBackend(filters.BaseFilterBackend):
return queryset return queryset
class HasOrgsFilterBackend(filters.BaseFilterBackend):
"""
This backend support filtering users with and organization association or not
"""
def filter_queryset(self, request, queryset, view):
"""
Parse querystring base on has_organizations query param
"""
has_orgs = request.QUERY_PARAMS.get('has_organizations', None)
if has_orgs:
if str2bool(has_orgs):
queryset = queryset.filter(organizations__id__gt=0)
else:
queryset = queryset.exclude(id__in=User.objects.filter(organizations__id__gt=0).
values_list('id', flat=True))
return queryset.distinct()
class CustomPaginationSerializer(pagination.PaginationSerializer): class CustomPaginationSerializer(pagination.PaginationSerializer):
""" """
Custom PaginationSerializer to include num_pages field Custom PaginationSerializer to include num_pages field
......
...@@ -13,7 +13,7 @@ class UserSerializer(serializers.ModelSerializer): ...@@ -13,7 +13,7 @@ class UserSerializer(serializers.ModelSerializer):
class Meta: class Meta:
""" Serializer/field specification """ """ Serializer/field specification """
model = APIUser model = APIUser
fields = ("id", "email", "username", "first_name", "last_name", "created", "organizations") fields = ("id", "email", "username", "first_name", "last_name", "created", "is_active", "organizations")
read_only_fields = ("id", "email", "username") read_only_fields = ("id", "email", "username")
......
...@@ -197,6 +197,44 @@ class UsersApiTests(ModuleStoreTestCase): ...@@ -197,6 +197,44 @@ class UsersApiTests(ModuleStoreTestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data['results']), 0) self.assertEqual(len(response.data['results']), 0)
def test_user_list_get_with_org_filter(self):
test_uri = '/api/users'
users = []
# create a 7 new users
for i in xrange(1, 8):
data = {
'email': 'test{}@example.com'.format(i),
'username': 'test_user{}'.format(i),
'password': 'test_pass',
'first_name': 'John{}'.format(i),
'last_name': 'Doe{}'.format(i)
}
response = self.do_post(test_uri, data)
self.assertEqual(response.status_code, 201)
users.append(response.data['id'])
# create organizations and add users to them
total_orgs = 4
for i in xrange(1, total_orgs):
data = {
'name': '{} {}'.format('Org', i),
'display_name': '{} {}'.format('Org display name', i),
'users': users[:i]
}
response = self.do_post(self.org_base_uri, data)
self.assertEqual(response.status_code, 201)
# fetch users without any organization association
response = self.do_get('{}?has_organizations=true'.format(test_uri))
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data['results']), 3)
self.assertIsNotNone(response.data['results'][0]['is_active'])
response = self.do_get('{}?has_organizations=false'.format(test_uri))
self.assertEqual(response.status_code, 200)
self.assertGreaterEqual(len(response.data['results']), 4)
def test_user_list_post(self): def test_user_list_post(self):
test_uri = '/api/users' test_uri = '/api/users'
local_username = self.test_username + str(randint(11, 99)) local_username = self.test_username + str(randint(11, 99))
......
...@@ -12,11 +12,12 @@ from django.conf import settings ...@@ -12,11 +12,12 @@ from django.conf import settings
from django.http import Http404 from django.http import Http404
from django.utils.translation import get_language, ugettext_lazy as _ from django.utils.translation import get_language, ugettext_lazy as _
from rest_framework import status from rest_framework import status
from rest_framework import filters
from rest_framework.response import Response from rest_framework.response import Response
from api_manager.courseware_access import get_course, get_course_child, get_course_total_score from api_manager.courseware_access import get_course, get_course_child, get_course_total_score
from api_manager.permissions import SecureAPIView, SecureListAPIView from api_manager.permissions import SecureAPIView, SecureListAPIView, IdsInFilterBackend, HasOrgsFilterBackend
from api_manager.models import GroupProfile, APIUser as User from api_manager.models import GroupProfile, APIUser as User
from api_manager.organizations.serializers import OrganizationSerializer from api_manager.organizations.serializers import OrganizationSerializer
from api_manager.courses.serializers import CourseModuleCompletionSerializer from api_manager.courses.serializers import CourseModuleCompletionSerializer
...@@ -102,7 +103,7 @@ class UsersList(SecureListAPIView): ...@@ -102,7 +103,7 @@ class UsersList(SecureListAPIView):
""" """
### The UsersList view allows clients to retrieve/append a list of User entities ### The UsersList view allows clients to retrieve/append a list of User entities
- URI: ```/api/users/``` - URI: ```/api/users/```
- GET: Provides paginated list of users, it supports email, username and id filters - GET: Provides paginated list of users, it supports email, username, has_organizations and id filters
Possible use cases Possible use cases
GET /api/users?ids=23 GET /api/users?ids=23
GET /api/users?ids=11,12,13&page=2 GET /api/users?ids=11,12,13&page=2
...@@ -110,6 +111,10 @@ class UsersList(SecureListAPIView): ...@@ -110,6 +111,10 @@ class UsersList(SecureListAPIView):
GET /api/users?username={john} GET /api/users?username={john}
* email: string, filters user set by email address * email: string, filters user set by email address
* username: string, filters user set by username * username: string, filters user set by username
GET /api/users?has_organizations={true}
* has_organizations: boolean, filters user set with organization association
GET /api/users?has_organizations={false}
* has_organizations: boolean, filters user set with no organization association
Example JSON output {'count': '25', 'next': 'https://testserver/api/users?page=2', num_pages='3', Example JSON output {'count': '25', 'next': 'https://testserver/api/users?page=2', num_pages='3',
'previous': None, 'results':[]} 'previous': None, 'results':[]}
...@@ -155,6 +160,7 @@ class UsersList(SecureListAPIView): ...@@ -155,6 +160,7 @@ class UsersList(SecureListAPIView):
""" """
queryset = User.objects.all() queryset = User.objects.all()
serializer_class = UserSerializer serializer_class = UserSerializer
filter_backends = (filters.DjangoFilterBackend, IdsInFilterBackend, HasOrgsFilterBackend)
filter_fields = ('email', 'username', ) filter_fields = ('email', 'username', )
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
...@@ -164,7 +170,8 @@ class UsersList(SecureListAPIView): ...@@ -164,7 +170,8 @@ class UsersList(SecureListAPIView):
email = request.QUERY_PARAMS.get('email', None) email = request.QUERY_PARAMS.get('email', None)
username = request.QUERY_PARAMS.get('username', None) username = request.QUERY_PARAMS.get('username', None)
ids = request.QUERY_PARAMS.get('ids', None) ids = request.QUERY_PARAMS.get('ids', None)
if email or username or ids: has_orgs = request.QUERY_PARAMS.get('has_organizations', None)
if email or username or ids or has_orgs:
return self.list(request, *args, **kwargs) return self.list(request, *args, **kwargs)
else: else:
return Response({'message': _('Unfiltered request is not allowed.')}, status=status.HTTP_400_BAD_REQUEST) return Response({'message': _('Unfiltered request is not allowed.')}, status=status.HTTP_400_BAD_REQUEST)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment