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):
response = self.do_get('{}/{}/projects/'.format(self.base_courses_uri, self.test_bogus_course_id))
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(
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>[^/]+/[^/]+/[^/]+)/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)
......@@ -1398,3 +1398,29 @@ class CoursesProjectList(SecureListAPIView):
raise Http404
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):
model = APIUser
fields = ("id", "email", "username", "first_name", "last_name", "organizations")
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):
completion_list_uri = '/api/users/{}/courses/{}/completions/'.format('34323422', self.course.id)
response = self.do_get(completion_list_uri)
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
urlpatterns = patterns(
'',
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]+)/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'),
......
......@@ -5,6 +5,7 @@ import logging
from django.contrib.auth.models import Group
from django.core.exceptions import ObjectDoesNotExist
from django.db import IntegrityError
from django.db.models import Count
from django.core.validators import validate_email, validate_slug, ValidationError
from django.conf import settings
from django.http import Http404
......@@ -20,7 +21,7 @@ from api_manager.organizations.serializers import OrganizationSerializer
from api_manager.courses.serializers import CourseModuleCompletionSerializer
from api_manager.utils import generate_base_uri
from projects.serializers import BasicWorkgroupSerializer
from .serializers import UserSerializer
from .serializers import UserSerializer, UserCountByCitySerializer
from courseware import module_render
from courseware.model_data import FieldDataCache
......@@ -978,3 +979,26 @@ class UsersSocialMetrics(SecureListAPIView):
http_status = status.HTTP_500_INTERNAL_SERVER_ERROR
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