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
aa1333c3
Commit
aa1333c3
authored
Dec 16, 2014
by
Chris Rossi
Committed by
cewing
Apr 10, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MIT: CCX. Hide course blocks not in the CCX from view for coaches and students
parent
6cfc3a02
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
256 additions
and
101 deletions
+256
-101
common/lib/xmodule/xmodule/course_module.py
+18
-5
lms/djangoapps/courseware/grades.py
+11
-4
lms/djangoapps/instructor/offline_gradecalc.py
+0
-1
lms/djangoapps/pocs/overrides.py
+34
-0
lms/djangoapps/pocs/tests/test_views.py
+110
-33
lms/djangoapps/pocs/views.py
+83
-58
No files found.
common/lib/xmodule/xmodule/course_module.py
View file @
aa1333c3
...
@@ -11,7 +11,7 @@ from datetime import datetime
...
@@ -11,7 +11,7 @@ from datetime import datetime
import
dateutil.parser
import
dateutil.parser
from
lazy
import
lazy
from
lazy
import
lazy
from
xmodule.exceptions
import
UndefinedContext
from
xmodule.seq_module
import
SequenceDescriptor
,
SequenceModule
from
xmodule.seq_module
import
SequenceDescriptor
,
SequenceModule
from
xmodule.graders
import
grader_from_conf
from
xmodule.graders
import
grader_from_conf
from
xmodule.tabs
import
CourseTabList
from
xmodule.tabs
import
CourseTabList
...
@@ -1213,21 +1213,34 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
...
@@ -1213,21 +1213,34 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
"""
"""
try
:
module
=
getattr
(
self
,
'_xmodule'
,
None
)
if
not
module
:
module
=
self
except
UndefinedContext
:
module
=
self
all_descriptors
=
[]
all_descriptors
=
[]
graded_sections
=
{}
graded_sections
=
{}
def
yield_desc
riptor_descendents
(
module_descriptor
):
def
yield_desc
endents
(
module
):
for
child
in
module
_descriptor
.
get_children
():
for
child
in
module
.
get_children
():
yield
child
yield
child
for
module_descriptor
in
yield_desc
riptor_desc
endents
(
child
):
for
module_descriptor
in
yield_descendents
(
child
):
yield
module_descriptor
yield
module_descriptor
<<<<<<<
HEAD
for
chapter
in
self
.
get_children
():
for
chapter
in
self
.
get_children
():
for
section
in
chapter
.
get_children
():
for
section
in
chapter
.
get_children
():
if
section
.
graded
:
if
section
.
graded
:
xmoduledescriptors
=
list
(
yield_descriptor_descendents
(
section
))
xmoduledescriptors
=
list
(
yield_descriptor_descendents
(
section
))
xmoduledescriptors
.
append
(
section
)
xmoduledescriptors
.
append
(
section
)
=======
for
c
in
module
.
get_children
():
for
s
in
c
.
get_children
():
if
s
.
graded
:
xmoduledescriptors
=
list
(
yield_descendents
(
s
))
xmoduledescriptors
.
append
(
s
)
>>>>>>>
Hide
course
blocks
not
in
the
CCX
from
view
for
coaches
and
students
# The xmoduledescriptors included here are only the ones that have scores.
# The xmoduledescriptors included here are only the ones that have scores.
section_description
=
{
section_description
=
{
...
...
lms/djangoapps/courseware/grades.py
View file @
aa1333c3
...
@@ -246,6 +246,8 @@ def _grade(student, request, course, keep_raw_scores):
...
@@ -246,6 +246,8 @@ def _grade(student, request, course, keep_raw_scores):
totaled_scores
[
section_format
]
=
format_scores
totaled_scores
[
section_format
]
=
format_scores
# Grading policy might be overriden by a POC, need to reset it
course
.
set_grading_policy
(
course
.
grading_policy
)
grade_summary
=
course
.
grader
.
grade
(
totaled_scores
,
generate_random_scores
=
settings
.
GENERATE_PROFILE_SCORES
)
grade_summary
=
course
.
grader
.
grade
(
totaled_scores
,
generate_random_scores
=
settings
.
GENERATE_PROFILE_SCORES
)
# We round the grade here, to make sure that the grade is an whole percentage and
# We round the grade here, to make sure that the grade is an whole percentage and
...
@@ -329,6 +331,8 @@ def _progress_summary(student, request, course):
...
@@ -329,6 +331,8 @@ def _progress_summary(student, request, course):
# This student must not have access to the course.
# This student must not have access to the course.
return
None
return
None
course_module
=
getattr
(
course_module
,
'_x_module'
,
course_module
)
submissions_scores
=
sub_api
.
get_scores
(
course
.
id
.
to_deprecated_string
(),
anonymous_id_for_user
(
student
,
course
.
id
))
submissions_scores
=
sub_api
.
get_scores
(
course
.
id
.
to_deprecated_string
(),
anonymous_id_for_user
(
student
,
course
.
id
))
chapters
=
[]
chapters
=
[]
...
@@ -479,7 +483,7 @@ def manual_transaction():
...
@@ -479,7 +483,7 @@ def manual_transaction():
transaction
.
commit
()
transaction
.
commit
()
def
iterate_grades_for
(
course_id
,
students
):
def
iterate_grades_for
(
course_
or_
id
,
students
):
"""Given a course_id and an iterable of students (User), yield a tuple of:
"""Given a course_id and an iterable of students (User), yield a tuple of:
(student, gradeset, err_msg) for every student enrolled in the course.
(student, gradeset, err_msg) for every student enrolled in the course.
...
@@ -497,7 +501,10 @@ def iterate_grades_for(course_id, students):
...
@@ -497,7 +501,10 @@ def iterate_grades_for(course_id, students):
make up the final grade. (For display)
make up the final grade. (For display)
- raw_scores: contains scores for every graded module
- raw_scores: contains scores for every graded module
"""
"""
course
=
courses
.
get_course_by_id
(
course_id
)
if
isinstance
(
course_or_id
,
basestring
):
course
=
courses
.
get_course_by_id
(
course_or_id
)
else
:
course
=
course_or_id
# We make a fake request because grading code expects to be able to look at
# We make a fake request because grading code expects to be able to look at
# the request. We have to attach the correct user to the request before
# the request. We have to attach the correct user to the request before
...
@@ -505,7 +512,7 @@ def iterate_grades_for(course_id, students):
...
@@ -505,7 +512,7 @@ def iterate_grades_for(course_id, students):
request
=
RequestFactory
()
.
get
(
'/'
)
request
=
RequestFactory
()
.
get
(
'/'
)
for
student
in
students
:
for
student
in
students
:
with
dog_stats_api
.
timer
(
'lms.grades.iterate_grades_for'
,
tags
=
[
u'action:{}'
.
format
(
course
_
id
)]):
with
dog_stats_api
.
timer
(
'lms.grades.iterate_grades_for'
,
tags
=
[
u'action:{}'
.
format
(
course
.
id
)]):
try
:
try
:
request
.
user
=
student
request
.
user
=
student
# Grading calls problem rendering, which calls masquerading,
# Grading calls problem rendering, which calls masquerading,
...
@@ -522,7 +529,7 @@ def iterate_grades_for(course_id, students):
...
@@ -522,7 +529,7 @@ def iterate_grades_for(course_id, students):
'Cannot grade student
%
s (
%
s) in course
%
s because of exception:
%
s'
,
'Cannot grade student
%
s (
%
s) in course
%
s because of exception:
%
s'
,
student
.
username
,
student
.
username
,
student
.
id
,
student
.
id
,
course
_
id
,
course
.
id
,
exc
.
message
exc
.
message
)
)
yield
student
,
{},
exc
.
message
yield
student
,
{},
exc
.
message
lms/djangoapps/instructor/offline_gradecalc.py
View file @
aa1333c3
...
@@ -81,7 +81,6 @@ def student_grades(student, request, course, keep_raw_scores=False, use_offline=
...
@@ -81,7 +81,6 @@ def student_grades(student, request, course, keep_raw_scores=False, use_offline=
This is the main interface to get grades. It has the same parameters as grades.grade, as well
This is the main interface to get grades. It has the same parameters as grades.grade, as well
as use_offline. If use_offline is True then this will look for an offline computed gradeset in the DB.
as use_offline. If use_offline is True then this will look for an offline computed gradeset in the DB.
'''
'''
if
not
use_offline
:
if
not
use_offline
:
return
grades
.
grade
(
student
,
request
,
course
,
keep_raw_scores
=
keep_raw_scores
)
return
grades
.
grade
(
student
,
request
,
course
,
keep_raw_scores
=
keep_raw_scores
)
...
...
lms/djangoapps/pocs/overrides.py
View file @
aa1333c3
...
@@ -3,6 +3,9 @@ API related to providing field overrides for individual students. This is used
...
@@ -3,6 +3,9 @@ API related to providing field overrides for individual students. This is used
by the individual due dates feature.
by the individual due dates feature.
"""
"""
import
json
import
json
import
threading
from
contextlib
import
contextmanager
from
courseware.field_overrides
import
FieldOverrideProvider
from
courseware.field_overrides
import
FieldOverrideProvider
...
@@ -22,10 +25,41 @@ class PersonalOnlineCoursesOverrideProvider(FieldOverrideProvider):
...
@@ -22,10 +25,41 @@ class PersonalOnlineCoursesOverrideProvider(FieldOverrideProvider):
return
default
return
default
class
_PocContext
(
threading
.
local
):
"""
A threading local used to implement the `with_poc` context manager, that
keeps track of the POC currently set as the context.
"""
poc
=
None
_POC_CONTEXT
=
_PocContext
()
@contextmanager
def
poc_context
(
poc
):
"""
A context manager which can be used to explicitly set the POC that is in
play for field overrides. This mechanism overrides the standard mechanism
of looking in the user's session to see if they are enrolled in a POC and
viewing that POC.
"""
prev
=
_POC_CONTEXT
.
poc
_POC_CONTEXT
.
poc
=
poc
yield
_POC_CONTEXT
.
poc
=
prev
def
get_current_poc
(
user
):
def
get_current_poc
(
user
):
"""
"""
TODO Needs to look in user's session
TODO Needs to look in user's session
"""
"""
# If poc context is explicitly set, that takes precedence over the user's
# session.
poc
=
_POC_CONTEXT
.
poc
if
poc
:
return
poc
# Temporary implementation. Final implementation will need to look in
# Temporary implementation. Final implementation will need to look in
# user's session so user can switch between (potentially multiple) POC and
# user's session so user can switch between (potentially multiple) POC and
# MOOC views. See courseware.courses.get_request_for_thread for idea to
# MOOC views. See courseware.courses.get_request_for_thread for idea to
...
...
lms/djangoapps/pocs/tests/test_views.py
View file @
aa1333c3
...
@@ -5,9 +5,11 @@ import pytz
...
@@ -5,9 +5,11 @@ import pytz
from
mock
import
patch
from
mock
import
patch
from
capa.tests.response_xml_factory
import
StringResponseXMLFactory
from
capa.tests.response_xml_factory
import
StringResponseXMLFactory
from
courseware.field_overrides
import
OverrideFieldData
from
courseware.tests.factories
import
StudentModuleFactory
from
courseware.tests.factories
import
StudentModuleFactory
from
courseware.tests.helpers
import
LoginEnrollmentTestCase
from
courseware.tests.helpers
import
LoginEnrollmentTestCase
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
django.test.utils
import
override_settings
from
edxmako.shortcuts
import
render_to_response
from
edxmako.shortcuts
import
render_to_response
from
student.roles
import
CoursePocCoachRole
from
student.roles
import
CoursePocCoachRole
from
student.tests.factories
import
(
from
student.tests.factories
import
(
...
@@ -26,7 +28,7 @@ from ..models import (
...
@@ -26,7 +28,7 @@ from ..models import (
PocMembership
,
PocMembership
,
PocFutureMembership
,
PocFutureMembership
,
)
)
from
..overrides
import
get_override_for_poc
from
..overrides
import
get_override_for_poc
,
override_field_for_poc
from
.factories
import
(
from
.factories
import
(
PocFactory
,
PocFactory
,
PocMembershipFactory
,
PocMembershipFactory
,
...
@@ -369,9 +371,8 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
...
@@ -369,9 +371,8 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
)
)
USER_COUNT
=
2
@override_settings
(
FIELD_OVERRIDE_PROVIDERS
=
(
'pocs.overrides.PersonalOnlineCoursesOverrideProvider'
,))
class
TestPocGrades
(
ModuleStoreTestCase
,
LoginEnrollmentTestCase
):
class
TestPocGrades
(
ModuleStoreTestCase
,
LoginEnrollmentTestCase
):
"""
"""
Tests for Personal Online Courses views.
Tests for Personal Online Courses views.
...
@@ -391,39 +392,65 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase):
...
@@ -391,39 +392,65 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase):
2010
,
5
,
12
,
2
,
42
,
tzinfo
=
pytz
.
UTC
)
2010
,
5
,
12
,
2
,
42
,
tzinfo
=
pytz
.
UTC
)
chapter
=
ItemFactory
.
create
(
chapter
=
ItemFactory
.
create
(
start
=
start
,
parent
=
course
,
category
=
'sequential'
)
start
=
start
,
parent
=
course
,
category
=
'sequential'
)
section
=
ItemFactory
.
create
(
sections
=
[
parent
=
chapter
,
ItemFactory
.
create
(
category
=
"sequential"
,
parent
=
chapter
,
metadata
=
{
'graded'
:
True
,
'format'
:
'Homework'
}
category
=
"sequential"
,
)
metadata
=
{
'graded'
:
True
,
'format'
:
'Homework'
})
for
_
in
xrange
(
4
)]
role
=
CoursePocCoachRole
(
self
.
course
.
id
)
role
=
CoursePocCoachRole
(
self
.
course
.
id
)
role
.
add_users
(
coach
)
role
.
add_users
(
coach
)
self
.
poc
=
poc
=
PocFactory
(
course_id
=
self
.
course
.
id
,
coach
=
self
.
coach
)
self
.
poc
=
poc
=
PocFactory
(
course_id
=
self
.
course
.
id
,
coach
=
self
.
coach
)
self
.
users
=
[
UserFactory
.
create
()
for
_
in
xrange
(
USER_COUNT
)]
self
.
student
=
student
=
UserFactory
.
create
()
for
user
in
self
.
users
:
CourseEnrollmentFactory
.
create
(
user
=
student
,
course_id
=
self
.
course
.
id
)
CourseEnrollmentFactory
.
create
(
user
=
user
,
course_id
=
self
.
course
.
id
)
PocMembershipFactory
(
poc
=
poc
,
student
=
student
,
active
=
True
)
PocMembershipFactory
(
poc
=
poc
,
student
=
user
,
active
=
True
)
for
i
,
section
in
enumerate
(
sections
):
for
i
in
xrange
(
USER_COUNT
-
1
):
for
j
in
xrange
(
4
):
category
=
"problem"
item
=
ItemFactory
.
create
(
item
=
ItemFactory
.
create
(
parent
=
section
,
parent_location
=
section
.
location
,
category
=
"problem"
,
category
=
category
,
data
=
StringResponseXMLFactory
()
.
build_xml
(
answer
=
'foo'
),
data
=
StringResponseXMLFactory
()
.
build_xml
(
answer
=
'foo'
),
metadata
=
{
'rerandomize'
:
'always'
}
metadata
=
{
'rerandomize'
:
'always'
}
)
)
for
j
,
user
in
enumerate
(
self
.
users
):
StudentModuleFactory
.
create
(
StudentModuleFactory
.
create
(
grade
=
1
if
i
<
j
else
0
,
grade
=
1
if
i
<
j
else
0
,
max_grade
=
1
,
max_grade
=
1
,
student
=
user
,
student
=
student
,
course_id
=
self
.
course
.
id
,
course_id
=
self
.
course
.
id
,
module_state_key
=
item
.
location
module_state_key
=
item
.
location
)
)
# Apparently the test harness doesn't use LmsFieldStorage, and I'm not
# sure if there's a way to poke the test harness to do so. So, we'll
# just inject the override field storage in this brute force manner.
OverrideFieldData
.
provider_classes
=
None
for
block
in
iter_blocks
(
course
):
block
.
_field_data
=
OverrideFieldData
.
wrap
(
# pylint: disable=protected-access
coach
,
block
.
_field_data
)
# pylint: disable=protected-access
block
.
_field_data_cache
=
{}
visible_children
(
block
)
patch_context
=
patch
(
'pocs.views.get_course_by_id'
)
get_course
=
patch_context
.
start
()
get_course
.
return_value
=
course
self
.
addCleanup
(
patch_context
.
stop
)
override_field_for_poc
(
poc
,
course
,
'grading_policy'
,
{
'GRADER'
:
[
{
'drop_count'
:
0
,
'min_count'
:
2
,
'short_label'
:
'HW'
,
'type'
:
'Homework'
,
'weight'
:
1
}
],
'GRADE_CUTOFFS'
:
{
'Pass'
:
0.75
},
})
override_field_for_poc
(
poc
,
sections
[
-
1
],
'visible_to_staff_only'
,
True
)
@patch
(
'pocs.views.render_to_response'
,
intercept_renderer
)
@patch
(
'pocs.views.render_to_response'
,
intercept_renderer
)
def
test_gradebook
(
self
):
def
test_gradebook
(
self
):
...
@@ -433,13 +460,13 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase):
...
@@ -433,13 +460,13 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase):
)
)
response
=
self
.
client
.
get
(
url
)
response
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
status_code
,
200
)
student_info
=
response
.
mako_context
[
'students'
]
student_info
=
response
.
mako_context
[
'students'
][
0
]
self
.
assertEqual
(
len
(
student_info
),
USER_COUNT
)
self
.
assertEqual
(
student_info
[
'grade_summary'
][
'percent'
],
0.5
)
self
.
assertEqual
(
student_info
[
0
][
'grade_summary'
][
'percent'
],
0.0
)
self
.
assertEqual
(
student_info
[
1
][
'grade_summary'
][
'percent'
],
0.02
)
self
.
assertEqual
(
self
.
assertEqual
(
student_info
[
1
][
'grade_summary'
][
'grade_breakdown'
][
0
][
'percent'
],
student_info
[
'grade_summary'
][
'grade_breakdown'
][
0
][
'percent'
],
0.015
)
0.5
)
self
.
assertEqual
(
len
(
student_info
[
'grade_summary'
][
'section_breakdown'
]),
4
)
def
test_grades_csv
(
self
):
def
test_grades_csv
(
self
):
url
=
reverse
(
url
=
reverse
(
...
@@ -448,8 +475,35 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase):
...
@@ -448,8 +475,35 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase):
)
)
response
=
self
.
client
.
get
(
url
)
response
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
headers
,
row
=
(
len
(
response
.
content
.
strip
()
.
split
(
'
\n
'
)),
USER_COUNT
+
1
)
row
.
strip
()
.
split
(
','
)
for
row
in
response
.
content
.
strip
()
.
split
(
'
\n
'
)
)
data
=
dict
(
zip
(
headers
,
row
))
self
.
assertEqual
(
data
[
'HW 01'
],
'0.75'
)
self
.
assertEqual
(
data
[
'HW 02'
],
'0.5'
)
self
.
assertEqual
(
data
[
'HW 03'
],
'0.25'
)
self
.
assertEqual
(
data
[
'HW Avg'
],
'0.5'
)
self
.
assertTrue
(
'HW 04'
not
in
data
)
@patch
(
'courseware.views.render_to_response'
,
intercept_renderer
)
def
test_student_progress
(
self
):
patch_context
=
patch
(
'courseware.views.get_course_with_access'
)
get_course
=
patch_context
.
start
()
get_course
.
return_value
=
self
.
course
self
.
addCleanup
(
patch_context
.
stop
)
self
.
client
.
login
(
username
=
self
.
student
.
username
,
password
=
"test"
)
url
=
reverse
(
'progress'
,
kwargs
=
{
'course_id'
:
self
.
course
.
id
.
to_deprecated_string
()}
)
response
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
grades
=
response
.
mako_context
[
'grade_summary'
]
self
.
assertEqual
(
grades
[
'percent'
],
0.5
)
self
.
assertEqual
(
grades
[
'grade_breakdown'
][
0
][
'percent'
],
0.5
)
self
.
assertEqual
(
len
(
grades
[
'section_breakdown'
]),
4
)
def
flatten
(
seq
):
def
flatten
(
seq
):
...
@@ -457,3 +511,26 @@ def flatten(seq):
...
@@ -457,3 +511,26 @@ def flatten(seq):
For [[1, 2], [3, 4]] returns [1, 2, 3, 4]. Does not recurse.
For [[1, 2], [3, 4]] returns [1, 2, 3, 4]. Does not recurse.
"""
"""
return
[
x
for
sub
in
seq
for
x
in
sub
]
return
[
x
for
sub
in
seq
for
x
in
sub
]
def
iter_blocks
(
course
):
"""
Returns an iterator over all of the blocks in a course.
"""
def
visit
(
block
):
yield
block
for
child
in
block
.
get_children
():
for
descendant
in
visit
(
child
):
# wish they'd backport yield from
yield
descendant
return
visit
(
course
)
def
visible_children
(
block
):
block_get_children
=
block
.
get_children
def
get_children
():
def
iter_children
():
for
child
in
block_get_children
():
child
.
_field_data_cache
=
{}
if
not
child
.
visible_to_staff_only
:
yield
child
return
list
(
iter_children
())
block
.
get_children
=
get_children
lms/djangoapps/pocs/views.py
View file @
aa1333c3
...
@@ -20,6 +20,8 @@ from django.contrib.auth.models import User
...
@@ -20,6 +20,8 @@ from django.contrib.auth.models import User
from
courseware.courses
import
get_course_by_id
from
courseware.courses
import
get_course_by_id
from
courseware.field_overrides
import
disable_overrides
from
courseware.field_overrides
import
disable_overrides
from
courseware.grades
import
iterate_grades_for
from
courseware.grades
import
iterate_grades_for
from
courseware.model_data
import
FieldDataCache
from
courseware.module_render
import
get_module_for_descriptor
from
edxmako.shortcuts
import
render_to_response
from
edxmako.shortcuts
import
render_to_response
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
student.roles
import
CoursePocCoachRole
from
student.roles
import
CoursePocCoachRole
...
@@ -33,6 +35,7 @@ from .overrides import (
...
@@ -33,6 +35,7 @@ from .overrides import (
clear_override_for_poc
,
clear_override_for_poc
,
get_override_for_poc
,
get_override_for_poc
,
override_field_for_poc
,
override_field_for_poc
,
poc_context
,
)
)
from
.utils
import
enroll_email
,
unenroll_email
from
.utils
import
enroll_email
,
unenroll_email
...
@@ -290,68 +293,90 @@ def poc_gradebook(request, course):
...
@@ -290,68 +293,90 @@ def poc_gradebook(request, course):
"""
"""
Show the gradebook for this POC.
Show the gradebook for this POC.
"""
"""
# Need course module for overrides to function properly
field_data_cache
=
FieldDataCache
.
cache_for_descriptor_descendents
(
course
.
id
,
request
.
user
,
course
,
depth
=
2
)
course
=
get_module_for_descriptor
(
request
.
user
,
request
,
course
,
field_data_cache
,
course
.
id
)
poc
=
get_poc_for_coach
(
course
,
request
.
user
)
poc
=
get_poc_for_coach
(
course
,
request
.
user
)
enrolled_students
=
User
.
objects
.
filter
(
with
poc_context
(
poc
):
pocmembership__poc
=
poc
,
course
.
_field_data_cache
=
{}
pocmembership__active
=
1
course
.
set_grading_policy
(
course
.
grading_policy
)
# this is so awful
)
.
order_by
(
'username'
)
.
select_related
(
"profile"
)
enrolled_students
=
User
.
objects
.
filter
(
pocmembership__poc
=
poc
,
student_info
=
[
pocmembership__active
=
1
{
)
.
order_by
(
'username'
)
.
select_related
(
"profile"
)
'username'
:
student
.
username
,
'id'
:
student
.
id
,
student_info
=
[
'email'
:
student
.
email
,
{
'grade_summary'
:
student_grades
(
student
,
request
,
course
),
'username'
:
student
.
username
,
'realname'
:
student
.
profile
.
name
,
'id'
:
student
.
id
,
}
'email'
:
student
.
email
,
for
student
in
enrolled_students
'grade_summary'
:
student_grades
(
student
,
request
,
course
),
]
'realname'
:
student
.
profile
.
name
,
}
return
render_to_response
(
'courseware/gradebook.html'
,
{
for
student
in
enrolled_students
'students'
:
student_info
,
]
'course'
:
course
,
'course_id'
:
course
.
id
,
return
render_to_response
(
'courseware/gradebook.html'
,
{
'staff_access'
:
request
.
user
.
is_staff
,
'students'
:
student_info
,
'ordered_grades'
:
sorted
(
'course'
:
course
,
course
.
grade_cutoffs
.
items
(),
key
=
lambda
i
:
i
[
1
],
reverse
=
True
),
'course_id'
:
course
.
id
,
})
'staff_access'
:
request
.
user
.
is_staff
,
'ordered_grades'
:
sorted
(
course
.
grade_cutoffs
.
items
(),
key
=
lambda
i
:
i
[
1
],
reverse
=
True
),
})
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@coach_dashboard
@coach_dashboard
def
poc_grades_csv
(
request
,
course
):
def
poc_grades_csv
(
request
,
course
):
poc
=
get_poc_for_coach
(
course
,
request
.
user
)
"""
enrolled_students
=
User
.
objects
.
filter
(
Download grades as CSV.
pocmembership__poc
=
poc
,
"""
pocmembership__active
=
1
# Need course module for overrides to function properly
)
.
order_by
(
'username'
)
.
select_related
(
"profile"
)
field_data_cache
=
FieldDataCache
.
cache_for_descriptor_descendents
(
grades
=
iterate_grades_for
(
course
.
id
,
enrolled_students
)
course
.
id
,
request
.
user
,
course
,
depth
=
2
)
course
=
get_module_for_descriptor
(
header
=
None
request
.
user
,
request
,
course
,
field_data_cache
,
course
.
id
)
rows
=
[]
for
student
,
gradeset
,
err_msg
in
grades
:
if
gradeset
:
# We were able to successfully grade this student for this course.
if
not
header
:
# Encode the header row in utf-8 encoding in case there are
# unicode characters
header
=
[
section
[
'label'
]
.
encode
(
'utf-8'
)
for
section
in
gradeset
[
u'section_breakdown'
]]
rows
.
append
([
"id"
,
"email"
,
"username"
,
"grade"
]
+
header
)
percents
=
{
section
[
'label'
]:
section
.
get
(
'percent'
,
0.0
)
for
section
in
gradeset
[
u'section_breakdown'
]
if
'label'
in
section
}
row_percents
=
[
percents
.
get
(
label
,
0.0
)
for
label
in
header
]
rows
.
append
([
student
.
id
,
student
.
email
,
student
.
username
,
gradeset
[
'percent'
]]
+
row_percents
)
buffer
=
StringIO
()
writer
=
csv
.
writer
(
buffer
)
for
row
in
rows
:
writer
.
writerow
(
row
)
return
HttpResponse
(
buffer
.
getvalue
(),
content_type
=
'text/csv'
)
poc
=
get_poc_for_coach
(
course
,
request
.
user
)
with
poc_context
(
poc
):
course
.
_field_data_cache
=
{}
course
.
set_grading_policy
(
course
.
grading_policy
)
# this is so awful
enrolled_students
=
User
.
objects
.
filter
(
pocmembership__poc
=
poc
,
pocmembership__active
=
1
)
.
order_by
(
'username'
)
.
select_related
(
"profile"
)
grades
=
iterate_grades_for
(
course
,
enrolled_students
)
header
=
None
rows
=
[]
for
student
,
gradeset
,
err_msg
in
grades
:
if
gradeset
:
# We were able to successfully grade this student for this
# course.
if
not
header
:
# Encode the header row in utf-8 encoding in case there are
# unicode characters
header
=
[
section
[
'label'
]
.
encode
(
'utf-8'
)
for
section
in
gradeset
[
u'section_breakdown'
]]
rows
.
append
([
"id"
,
"email"
,
"username"
,
"grade"
]
+
header
)
percents
=
{
section
[
'label'
]:
section
.
get
(
'percent'
,
0.0
)
for
section
in
gradeset
[
u'section_breakdown'
]
if
'label'
in
section
}
row_percents
=
[
percents
.
get
(
label
,
0.0
)
for
label
in
header
]
rows
.
append
([
student
.
id
,
student
.
email
,
student
.
username
,
gradeset
[
'percent'
]]
+
row_percents
)
buffer
=
StringIO
()
writer
=
csv
.
writer
(
buffer
)
for
row
in
rows
:
writer
.
writerow
(
row
)
return
HttpResponse
(
buffer
.
getvalue
(),
content_type
=
'text/plain'
)
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