Commit 4fac6450 by Matt Drayer Committed by Jonathan Piacenti

mattdrayer/api-groups-organizations-list: Support for viewing related orgs

merged with master and updated url
parent d9e21cf1
...@@ -1357,3 +1357,32 @@ class CoursesApiTests(TestCase): ...@@ -1357,3 +1357,32 @@ class CoursesApiTests(TestCase):
response = self.do_get('{}/{}/projects/'.format(self.base_courses_uri, self.test_bogus_course_id)) response = self.do_get('{}/{}/projects/'.format(self.base_courses_uri, self.test_bogus_course_id))
self.assertEqual(response.status_code, 404) self.assertEqual(response.status_code, 404)
def test_courses_data_metrics(self):
test_uri = self.base_courses_uri + '/' + self.test_course_id + '/users'
test_user_uri = '/api/users'
users_to_add = 5
for i in xrange(0, users_to_add):
data = {
'email': 'test{}@example.com'.format(i), 'username': 'test_user{}'.format(i),
'password': 'test_password'
}
# create a new user
response = self.do_post(test_user_uri, data)
self.assertEqual(response.status_code, 201)
created_user_id = response.data['id']
# now enroll this user in the course
post_data = {'user_id': created_user_id}
response = self.do_post(test_uri, post_data)
self.assertEqual(response.status_code, 201)
# get course metrics
course_metrics_uri = '/api/courses/{}/metrics/'
response = self.do_get(course_metrics_uri.format(self.test_course_id))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data['users_enrolled'], users_to_add + USER_COUNT)
# test with bogus course
response = self.do_get(course_metrics_uri.format(self.test_bogus_course_id))
self.assertEqual(response.status_code, 404)
...@@ -29,6 +29,7 @@ urlpatterns = patterns( ...@@ -29,6 +29,7 @@ urlpatterns = patterns(
url(r'^(?P<course_id>[^/]+/[^/]+/[^/]+)/users/*$', courses_views.CoursesUsersList.as_view()), url(r'^(?P<course_id>[^/]+/[^/]+/[^/]+)/users/*$', courses_views.CoursesUsersList.as_view()),
url(r'^(?P<course_id>[^/]+/[^/]+/[^/]+)/completions/*$', courses_views.CourseModuleCompletionList.as_view(), name='completion-list'), url(r'^(?P<course_id>[^/]+/[^/]+/[^/]+)/completions/*$', courses_views.CourseModuleCompletionList.as_view(), name='completion-list'),
url(r'^(?P<course_id>[^/]+/[^/]+/[^/]+)/projects/*$', courses_views.CoursesProjectList.as_view(), name='courseproject-list'), url(r'^(?P<course_id>[^/]+/[^/]+/[^/]+)/projects/*$', courses_views.CoursesProjectList.as_view(), name='courseproject-list'),
url(r'^(?P<course_id>[^/]+/[^/]+/[^/]+)/metrics/*$', courses_views.CourseMetrics.as_view(), name='course-metrics'),
) )
urlpatterns = format_suffix_patterns(urlpatterns) urlpatterns = format_suffix_patterns(urlpatterns)
...@@ -1398,3 +1398,29 @@ class CoursesProjectList(SecureListAPIView): ...@@ -1398,3 +1398,29 @@ class CoursesProjectList(SecureListAPIView):
raise Http404 raise Http404
return Project.objects.filter(course_id=course_id) return Project.objects.filter(course_id=course_id)
class CourseMetrics(SecureAPIView):
"""
### The CourseMetrics view allows clients to retrieve a list of Metrics for the specified Course
- URI: ```/api/courses/{course_id}/metrics/```
- GET: Returns a JSON representation (array) of the set of course metrics
### Use Cases/Notes:
* Example: Display number of users enrolled in a given course
"""
def get(self, request, course_id): # pylint: disable=W0613
"""
GET /api/courses/{course_id}/metrics/
"""
try:
existing_course = get_course(course_id)
except ValueError:
existing_course = None
if not existing_course:
return Response({}, status=status.HTTP_404_NOT_FOUND)
users_enrolled = CourseEnrollment.num_enrolled_in(course_id)
data = {
'users_enrolled': users_enrolled
}
return Response(data, status=status.HTTP_200_OK)
...@@ -14,3 +14,9 @@ class UserSerializer(serializers.ModelSerializer): ...@@ -14,3 +14,9 @@ class UserSerializer(serializers.ModelSerializer):
model = APIUser model = APIUser
fields = ("id", "email", "username", "first_name", "last_name", "organizations") fields = ("id", "email", "username", "first_name", "last_name", "organizations")
read_only_fields = ("id", "email", "username") read_only_fields = ("id", "email", "username")
class UserCountByCitySerializer(serializers.Serializer):
""" Serializer for user count by city """
city = serializers.CharField(source='profile__city')
count = serializers.IntegerField()
...@@ -1087,3 +1087,43 @@ class UsersApiTests(TestCase): ...@@ -1087,3 +1087,43 @@ class UsersApiTests(TestCase):
completion_list_uri = '/api/users/{}/courses/{}/completions/'.format('34323422', self.course.id) completion_list_uri = '/api/users/{}/courses/{}/completions/'.format('34323422', self.course.id)
response = self.do_get(completion_list_uri) response = self.do_get(completion_list_uri)
self.assertEqual(response.status_code, 404) self.assertEqual(response.status_code, 404)
def test_user_count_by_city(self):
test_uri = '/api/users'
# create a 25 new users
for i in xrange(1, 26):
if i < 10:
city = 'San Francisco'
elif i < 15:
city = 'Denver'
elif i < 20:
city = 'Dallas'
else:
city = 'New York City'
data = {
'email': 'test{}@example.com'.format(i), 'username': 'test_user{}'.format(i),
'password': self.test_password,
'first_name': self.test_first_name, 'last_name': self.test_last_name, 'city': city,
'country': 'PK', 'level_of_education': 'b', 'year_of_birth': '2000', 'gender': 'male',
'title': 'Software Engineer', 'avatar_url': 'http://example.com/avatar.png'
}
response = self.do_post(test_uri, data)
self.assertEqual(response.status_code, 201)
response = self.do_get(response.data['uri'])
self.assertEqual(response.status_code, 200)
self.is_user_profile_created_updated(response, data)
response = self.do_get('/api/users/metrics/cities/')
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data['results']), 4)
self.assertEqual(response.data['results'][0]['city'], 'San Francisco')
self.assertEqual(response.data['results'][0]['count'], 9)
# filter counts by city
response = self.do_get('/api/users/metrics/cities/?city=new york city')
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data['results']), 1)
self.assertEqual(response.data['results'][0]['city'], 'New York City')
self.assertEqual(response.data['results'][0]['count'], 6)
...@@ -8,6 +8,7 @@ from api_manager.users import views as users_views ...@@ -8,6 +8,7 @@ from api_manager.users import views as users_views
urlpatterns = patterns( urlpatterns = patterns(
'', '',
url(r'/*$^', users_views.UsersList.as_view(), name='apimgr-users-list'), url(r'/*$^', users_views.UsersList.as_view(), name='apimgr-users-list'),
url(r'^metrics/cities/$', users_views.UsersMetricsCitiesList.as_view(), name='apimgr-users-metrics-cities-list'),
url(r'^(?P<user_id>[a-zA-Z0-9]+)$', users_views.UsersDetail.as_view(), name='apimgr-users-detail'), url(r'^(?P<user_id>[a-zA-Z0-9]+)$', users_views.UsersDetail.as_view(), name='apimgr-users-detail'),
url(r'^(?P<user_id>[a-zA-Z0-9]+)/courses/*$', users_views.UsersCoursesList.as_view(), name='users-courses-list'), url(r'^(?P<user_id>[a-zA-Z0-9]+)/courses/*$', users_views.UsersCoursesList.as_view(), name='users-courses-list'),
url(r'^(?P<user_id>[a-zA-Z0-9]+)/courses/(?P<course_id>[^/]+/[^/]+/[^/]+)$', users_views.UsersCoursesDetail.as_view(), name='users-courses-detail'), url(r'^(?P<user_id>[a-zA-Z0-9]+)/courses/(?P<course_id>[^/]+/[^/]+/[^/]+)$', users_views.UsersCoursesDetail.as_view(), name='users-courses-detail'),
......
...@@ -5,6 +5,7 @@ import logging ...@@ -5,6 +5,7 @@ import logging
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.db import IntegrityError from django.db import IntegrityError
from django.db.models import Count
from django.core.validators import validate_email, validate_slug, ValidationError from django.core.validators import validate_email, validate_slug, ValidationError
from django.conf import settings from django.conf import settings
from django.http import Http404 from django.http import Http404
...@@ -20,7 +21,7 @@ from api_manager.organizations.serializers import OrganizationSerializer ...@@ -20,7 +21,7 @@ from api_manager.organizations.serializers import OrganizationSerializer
from api_manager.courses.serializers import CourseModuleCompletionSerializer from api_manager.courses.serializers import CourseModuleCompletionSerializer
from api_manager.utils import generate_base_uri from api_manager.utils import generate_base_uri
from projects.serializers import BasicWorkgroupSerializer from projects.serializers import BasicWorkgroupSerializer
from .serializers import UserSerializer from .serializers import UserSerializer, UserCountByCitySerializer
from courseware import module_render from courseware import module_render
from courseware.model_data import FieldDataCache from courseware.model_data import FieldDataCache
...@@ -978,3 +979,26 @@ class UsersSocialMetrics(SecureListAPIView): ...@@ -978,3 +979,26 @@ class UsersSocialMetrics(SecureListAPIView):
http_status = status.HTTP_500_INTERNAL_SERVER_ERROR http_status = status.HTTP_500_INTERNAL_SERVER_ERROR
return Response(data, http_status) return Response(data, http_status)
class UsersMetricsCitiesList(SecureListAPIView):
"""
### The UsersMetricsCitiesList view allows clients to retrieve ordered list of user
count by city
- URI: ```/api/users/metrics/cities/```
- GET: Provides paginated list of user count
To get user count a particular city filter can be applied
GET ```/api/users/metrics/cities/?city={city}```
"""
serializer_class = UserCountByCitySerializer
def get_queryset(self):
city = self.request.QUERY_PARAMS.get('city', None)
queryset = User.objects.all()
if city:
queryset = queryset.filter(profile__city__iexact=city)
queryset = queryset.values('profile__city').annotate(count=Count('profile__city'))\
.filter(count__gt=0).order_by('-count')
return queryset
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