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
993c24b7
Commit
993c24b7
authored
Jan 08, 2013
by
Calen Pennington
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
WIP: Model data caching work
parent
507d2021
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
170 additions
and
234 deletions
+170
-234
common/lib/xmodule/xmodule/course_module.py
+1
-1
lms/djangoapps/courseware/courses.py
+30
-8
lms/djangoapps/courseware/grades.py
+57
-41
lms/djangoapps/courseware/management/commands/check_course.py
+2
-2
lms/djangoapps/courseware/model_data.py
+0
-0
lms/djangoapps/courseware/models.py
+0
-103
lms/djangoapps/courseware/module_render.py
+22
-27
lms/djangoapps/courseware/tests/test_model_data.py
+36
-27
lms/djangoapps/courseware/tests/tests.py
+5
-5
lms/djangoapps/courseware/views.py
+13
-16
lms/templates/courseware/info.html
+4
-4
No files found.
common/lib/xmodule/xmodule/course_module.py
View file @
993c24b7
...
...
@@ -358,7 +358,7 @@ class CourseDescriptor(SequenceDescriptor):
all_descriptors - This contains a list of all xmodules that can
effect grading a student. This is used to efficiently fetch
all the xmodule state for a
StudentModule
Cache without walking
all the xmodule state for a
ModelData
Cache without walking
the descriptor tree again.
...
...
lms/djangoapps/courseware/courses.py
View file @
993c24b7
...
...
@@ -19,10 +19,10 @@ from xmodule.contentstore.content import StaticContent
from
xmodule.modulestore.xml
import
XMLModuleStore
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
xmodule.x_module
import
XModule
from
courseware.model_data
import
ModelDataCache
from
static_replace
import
replace_urls
,
try_staticfiles_lookup
from
courseware.access
import
has_access
import
branding
from
courseware.models
import
StudentModuleCache
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -148,12 +148,23 @@ def get_course_about_section(course, section_key):
request
=
get_request_for_thread
()
loc
=
course
.
location
.
_replace
(
category
=
'about'
,
name
=
section_key
)
course_module
=
get_module
(
request
.
user
,
request
,
loc
,
None
,
course
.
id
,
not_found_ok
=
True
,
wrap_xmodule_display
=
True
)
# Use an empty cache
model_data_cache
=
ModelDataCache
([],
course
.
id
,
request
.
user
)
about_module
=
get_module
(
request
.
user
,
request
,
loc
,
model_data_cache
,
course
.
id
,
not_found_ok
=
True
,
wrap_xmodule_display
=
True
)
html
=
''
if
course
_module
is
not
None
:
html
=
course
_module
.
get_html
()
if
about
_module
is
not
None
:
html
=
about
_module
.
get_html
()
return
html
...
...
@@ -174,7 +185,7 @@ def get_course_about_section(course, section_key):
def
get_course_info_section
(
request
,
c
ache
,
c
ourse
,
section_key
):
def
get_course_info_section
(
request
,
course
,
section_key
):
"""
This returns the snippet of html to be rendered on the course info page,
given the key for the section.
...
...
@@ -188,11 +199,22 @@ def get_course_info_section(request, cache, course, section_key):
loc
=
Location
(
course
.
location
.
tag
,
course
.
location
.
org
,
course
.
location
.
course
,
'course_info'
,
section_key
)
course_module
=
get_module
(
request
.
user
,
request
,
loc
,
cache
,
course
.
id
,
wrap_xmodule_display
=
True
)
# Use an empty cache
model_data_cache
=
ModelDataCache
([],
course
.
id
,
request
.
user
)
info_module
=
get_module
(
request
.
user
,
request
,
loc
,
model_data_cache
,
course
.
id
,
wrap_xmodule_display
=
True
)
html
=
''
if
course
_module
is
not
None
:
html
=
course
_module
.
get_html
()
if
info
_module
is
not
None
:
html
=
info
_module
.
get_html
()
return
html
...
...
lms/djangoapps/courseware/grades.py
View file @
993c24b7
This diff is collapsed.
Click to expand it.
lms/djangoapps/courseware/management/commands/check_course.py
View file @
993c24b7
...
...
@@ -13,7 +13,7 @@ import xmodule
import
mitxmako.middleware
as
middleware
middleware
.
MakoMiddleware
()
from
xmodule.modulestore.django
import
modulestore
from
courseware.model
s
import
StudentModule
Cache
from
courseware.model
_data
import
ModelData
Cache
from
courseware.module_render
import
get_module
...
...
@@ -83,7 +83,7 @@ class Command(BaseCommand):
# TODO (cpennington): Get coursename in a legitimate way
course_location = 'i4x://edx/6002xs12/course/6.002_Spring_2012'
student_module_cache =
StudentModule
Cache.cache_for_descriptor_descendents(
student_module_cache =
ModelData
Cache.cache_for_descriptor_descendents(
course_id,
sample_user, modulestore().get_item(course_location))
course = get_module(sample_user, None, course_location, student_module_cache)
...
...
lms/djangoapps/courseware/model_data.py
View file @
993c24b7
This diff is collapsed.
Click to expand it.
lms/djangoapps/courseware/models.py
View file @
993c24b7
...
...
@@ -198,106 +198,3 @@ class XModuleStudentInfoField(models.Model):
def
__unicode__
(
self
):
return
unicode
(
repr
(
self
))
# TODO (cpennington): Remove these once the LMS switches to using XModuleDescriptors
class
StudentModuleCache
(
object
):
"""
A cache of StudentModules for a specific student
"""
def
__init__
(
self
,
course_id
,
user
,
descriptors
,
select_for_update
=
False
):
'''
Find any StudentModule objects that are needed by any descriptor
in descriptors. Avoids making multiple queries to the database.
Note: Only modules that have store_state = True or have shared
state will have a StudentModule.
Arguments
user: The user for which to fetch maching StudentModules
descriptors: An array of XModuleDescriptors.
select_for_update: Flag indicating whether the rows should be locked until end of transaction
'''
if
user
.
is_authenticated
():
module_ids
=
self
.
_get_module_state_keys
(
descriptors
)
# This works around a limitation in sqlite3 on the number of parameters
# that can be put into a single query
self
.
cache
=
[]
chunk_size
=
500
for
id_chunk
in
[
module_ids
[
i
:
i
+
chunk_size
]
for
i
in
xrange
(
0
,
len
(
module_ids
),
chunk_size
)]:
if
select_for_update
:
self
.
cache
.
extend
(
StudentModule
.
objects
.
select_for_update
()
.
filter
(
course_id
=
course_id
,
student
=
user
,
module_state_key__in
=
id_chunk
)
)
else
:
self
.
cache
.
extend
(
StudentModule
.
objects
.
filter
(
course_id
=
course_id
,
student
=
user
,
module_state_key__in
=
id_chunk
)
)
else
:
self
.
cache
=
[]
@classmethod
def
cache_for_descriptor_descendents
(
cls
,
course_id
,
user
,
descriptor
,
depth
=
None
,
descriptor_filter
=
lambda
descriptor
:
True
,
select_for_update
=
False
):
"""
course_id: the course in the context of which we want StudentModules.
user: the django user for whom to load modules.
descriptor: An XModuleDescriptor
depth is the number of levels of descendent modules to load StudentModules for, in addition to
the supplied descriptor. If depth is None, load all descendent StudentModules
descriptor_filter is a function that accepts a descriptor and return wether the StudentModule
should be cached
select_for_update: Flag indicating whether the rows should be locked until end of transaction
"""
def
get_child_descriptors
(
descriptor
,
depth
,
descriptor_filter
):
if
descriptor_filter
(
descriptor
):
descriptors
=
[
descriptor
]
else
:
descriptors
=
[]
if
depth
is
None
or
depth
>
0
:
new_depth
=
depth
-
1
if
depth
is
not
None
else
depth
for
child
in
descriptor
.
get_children
():
descriptors
.
extend
(
get_child_descriptors
(
child
,
new_depth
,
descriptor_filter
))
return
descriptors
descriptors
=
get_child_descriptors
(
descriptor
,
depth
,
descriptor_filter
)
return
StudentModuleCache
(
course_id
,
user
,
descriptors
,
select_for_update
)
def
_get_module_state_keys
(
self
,
descriptors
):
'''
Get a list of the state_keys needed for StudentModules
required for this module descriptor
descriptor_filter is a function that accepts a descriptor and return wether the StudentModule
should be cached
'''
return
[
descriptor
.
location
.
url
()
for
descriptor
in
descriptors
if
descriptor
.
stores_state
]
def
lookup
(
self
,
course_id
,
module_type
,
module_state_key
):
'''
Look for a student module with the given course_id, type, and id in the cache.
cache -- list of student modules
returns first found object, or None
'''
for
o
in
self
.
cache
:
if
(
o
.
course_id
==
course_id
and
o
.
module_type
==
module_type
and
o
.
module_state_key
==
module_state_key
):
return
o
return
None
def
append
(
self
,
student_module
):
self
.
cache
.
append
(
student_module
)
lms/djangoapps/courseware/module_render.py
View file @
993c24b7
...
...
@@ -17,7 +17,7 @@ from capa.xqueue_interface import XQueueInterface
from
capa.chem
import
chemcalc
from
courseware.access
import
has_access
from
mitxmako.shortcuts
import
render_to_string
from
models
import
StudentModule
,
StudentModuleCache
from
models
import
StudentModule
from
psychometrics.psychoanalyze
import
make_psychometrics_data_update_handler
from
static_replace
import
replace_urls
from
xmodule.errortracker
import
exc_info_to_str
...
...
@@ -28,7 +28,7 @@ from xmodule.x_module import ModuleSystem
from
xmodule.error_module
import
ErrorDescriptor
,
NonStaffErrorDescriptor
from
xblock.runtime
import
DbModel
from
xmodule_modifiers
import
replace_course_urls
,
replace_static_urls
,
add_histogram
,
wrap_xmodule
from
.model_data
import
LmsKeyValueStore
,
LmsUsage
from
.model_data
import
LmsKeyValueStore
,
LmsUsage
,
ModelDataCache
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
statsd
import
statsd
...
...
@@ -60,7 +60,7 @@ def make_track_function(request):
return
f
def
toc_for_course
(
user
,
request
,
course
,
active_chapter
,
active_section
):
def
toc_for_course
(
user
,
request
,
course
,
active_chapter
,
active_section
,
model_data_cache
):
'''
Create a table of contents from the module store
...
...
@@ -80,11 +80,11 @@ def toc_for_course(user, request, course, active_chapter, active_section):
NOTE: assumes that if we got this far, user has access to course. Returns
None if this is not the case.
model_data_cache must include data from the course module and 2 levels of its descendents
'''
student_module_cache
=
StudentModuleCache
.
cache_for_descriptor_descendents
(
course
.
id
,
user
,
course
,
depth
=
2
)
course_module
=
get_module
(
user
,
request
,
course
.
location
,
student_module_cache
,
course
.
id
)
course_module
=
get_module
(
user
,
request
,
course
.
location
,
model_data_cache
,
course
.
id
)
if
course_module
is
None
:
return
None
...
...
@@ -115,7 +115,7 @@ def toc_for_course(user, request, course, active_chapter, active_section):
return
chapters
def
get_module
(
user
,
request
,
location
,
student_module
_cache
,
course_id
,
def
get_module
(
user
,
request
,
location
,
model_data
_cache
,
course_id
,
position
=
None
,
not_found_ok
=
False
,
wrap_xmodule_display
=
True
,
grade_bucket_type
=
None
):
"""
...
...
@@ -128,7 +128,7 @@ def get_module(user, request, location, student_module_cache, course_id,
- request : current django HTTPrequest. Note: request.user isn't used for anything--all auth
and such works based on user.
- location : A Location-like object identifying the module to load
-
student_module_cache : a StudentModule
Cache
-
model_data_cache : a ModelData
Cache
- course_id : the course_id in the context of which to load module
- position : extra information from URL for user-specified
position within module
...
...
@@ -138,7 +138,7 @@ def get_module(user, request, location, student_module_cache, course_id,
if possible. If not possible, return None.
"""
try
:
return
_get_module
(
user
,
request
,
location
,
student_module
_cache
,
course_id
,
position
,
wrap_xmodule_display
)
return
_get_module
(
user
,
request
,
location
,
model_data
_cache
,
course_id
,
position
,
wrap_xmodule_display
)
except
ItemNotFoundError
:
if
not
not_found_ok
:
log
.
exception
(
"Error in get_module"
)
...
...
@@ -149,7 +149,7 @@ def get_module(user, request, location, student_module_cache, course_id,
return
None
def
_get_module
(
user
,
request
,
location
,
student_module
_cache
,
course_id
,
def
_get_module
(
user
,
request
,
location
,
model_data
_cache
,
course_id
,
position
=
None
,
wrap_xmodule_display
=
True
,
grade_bucket_type
=
None
):
"""
Actually implement get_module. See docstring there for details.
...
...
@@ -204,11 +204,11 @@ def _get_module(user, request, location, student_module_cache, course_id,
Delegate to get_module. It does an access check, so may return None
"""
return
get_module
(
user
,
request
,
location
,
student_module
_cache
,
course_id
,
position
)
model_data
_cache
,
course_id
,
position
)
def
xblock_model_data
(
descriptor
):
return
DbModel
(
LmsKeyValueStore
(
course_id
,
user
,
descriptor
.
_model_data
,
student_module
_cache
),
LmsKeyValueStore
(
descriptor
.
_model_data
,
model_data
_cache
),
descriptor
.
module_class
,
user
.
id
,
LmsUsage
(
location
,
location
)
...
...
@@ -218,18 +218,13 @@ def _get_module(user, request, location, student_module_cache, course_id,
if
event
.
get
(
'event_name'
)
!=
'grade'
:
return
student_module
=
student_module_cache
.
lookup
(
course_id
,
descriptor
.
location
.
category
,
descriptor
.
location
.
url
()
student_module
,
created
=
StudentModule
.
objects
.
get_or_create
(
course_id
=
course_id
,
student
=
user
,
module_type
=
descriptor
.
location
.
category
,
module_state_key
=
descriptor
.
location
.
url
(),
defaults
=
{
'state'
:
'{}'
},
)
if
student_module
is
None
:
student_module
=
StudentModule
(
course_id
=
course_id
,
student
=
user
,
module_type
=
descriptor
.
location
.
category
,
module_state_key
=
descriptor
.
location
.
url
(),
state
=
json
.
dumps
({})
)
student_module_cache
.
append
(
student_module
)
student_module
.
grade
=
event
.
get
(
'value'
)
student_module
.
max_grade
=
event
.
get
(
'max_value'
)
student_module
.
save
()
...
...
@@ -335,9 +330,9 @@ def xqueue_callback(request, course_id, userid, id, dispatch):
# Retrieve target StudentModule
user
=
User
.
objects
.
get
(
id
=
userid
)
student_module_cache
=
StudentModule
Cache
.
cache_for_descriptor_descendents
(
course_id
,
model_data_cache
=
ModelData
Cache
.
cache_for_descriptor_descendents
(
course_id
,
user
,
modulestore
()
.
get_instance
(
course_id
,
id
),
depth
=
0
,
select_for_update
=
True
)
instance
=
get_module
(
user
,
request
,
id
,
student_module
_cache
,
course_id
,
grade_bucket_type
=
'xqueue'
)
instance
=
get_module
(
user
,
request
,
id
,
model_data
_cache
,
course_id
,
grade_bucket_type
=
'xqueue'
)
if
instance
is
None
:
log
.
debug
(
"No module {0} for user {1}--access denied?"
.
format
(
id
,
user
))
raise
Http404
...
...
@@ -394,10 +389,10 @@ def modx_dispatch(request, dispatch, location, course_id):
return
HttpResponse
(
json
.
dumps
({
'success'
:
file_too_big_msg
}))
p
[
fileinput_id
]
=
inputfiles
student_module_cache
=
StudentModule
Cache
.
cache_for_descriptor_descendents
(
course_id
,
model_data_cache
=
ModelData
Cache
.
cache_for_descriptor_descendents
(
course_id
,
request
.
user
,
modulestore
()
.
get_instance
(
course_id
,
location
))
instance
=
get_module
(
request
.
user
,
request
,
location
,
student_module
_cache
,
course_id
,
grade_bucket_type
=
'ajax'
)
instance
=
get_module
(
request
.
user
,
request
,
location
,
model_data
_cache
,
course_id
,
grade_bucket_type
=
'ajax'
)
if
instance
is
None
:
# Either permissions just changed, or someone is trying to be clever
# and load something they shouldn't have access to.
...
...
lms/djangoapps/courseware/tests/test_model_data.py
View file @
993c24b7
...
...
@@ -5,18 +5,26 @@ from django.contrib.auth.models import User
from
functools
import
partial
from
courseware.model_data
import
LmsKeyValueStore
,
InvalidWriteError
,
InvalidScopeError
from
courseware.models
import
StudentModule
,
XModuleContentField
,
XModuleSettingsField
,
XModuleStudentInfoField
,
XModuleStudentPrefsField
,
StudentModuleCache
from
courseware.model_data
import
LmsKeyValueStore
,
InvalidWriteError
,
InvalidScopeError
,
ModelDataCache
from
courseware.models
import
StudentModule
,
XModuleContentField
,
XModuleSettingsField
,
XModuleStudentInfoField
,
XModuleStudentPrefsField
from
xblock.core
import
Scope
,
BlockScope
from
xmodule.modulestore
import
Location
from
django.test
import
TestCase
def
mock_descriptor
():
def
mock_field
(
scope
,
name
):
field
=
Mock
()
field
.
scope
=
scope
field
.
name
=
name
return
field
def
mock_descriptor
(
fields
=
[],
lms_fields
=
[]):
descriptor
=
Mock
()
descriptor
.
stores_state
=
True
descriptor
.
location
=
location
(
'def_id'
)
descriptor
.
module_class
.
fields
=
fields
descriptor
.
module_class
.
lms
.
fields
=
lms_fields
return
descriptor
location
=
partial
(
Location
,
'i4x'
,
'edX'
,
'test_course'
,
'problem'
)
...
...
@@ -85,7 +93,7 @@ class TestDescriptorFallback(TestCase):
'field_a'
:
'content'
,
'field_b'
:
'settings'
,
}
self
.
kvs
=
LmsKeyValueStore
(
course_id
,
UserFactory
.
build
(),
self
.
desc_md
,
None
)
self
.
kvs
=
LmsKeyValueStore
(
self
.
desc_md
,
None
)
def
test_get_from_descriptor
(
self
):
self
.
assertEquals
(
'content'
,
self
.
kvs
.
get
(
content_key
(
'field_a'
)))
...
...
@@ -103,13 +111,11 @@ class TestDescriptorFallback(TestCase):
self
.
assertEquals
(
'settings'
,
self
.
desc_md
[
'field_b'
])
class
TestStudentStateFields
(
TestCase
):
pass
class
TestInvalidScopes
(
TestCase
):
def
setUp
(
self
):
self
.
desc_md
=
{}
self
.
kvs
=
LmsKeyValueStore
(
course_id
,
UserFactory
.
build
(),
self
.
desc_md
,
None
)
self
.
mdc
=
ModelDataCache
([
mock_descriptor
([
mock_field
(
Scope
.
student_state
,
'a_field'
)])],
course_id
,
self
.
user
)
self
.
kvs
=
LmsKeyValueStore
(
self
.
desc_md
,
self
.
mdc
)
def
test_invalid_scopes
(
self
):
for
scope
in
(
Scope
(
student
=
True
,
block
=
BlockScope
.
DEFINITION
),
...
...
@@ -123,12 +129,10 @@ class TestInvalidScopes(TestCase):
class
TestStudentModuleStorage
(
TestCase
):
def
setUp
(
self
):
student_module
=
StudentModuleFactory
.
create
(
state
=
json
.
dumps
({
'a_field'
:
'a_value'
}))
self
.
user
=
student_module
.
student
self
.
desc_md
=
{}
self
.
smc
=
StudentModuleCache
(
course_id
,
self
.
user
,
[
mock_descriptor
()]
)
self
.
kvs
=
LmsKeyValueStore
(
course_id
,
self
.
user
,
self
.
desc_md
,
self
.
smc
)
self
.
mdc
=
Mock
(
)
self
.
mdc
.
find
.
return_value
.
state
=
json
.
dumps
({
'a_field'
:
'a_value'
}
)
self
.
kvs
=
LmsKeyValueStore
(
self
.
desc_md
,
self
.
mdc
)
def
test_get_existing_field
(
self
):
"Test that getting an existing field in an existing StudentModule works"
...
...
@@ -154,7 +158,7 @@ class TestStudentModuleStorage(TestCase):
"Test that deleting an existing field removes it from the StudentModule"
self
.
kvs
.
delete
(
student_state_key
(
'a_field'
))
self
.
assertEquals
(
1
,
StudentModule
.
objects
.
all
()
.
count
())
self
.
assertEquals
({},
json
.
loads
(
StudentModule
.
objects
.
all
()[
0
]
.
state
)
)
self
.
assertEquals
({},
self
.
mdc
.
find
.
return_value
.
state
)
def
test_delete_missing_field
(
self
):
"Test that deleting a missing field from an existing StudentModule raises a KeyError"
...
...
@@ -167,8 +171,8 @@ class TestMissingStudentModule(TestCase):
def
setUp
(
self
):
self
.
user
=
UserFactory
.
create
()
self
.
desc_md
=
{}
self
.
smc
=
StudentModuleCache
(
course_id
,
self
.
user
,
[
mock_descriptor
()]
)
self
.
kvs
=
LmsKeyValueStore
(
course_id
,
self
.
user
,
self
.
desc_md
,
self
.
sm
c
)
self
.
mdc
=
ModelDataCache
([
mock_descriptor
()],
course_id
,
self
.
user
)
self
.
kvs
=
LmsKeyValueStore
(
self
.
desc_md
,
self
.
md
c
)
def
test_get_field_from_missing_student_module
(
self
):
"Test that getting a field from a missing StudentModule raises a KeyError"
...
...
@@ -176,12 +180,12 @@ class TestMissingStudentModule(TestCase):
def
test_set_field_in_missing_student_module
(
self
):
"Test that setting a field in a missing StudentModule creates the student module"
self
.
assertEquals
(
0
,
len
(
self
.
sm
c
.
cache
))
self
.
assertEquals
(
0
,
len
(
self
.
md
c
.
cache
))
self
.
assertEquals
(
0
,
StudentModule
.
objects
.
all
()
.
count
())
self
.
kvs
.
set
(
student_state_key
(
'a_field'
),
'a_value'
)
self
.
assertEquals
(
1
,
len
(
self
.
sm
c
.
cache
))
self
.
assertEquals
(
1
,
len
(
self
.
md
c
.
cache
))
self
.
assertEquals
(
1
,
StudentModule
.
objects
.
all
()
.
count
())
student_module
=
StudentModule
.
objects
.
all
()[
0
]
...
...
@@ -201,8 +205,8 @@ class TestSettingsStorage(TestCase):
settings
=
SettingsFactory
.
create
()
self
.
user
=
UserFactory
.
create
()
self
.
desc_md
=
{}
self
.
smc
=
StudentModuleCache
(
course_id
,
self
.
user
,
[]
)
self
.
kvs
=
LmsKeyValueStore
(
course_id
,
self
.
user
,
self
.
desc_md
,
self
.
sm
c
)
self
.
mdc
=
ModelDataCache
([
mock_descriptor
()],
course_id
,
self
.
user
)
self
.
kvs
=
LmsKeyValueStore
(
self
.
desc_md
,
self
.
md
c
)
def
test_get_existing_field
(
self
):
"Test that getting an existing field in an existing SettingsField works"
...
...
@@ -242,8 +246,8 @@ class TestContentStorage(TestCase):
content
=
ContentFactory
.
create
()
self
.
user
=
UserFactory
.
create
()
self
.
desc_md
=
{}
self
.
smc
=
StudentModuleCache
(
course_id
,
self
.
user
,
[]
)
self
.
kvs
=
LmsKeyValueStore
(
course_id
,
self
.
user
,
self
.
desc_md
,
self
.
sm
c
)
self
.
mdc
=
ModelDataCache
([
mock_descriptor
()],
course_id
,
self
.
user
)
self
.
kvs
=
LmsKeyValueStore
(
self
.
desc_md
,
self
.
md
c
)
def
test_get_existing_field
(
self
):
"Test that getting an existing field in an existing ContentField works"
...
...
@@ -283,8 +287,11 @@ class TestStudentPrefsStorage(TestCase):
student_pref
=
StudentPrefsFactory
.
create
()
self
.
user
=
student_pref
.
student
self
.
desc_md
=
{}
self
.
smc
=
StudentModuleCache
(
course_id
,
self
.
user
,
[])
self
.
kvs
=
LmsKeyValueStore
(
course_id
,
self
.
user
,
self
.
desc_md
,
self
.
smc
)
self
.
mdc
=
ModelDataCache
([
mock_descriptor
([
mock_field
(
Scope
.
student_preferences
,
'student_pref_field'
),
mock_field
(
Scope
.
student_preferences
,
'not_student_pref_field'
),
])],
course_id
,
self
.
user
)
self
.
kvs
=
LmsKeyValueStore
(
self
.
desc_md
,
self
.
mdc
)
def
test_get_existing_field
(
self
):
"Test that getting an existing field in an existing StudentPrefsField works"
...
...
@@ -309,7 +316,6 @@ class TestStudentPrefsStorage(TestCase):
def
test_delete_existing_field
(
self
):
"Test that deleting an existing field removes it"
print
list
(
XModuleStudentPrefsField
.
objects
.
all
())
self
.
kvs
.
delete
(
student_prefs_key
(
'student_pref_field'
))
self
.
assertEquals
(
0
,
XModuleStudentPrefsField
.
objects
.
all
()
.
count
())
...
...
@@ -325,8 +331,11 @@ class TestStudentInfoStorage(TestCase):
student_info
=
StudentInfoFactory
.
create
()
self
.
user
=
student_info
.
student
self
.
desc_md
=
{}
self
.
smc
=
StudentModuleCache
(
course_id
,
self
.
user
,
[])
self
.
kvs
=
LmsKeyValueStore
(
course_id
,
self
.
user
,
self
.
desc_md
,
self
.
smc
)
self
.
mdc
=
ModelDataCache
([
mock_descriptor
([
mock_field
(
Scope
.
student_info
,
'student_info_field'
),
mock_field
(
Scope
.
student_info
,
'not_student_info_field'
),
])],
course_id
,
self
.
user
)
self
.
kvs
=
LmsKeyValueStore
(
self
.
desc_md
,
self
.
mdc
)
def
test_get_existing_field
(
self
):
"Test that getting an existing field in an existing StudentInfoField works"
...
...
lms/djangoapps/courseware/tests/tests.py
View file @
993c24b7
...
...
@@ -23,7 +23,7 @@ import xmodule.modulestore.django
# Need access to internal func to put users in the right group
from
courseware
import
grades
from
courseware.access
import
_course_staff_group_name
from
courseware.model
s
import
StudentModule
Cache
from
courseware.model
_data
import
ModelData
Cache
from
student.models
import
Registration
from
xmodule.modulestore.django
import
modulestore
...
...
@@ -705,27 +705,27 @@ class TestCourseGrader(PageLoader):
self
.
factory
=
RequestFactory
()
def
get_grade_summary
(
self
):
student_module_cache
=
StudentModule
Cache
.
cache_for_descriptor_descendents
(
model_data_cache
=
ModelData
Cache
.
cache_for_descriptor_descendents
(
self
.
graded_course
.
id
,
self
.
student_user
,
self
.
graded_course
)
fake_request
=
self
.
factory
.
get
(
reverse
(
'progress'
,
kwargs
=
{
'course_id'
:
self
.
graded_course
.
id
}))
return
grades
.
grade
(
self
.
student_user
,
fake_request
,
self
.
graded_course
,
student_module
_cache
)
self
.
graded_course
,
model_data
_cache
)
def
get_homework_scores
(
self
):
return
self
.
get_grade_summary
()[
'totaled_scores'
][
'Homework'
]
def
get_progress_summary
(
self
):
student_module_cache
=
StudentModule
Cache
.
cache_for_descriptor_descendents
(
model_data_cache
=
ModelData
Cache
.
cache_for_descriptor_descendents
(
self
.
graded_course
.
id
,
self
.
student_user
,
self
.
graded_course
)
fake_request
=
self
.
factory
.
get
(
reverse
(
'progress'
,
kwargs
=
{
'course_id'
:
self
.
graded_course
.
id
}))
progress_summary
=
grades
.
progress_summary
(
self
.
student_user
,
fake_request
,
self
.
graded_course
,
student_module
_cache
)
self
.
graded_course
,
model_data
_cache
)
return
progress_summary
def
check_grade_percent
(
self
,
percent
):
...
...
lms/djangoapps/courseware/views.py
View file @
993c24b7
...
...
@@ -23,7 +23,7 @@ from courseware import grades
from
courseware.access
import
has_access
from
courseware.courses
import
(
get_course_with_access
,
get_courses_by_university
)
import
courseware.tabs
as
tabs
from
courseware.model
s
import
StudentModule
Cache
from
courseware.model
_data
import
ModelData
Cache
from
module_render
import
toc_for_course
,
get_module
from
student.models
import
UserProfile
...
...
@@ -81,7 +81,7 @@ def courses(request):
return
render_to_response
(
"courses.html"
,
{
'universities'
:
universities
})
def
render_accordion
(
request
,
course
,
chapter
,
section
):
def
render_accordion
(
request
,
course
,
chapter
,
section
,
model_data_cache
):
''' Draws navigation bar. Takes current position in accordion as
parameter.
...
...
@@ -92,7 +92,7 @@ def render_accordion(request, course, chapter, section):
Returns the html string'''
# grab the table of contents
toc
=
toc_for_course
(
request
.
user
,
request
,
course
,
chapter
,
section
)
toc
=
toc_for_course
(
request
.
user
,
request
,
course
,
chapter
,
section
,
model_data_cache
)
context
=
dict
([(
'toc'
,
toc
),
(
'course_id'
,
course
.
id
),
...
...
@@ -191,24 +191,21 @@ def index(request, course_id, chapter=None, section=None,
return
redirect
(
reverse
(
'about_course'
,
args
=
[
course
.
id
]))
try
:
student_module_cache
=
StudentModule
Cache
.
cache_for_descriptor_descendents
(
model_data_cache
=
ModelData
Cache
.
cache_for_descriptor_descendents
(
course
.
id
,
request
.
user
,
course
,
depth
=
2
)
# Has this student been in this course before?
first_time
=
student_module_cache
.
lookup
(
course_id
,
'course'
,
course
.
location
.
url
())
is
None
course_module
=
get_module
(
request
.
user
,
request
,
course
.
location
,
student_module_cache
,
course
.
id
)
course_module
=
get_module
(
request
.
user
,
request
,
course
.
location
,
model_data_cache
,
course
.
id
)
if
course_module
is
None
:
log
.
warning
(
'If you see this, something went wrong: if we got this'
' far, should have gotten a course module for this user'
)
return
redirect
(
reverse
(
'about_course'
,
args
=
[
course
.
id
]))
if
chapter
is
None
:
return
redirect_to_course_position
(
course_module
,
first_time
)
return
redirect_to_course_position
(
course_module
,
course_module
.
first_time_user
)
context
=
{
'csrf'
:
csrf
(
request
)[
'csrf_token'
],
'accordion'
:
render_accordion
(
request
,
course
,
chapter
,
section
),
'accordion'
:
render_accordion
(
request
,
course
,
chapter
,
section
,
model_data_cache
),
'COURSE_TITLE'
:
course
.
title
,
'course'
:
course
,
'init'
:
''
,
...
...
@@ -224,7 +221,7 @@ def index(request, course_id, chapter=None, section=None,
raise
Http404
chapter_module
=
get_module
(
request
.
user
,
request
,
chapter_descriptor
.
location
,
student_module
_cache
,
course_id
)
model_data
_cache
,
course_id
)
if
chapter_module
is
None
:
# User may be trying to access a chapter that isn't live yet
raise
Http404
...
...
@@ -235,11 +232,11 @@ def index(request, course_id, chapter=None, section=None,
# Specifically asked-for section doesn't exist
raise
Http404
section_
student_module_cache
=
StudentModule
Cache
.
cache_for_descriptor_descendents
(
section_
model_data_cache
=
ModelData
Cache
.
cache_for_descriptor_descendents
(
course_id
,
request
.
user
,
section_descriptor
)
section_module
=
get_module
(
request
.
user
,
request
,
section_descriptor
.
location
,
section_
student_module
_cache
,
course_id
,
position
)
section_
model_data
_cache
,
course_id
,
position
)
if
section_module
is
None
:
# User may be trying to be clever and access something
# they don't have access to.
...
...
@@ -491,12 +488,12 @@ def progress(request, course_id, student_id=None):
# additional DB lookup (this kills the Progress page in particular).
student
=
User
.
objects
.
prefetch_related
(
"groups"
)
.
get
(
id
=
student
.
id
)
student_module_cache
=
StudentModule
Cache
.
cache_for_descriptor_descendents
(
model_data_cache
=
ModelData
Cache
.
cache_for_descriptor_descendents
(
course_id
,
student
,
course
)
courseware_summary
=
grades
.
progress_summary
(
student
,
request
,
course
,
student_module
_cache
)
grade_summary
=
grades
.
grade
(
student
,
request
,
course
,
student_module
_cache
)
model_data
_cache
)
grade_summary
=
grades
.
grade
(
student
,
request
,
course
,
model_data
_cache
)
if
courseware_summary
is
None
:
#This means the student didn't have access to the course (which the instructor requested)
...
...
lms/templates/courseware/info.html
View file @
993c24b7
...
...
@@ -27,20 +27,20 @@ $(document).ready(function(){
% if user.is_authenticated():
<section
class=
"updates"
>
<h1>
Course Updates
&
News
</h1>
${get_course_info_section(request, c
ache, c
ourse, 'updates')}
${get_course_info_section(request, course, 'updates')}
</section>
<section
aria-label=
"Handout Navigation"
class=
"handouts"
>
<h1>
${course.info_sidebar_name}
</h1>
${get_course_info_section(request, c
ache, c
ourse, 'handouts')}
${get_course_info_section(request, course, 'handouts')}
</section>
% else:
<section
class=
"updates"
>
<h1>
Course Updates
&
News
</h1>
${get_course_info_section(request, c
ache, c
ourse, 'guest_updates')}
${get_course_info_section(request, course, 'guest_updates')}
</section>
<section
aria-label=
"Handout Navigation"
class=
"handouts"
>
<h1>
Course Handouts
</h1>
${get_course_info_section(request, c
ache, c
ourse, 'guest_handouts')}
${get_course_info_section(request, course, 'guest_handouts')}
</section>
% endif
</div>
...
...
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