Commit 63d033f5 by Zia Fazal Committed by Jonathan Piacenti

position of user in completions and course avg

added completions to response dict

Merged course completions leaders and course avg

added is_active check

pep8 compliant

remove serialiser class
parent 64a976ab
......@@ -27,3 +27,12 @@ class CourseLeadersSerializer(serializers.Serializer):
title = serializers.CharField(source='student__profile__title')
avatar_url = serializers.CharField(source='student__profile__avatar_url')
points_scored = serializers.IntegerField()
class CourseCompletionsLeadersSerializer(serializers.Serializer):
""" Serializer for course completions leaderboard """
id = serializers.IntegerField(source='user__id')
username = serializers.CharField(source='user__username')
title = serializers.CharField(source='user__profile__title')
avatar_url = serializers.CharField(source='user__profile__avatar_url')
completions = serializers.IntegerField()
......@@ -1315,6 +1315,54 @@ class CoursesApiTests(TestCase):
response = self.do_get(test_uri)
self.assertEqual(response.status_code, 404)
def test_courses_completions_leaders_list_get(self):
completion_uri = '{}/{}/completions/'.format(self.base_courses_uri, self.course.id)
users = []
for i in xrange(1, 5):
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(self.base_users_uri, data)
self.assertEqual(response.status_code, 201)
users.append(response.data['id'])
for i in xrange(1, 26):
if i < 3:
user_id = users[0]
elif i < 8:
user_id = users[1]
elif i < 16:
user_id = users[2]
else:
user_id = users[3]
content_id = self.course_content.id + str(i)
completions_data = {'content_id': content_id, 'user_id': user_id}
response = self.do_post(completion_uri, completions_data)
self.assertEqual(response.status_code, 201)
test_uri = '{}/{}/metrics/completions/leaders/?{}'.format(self.base_courses_uri, self.test_course_id, 'count=6')
response = self.do_get(test_uri)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data['leaders']), 4)
self.assertEqual(response.data['course_avg'], 6.3)
# without count filter and user_id
test_uri = '{}/{}/metrics/completions/leaders/?user_id={}'.format(self.base_courses_uri, self.test_course_id,
users[3])
response = self.do_get(test_uri)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data['leaders']), 3)
self.assertEqual(response.data['position'], 1)
self.assertEqual(response.data['completions'], 10)
# test with bogus course
test_uri = '{}/{}/metrics/completions/leaders/'.format(self.base_courses_uri, self.test_bogus_course_id)
response = self.do_get(test_uri)
self.assertEqual(response.status_code, 404)
def test_courses_grades_list_get(self):
# Retrieve the list of grades for this course
......
......@@ -31,6 +31,7 @@ urlpatterns = patterns(
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'),
url(r'^(?P<course_id>[^/]+/[^/]+/[^/]+)/metrics/proficiency/leaders/*$', courses_views.CoursesLeadersList.as_view(), name='course-metrics-proficiency-leaders'),
url(r'^(?P<course_id>[^/]+/[^/]+/[^/]+)/metrics/completions/leaders/*$', courses_views.CoursesCompletionsLeadersList.as_view(), name='course-metrics-completions-leaders'),
)
urlpatterns = format_suffix_patterns(urlpatterns)
......@@ -9,7 +9,7 @@ from StringIO import StringIO
from django.conf import settings
from django.contrib.auth.models import Group, User
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Avg, Sum
from django.db.models import Avg, Sum, Count
from django.http import Http404
from django.utils.translation import ugettext_lazy as _
......@@ -34,7 +34,7 @@ from projects.models import Project
from projects.serializers import ProjectSerializer
from .serializers import CourseModuleCompletionSerializer
from .serializers import GradeSerializer, CourseLeadersSerializer
from .serializers import GradeSerializer, CourseLeadersSerializer, CourseCompletionsLeadersSerializer
log = logging.getLogger(__name__)
......@@ -1445,7 +1445,7 @@ class CoursesLeadersList(SecureListAPIView):
def get_queryset(self):
"""
GET /api/courses/{course_id}/leaders/
GET /api/courses/{course_id}/metrics/proficiency/leaders/
"""
course_id = self.kwargs['course_id']
content_id = self.request.QUERY_PARAMS.get('content_id', None)
......@@ -1467,3 +1467,56 @@ class CoursesLeadersList(SecureListAPIView):
queryset = queryset.values('student__id', 'student__username', 'student__profile__title',
'student__profile__avatar_url').annotate(points_scored=Sum('grade')).order_by('-points_scored')[:count]
return queryset
class CoursesCompletionsLeadersList(SecureAPIView):
"""
### The CoursesCompletionsLeadersList view allows clients to retrieve top 3 users who are leading
in terms of course module completions and course average for the specified Course, if user_id parameter is given
position of user is returned
- URI: ```/api/courses/{course_id}/metrics/completions/leaders/```
- GET: Returns a JSON representation (array) of the users with points scored
Filters can also be applied
```/api/courses/{course_id}/metrics/completions/leaders/?content_id={content_id}```
To get more than 3 users use count parameter
```/api/courses/{course_id}/metrics/completions/leaders/?count=6```
### Use Cases/Notes:
* Example: Display leaders in terms of completions in a given course
* Example: Display top 3 users leading in terms of completions in a given course
"""
def get(self, request, course_id): # pylint: disable=W0613
"""
GET /api/courses/{course_id}/metrics/completions/leaders/
"""
user_id = self.request.QUERY_PARAMS.get('user_id', None)
count = self.request.QUERY_PARAMS.get('count', 3)
data = {}
course_avg = 0
try:
get_course(course_id)
except ValueError:
raise Http404
queryset = CourseModuleCompletion.objects.filter(course_id=course_id)
if user_id:
user_completions = queryset.filter(user__id=user_id).count()
completions_above_user = queryset.filter(user__is_active=True).values('user__id')\
.annotate(completions=Count('content_id')).filter(completions__gt=user_completions).count()
data['position'] = completions_above_user + 1
data['completions'] = user_completions
total_completions = queryset.filter(user__is_active=True).count()
users = CourseModuleCompletion.objects.filter(user__is_active=True)\
.aggregate(total=Count('user__id', distinct=True))
if users and users['total'] > 0:
course_avg = round(total_completions / float(users['total']), 1)
data['course_avg'] = course_avg
queryset = queryset.filter(user__is_active=True).values('user__id', 'user__username', 'user__profile__title',
'user__profile__avatar_url')\
.annotate(completions=Count('content_id')).order_by('-completions')[:count]
serializer = CourseCompletionsLeadersSerializer(queryset, many=True)
data['leaders'] = serializer.data # pylint: disable=E1101
return Response(data, status=status.HTTP_200_OK)
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