Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
c04fcc7b
Commit
c04fcc7b
authored
Sep 15, 2014
by
Matt Drayer
Committed by
Jonathan Piacenti
Aug 20, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
mattdrayer/api: Fixed NRE corner case for grades leaderboard
parent
6cd45965
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
74 additions
and
42 deletions
+74
-42
lms/djangoapps/api_manager/courses/tests.py
+20
-0
lms/djangoapps/gradebook/models.py
+54
-42
No files found.
lms/djangoapps/api_manager/courses/tests.py
View file @
c04fcc7b
...
@@ -187,6 +187,11 @@ class CoursesApiTests(TestCase):
...
@@ -187,6 +187,11 @@ class CoursesApiTests(TestCase):
display_name
=
u"test unit 2"
,
display_name
=
u"test unit 2"
,
)
)
self
.
empty_course
=
CourseFactory
.
create
(
start
=
datetime
(
2014
,
6
,
16
,
14
,
30
),
end
=
datetime
(
2015
,
1
,
16
),
org
=
"MTD"
)
self
.
users
=
[
UserFactory
.
create
(
username
=
"testuser"
+
str
(
__
),
profile
=
'test'
)
for
__
in
xrange
(
USER_COUNT
)]
self
.
users
=
[
UserFactory
.
create
(
username
=
"testuser"
+
str
(
__
),
profile
=
'test'
)
for
__
in
xrange
(
USER_COUNT
)]
...
@@ -1630,6 +1635,13 @@ class CoursesApiTests(TestCase):
...
@@ -1630,6 +1635,13 @@ class CoursesApiTests(TestCase):
response
=
self
.
do_get
(
bogus_test_uri
)
response
=
self
.
do_get
(
bogus_test_uri
)
self
.
assertEqual
(
response
.
status_code
,
404
)
self
.
assertEqual
(
response
.
status_code
,
404
)
def
test_courses_metrics_grades_leaders_list_get_empty_course
(
self
):
test_uri
=
'{}/{}/metrics/grades/leaders/'
.
format
(
self
.
base_courses_uri
,
unicode
(
self
.
empty_course
.
id
))
response
=
self
.
do_get
(
test_uri
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
data
[
'course_avg'
],
0
)
self
.
assertEqual
(
len
(
response
.
data
[
'leaders'
]),
0
)
def
test_courses_completions_leaders_list_get
(
self
):
def
test_courses_completions_leaders_list_get
(
self
):
completion_uri
=
'{}/{}/completions/'
.
format
(
self
.
base_courses_uri
,
unicode
(
self
.
course
.
id
))
completion_uri
=
'{}/{}/completions/'
.
format
(
self
.
base_courses_uri
,
unicode
(
self
.
course
.
id
))
# Make last user as observer to make sure that data is being filtered out
# Make last user as observer to make sure that data is being filtered out
...
@@ -1722,6 +1734,14 @@ class CoursesApiTests(TestCase):
...
@@ -1722,6 +1734,14 @@ class CoursesApiTests(TestCase):
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
len
(
response
.
data
[
'grades'
]),
user_index
)
self
.
assertEqual
(
len
(
response
.
data
[
'grades'
]),
user_index
)
def
test_courses_metrics_grades_list_get_empty_course
(
self
):
# Retrieve the list of grades for this course
# All the course/item/user scaffolding was handled in Setup
test_uri
=
'{}/{}/metrics/grades'
.
format
(
self
.
base_courses_uri
,
unicode
(
self
.
empty_course
.
id
))
response
=
self
.
do_get
(
test_uri
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
data
[
'grade_count'
],
0
)
self
.
assertEqual
(
response
.
data
[
'course_grade_maximum'
],
0
)
def
test_courses_grades_list_get_invalid_course
(
self
):
def
test_courses_grades_list_get_invalid_course
(
self
):
# Retrieve the list of grades for this course
# Retrieve the list of grades for this course
...
...
lms/djangoapps/gradebook/models.py
View file @
c04fcc7b
...
@@ -56,52 +56,64 @@ class StudentGradebook(TimeStampedModel):
...
@@ -56,52 +56,64 @@ class StudentGradebook(TimeStampedModel):
have not yet submitted a response to a scored assessment which means no grade has been calculated.
have not yet submitted a response to a scored assessment which means no grade has been calculated.
"""
"""
data
=
{}
data
=
{}
data
[
'course_avg'
]
=
0
data
[
'course_max'
]
=
0
data
[
'course_min'
]
=
0
data
[
'course_count'
]
=
0
data
[
'queryset'
]
=
[]
total_user_count
=
CourseEnrollment
.
users_enrolled_in
(
course_key
)
.
count
()
total_user_count
=
CourseEnrollment
.
users_enrolled_in
(
course_key
)
.
count
()
queryset
=
StudentGradebook
.
objects
.
select_related
(
'user'
)
\
if
total_user_count
:
.
filter
(
course_id__exact
=
course_key
,
user__is_active
=
True
)
gradebook_user_count
=
len
(
queryset
)
if
exclude_users
:
# Generate the base data set we're going to work with
total_user_count
=
total_user_count
-
len
(
exclude_users
)
queryset
=
StudentGradebook
.
objects
.
select_related
(
'user'
)
\
queryset
=
queryset
.
exclude
(
user__in
=
exclude_users
)
.
filter
(
course_id__exact
=
course_key
,
user__is_active
=
True
)
gradebook_user_count
=
len
(
queryset
)
gradebook_user_count
=
len
(
queryset
)
# Calculate the class average
# Remove any users who should not be considered for the statistics
course_avg
=
queryset
.
aggregate
(
Avg
(
'grade'
))[
'grade__avg'
]
if
exclude_users
:
if
gradebook_user_count
<
total_user_count
:
total_user_count
=
total_user_count
-
len
(
exclude_users
)
# Take into account any ungraded students (assumes zeros for grades...)
queryset
=
queryset
.
exclude
(
user__in
=
exclude_users
)
course_avg
=
course_avg
/
total_user_count
*
gradebook_user_count
gradebook_user_count
=
len
(
queryset
)
data
[
'course_avg'
]
=
course_avg
data
[
'course_max'
]
=
queryset
.
aggregate
(
Max
(
'grade'
))[
'grade__max'
]
# Calculate the class average
data
[
'course_min'
]
=
queryset
.
aggregate
(
Min
(
'grade'
))[
'grade__min'
]
course_avg
=
queryset
.
aggregate
(
Avg
(
'grade'
))[
'grade__avg'
]
data
[
'course_count'
]
=
queryset
.
aggregate
(
Count
(
'grade'
))[
'grade__count'
]
if
gradebook_user_count
<
total_user_count
:
# Take into account any ungraded students (assumes zeros for grades...)
# Construct the leaderboard as a queryset
course_avg
=
course_avg
/
total_user_count
*
gradebook_user_count
data
[
'queryset'
]
=
queryset
.
values
(
'user__id'
,
# Fill up the response container
'user__username'
,
data
[
'course_avg'
]
=
course_avg
'user__profile__title'
,
data
[
'course_max'
]
=
queryset
.
aggregate
(
Max
(
'grade'
))[
'grade__max'
]
'user__profile__avatar_url'
,
data
[
'course_min'
]
=
queryset
.
aggregate
(
Min
(
'grade'
))[
'grade__min'
]
'grade'
,
data
[
'course_count'
]
=
queryset
.
aggregate
(
Count
(
'grade'
))[
'grade__count'
]
'created'
)
\
.
order_by
(
'-grade'
,
'created'
)[:
count
]
# Construct the leaderboard as a queryset
data
[
'queryset'
]
=
queryset
.
values
(
# If a user_id value was provided, we need to provide some additional user-specific data to the caller
'user__id'
,
if
user_id
:
'user__username'
,
user_grade
=
0
'user__profile__title'
,
user_time_scored
=
timezone
.
now
()
'user__profile__avatar_url'
,
try
:
'grade'
,
user_queryset
=
StudentGradebook
.
objects
.
get
(
course_id__exact
=
course_key
,
user__id
=
user_id
)
'created'
)
\
except
StudentGradebook
.
DoesNotExist
:
.
order_by
(
'-grade'
,
'created'
)[:
count
]
user_queryset
=
None
if
user_queryset
:
# If a user_id value was provided, we need to provide some additional user-specific data to the caller
user_grade
=
user_queryset
.
grade
if
user_id
:
user_time_scored
=
user_queryset
.
created
user_grade
=
0
users_above
=
queryset
.
filter
(
grade__gte
=
user_grade
)
\
user_time_scored
=
timezone
.
now
()
.
exclude
(
user__id
=
user_id
)
\
try
:
.
exclude
(
grade
=
user_grade
,
created__lt
=
user_time_scored
)
user_queryset
=
StudentGradebook
.
objects
.
get
(
course_id__exact
=
course_key
,
user__id
=
user_id
)
data
[
'user_position'
]
=
len
(
users_above
)
+
1
except
StudentGradebook
.
DoesNotExist
:
data
[
'user_grade'
]
=
user_grade
user_queryset
=
None
if
user_queryset
:
user_grade
=
user_queryset
.
grade
user_time_scored
=
user_queryset
.
created
users_above
=
queryset
.
filter
(
grade__gte
=
user_grade
)
\
.
exclude
(
user__id
=
user_id
)
\
.
exclude
(
grade
=
user_grade
,
created__lt
=
user_time_scored
)
data
[
'user_position'
]
=
len
(
users_above
)
+
1
data
[
'user_grade'
]
=
user_grade
return
data
return
data
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment