Commit bbd6f788 by Greg Price

Add endpoint to get user list for a preference

The endpoint includes the key of the desired preference in the URL and
returns the list of users for whom the preference is set (regardless of
the value).
parent 8f01756c
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.validators import RegexValidator
from django.db import models from django.db import models
class UserPreference(models.Model): class UserPreference(models.Model):
"""A user's preference, stored as generic text to be processed by client""" """A user's preference, stored as generic text to be processed by client"""
KEY_REGEX = r"[-_a-zA-Z0-9]+"
user = models.ForeignKey(User, db_index=True, related_name="preferences") user = models.ForeignKey(User, db_index=True, related_name="preferences")
key = models.CharField(max_length=255, db_index=True) key = models.CharField(max_length=255, db_index=True, validators=[RegexValidator(KEY_REGEX)])
value = models.TextField() value = models.TextField()
class Meta: class Meta:
......
...@@ -373,3 +373,59 @@ class UserPreferenceViewSetTest(UserApiTestCase): ...@@ -373,3 +373,59 @@ class UserPreferenceViewSetTest(UserApiTestCase):
"url": uri, "url": uri,
} }
) )
class PreferenceUsersListViewTest(UserApiTestCase):
LIST_URI = "/user_api/v1/preferences/key0/users/"
def test_options(self):
self.assertAllowedMethods(self.LIST_URI, ["OPTIONS", "GET", "HEAD"])
def test_put_not_allowed(self):
self.assertHttpMethodNotAllowed(self.request_with_auth("put", self.LIST_URI))
def test_patch_not_allowed(self):
raise SkipTest("Django 1.4's test client does not support patch")
def test_delete_not_allowed(self):
self.assertHttpMethodNotAllowed(self.request_with_auth("delete", self.LIST_URI))
def test_unauthorized(self):
self.assertHttpForbidden(self.client.get(self.LIST_URI))
@override_settings(DEBUG=True)
@override_settings(EDX_API_KEY=None)
def test_debug_auth(self):
self.assertHttpOK(self.client.get(self.LIST_URI))
def test_get_basic(self):
result = self.get_json(self.LIST_URI)
self.assertEqual(result["count"], 2)
self.assertIsNone(result["next"])
self.assertIsNone(result["previous"])
users = result["results"]
self.assertEqual(len(users), 2)
for user in users:
self.assertUserIsValid(user)
def test_get_pagination(self):
first_page = self.get_json(self.LIST_URI, data={"page_size": 1})
self.assertEqual(first_page["count"], 2)
first_page_next_uri = first_page["next"]
self.assertIsNone(first_page["previous"])
first_page_users = first_page["results"]
self.assertEqual(len(first_page_users), 1)
second_page = self.get_json(first_page_next_uri)
self.assertEqual(second_page["count"], 2)
self.assertIsNone(second_page["next"])
second_page_prev_uri = second_page["previous"]
second_page_users = second_page["results"]
self.assertEqual(len(second_page_users), 1)
self.assertEqual(self.get_json(second_page_prev_uri), first_page)
for user in first_page_users + second_page_users:
self.assertUserIsValid(user)
all_user_uris = [user["url"] for user in first_page_users + second_page_users]
self.assertEqual(len(set(all_user_uris)), 2)
from django.conf.urls import include, patterns, url from django.conf.urls import include, patterns, url
from rest_framework import routers from rest_framework import routers
from user_api import views as user_api_views from user_api import views as user_api_views
from user_api.models import UserPreference
user_api_router = routers.DefaultRouter() user_api_router = routers.DefaultRouter()
...@@ -9,4 +10,8 @@ user_api_router.register(r'user_prefs', user_api_views.UserPreferenceViewSet) ...@@ -9,4 +10,8 @@ user_api_router.register(r'user_prefs', user_api_views.UserPreferenceViewSet)
urlpatterns = patterns( urlpatterns = patterns(
'', '',
url(r'^v1/', include(user_api_router.urls)), url(r'^v1/', include(user_api_router.urls)),
url(
r'^v1/preferences/(?P<pref_key>{})/users/$'.format(UserPreference.KEY_REGEX),
user_api_views.PreferenceUsersListView.as_view()
),
) )
...@@ -2,6 +2,7 @@ from django.conf import settings ...@@ -2,6 +2,7 @@ from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from rest_framework import authentication from rest_framework import authentication
from rest_framework import filters from rest_framework import filters
from rest_framework import generics
from rest_framework import permissions from rest_framework import permissions
from rest_framework import viewsets from rest_framework import viewsets
from user_api.serializers import UserSerializer, UserPreferenceSerializer from user_api.serializers import UserSerializer, UserPreferenceSerializer
...@@ -43,3 +44,14 @@ class UserPreferenceViewSet(viewsets.ReadOnlyModelViewSet): ...@@ -43,3 +44,14 @@ class UserPreferenceViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = UserPreferenceSerializer serializer_class = UserPreferenceSerializer
paginate_by = 10 paginate_by = 10
paginate_by_param = "page_size" paginate_by_param = "page_size"
class PreferenceUsersListView(generics.ListAPIView):
authentication_classes = (authentication.SessionAuthentication,)
permission_classes = (ApiKeyHeaderPermission,)
serializer_class = UserSerializer
paginate_by = 10
paginate_by_param = "page_size"
def get_queryset(self):
return User.objects.filter(preferences__key=self.kwargs["pref_key"]).prefetch_related("preferences")
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