Skip to content

Commit

Permalink
position of user in completions and course avg
Browse files Browse the repository at this point in the history
added completions to response dict

Merged course completions leaders and course avg

added is_active check

pep8 compliant

remove serialiser class
  • Loading branch information
ziafazal committed Jun 27, 2014
1 parent 89b5e94 commit 6eed966
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 3 deletions.
9 changes: 9 additions & 0 deletions lms/djangoapps/api_manager/courses/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
48 changes: 48 additions & 0 deletions lms/djangoapps/api_manager/courses/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,54 @@ def test_courses_leaders_list_get(self):
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
Expand Down
1 change: 1 addition & 0 deletions lms/djangoapps/api_manager/courses/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
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)
59 changes: 56 additions & 3 deletions lms/djangoapps/api_manager/courses/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
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 _

Expand All @@ -34,7 +34,7 @@
from projects.serializers import ProjectSerializer

from .serializers import CourseModuleCompletionSerializer
from .serializers import GradeSerializer, CourseLeadersSerializer
from .serializers import GradeSerializer, CourseLeadersSerializer, CourseCompletionsLeadersSerializer

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -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)
Expand All @@ -1467,3 +1467,56 @@ def get_queryset(self):
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)

0 comments on commit 6eed966

Please sign in to comment.