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
2a9eba38
Commit
2a9eba38
authored
Jun 29, 2012
by
Calen Pennington
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Removing content_parser
parent
c7f95695
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
33 additions
and
214 deletions
+33
-214
lms/djangoapps/courseware/content_parser.py
+0
-205
lms/djangoapps/courseware/views.py
+33
-9
No files found.
lms/djangoapps/courseware/content_parser.py
deleted
100644 → 0
View file @
c7f95695
'''
courseware/content_parser.py
This file interfaces between all courseware modules and the top-level course.xml file for a course.
Does some caching (to be explained).
'''
import
logging
import
os
import
sys
import
urllib
from
lxml
import
etree
from
util.memcache
import
fasthash
from
django.conf
import
settings
from
student.models
import
UserProfile
from
student.models
import
UserTestGroup
from
mitxmako.shortcuts
import
render_to_string
from
util.cache
import
cache
from
multicourse
import
multicourse_settings
import
xmodule
''' This file will eventually form an abstraction layer between the
course XML file and the rest of the system.
'''
# ==== This section has no direct dependencies on django ====================================
# NOTE: it does still have some indirect dependencies:
# util.memcache.fasthash (which does not depend on memcache at all)
#
log
=
logging
.
getLogger
(
"mitx.courseware"
)
def
format_url_params
(
params
):
return
[
urllib
.
quote
(
string
.
replace
(
' '
,
'_'
))
for
string
in
params
]
def
id_tag
(
course
):
''' Tag all course elements with unique IDs '''
default_ids
=
xmodule
.
get_default_ids
()
# Tag elements with unique IDs
elements
=
course
.
xpath
(
"|"
.
join
(
'//'
+
c
for
c
in
default_ids
))
for
elem
in
elements
:
if
elem
.
get
(
'id'
):
pass
elif
elem
.
get
(
default_ids
[
elem
.
tag
]):
new_id
=
elem
.
get
(
default_ids
[
elem
.
tag
])
# Convert to alphanumeric
new_id
=
""
.
join
(
a
for
a
in
new_id
if
a
.
isalnum
())
# Without this, a conflict may occur between an html or youtube id
new_id
=
default_ids
[
elem
.
tag
]
+
new_id
elem
.
set
(
'id'
,
new_id
)
else
:
elem
.
set
(
'id'
,
"id"
+
fasthash
(
etree
.
tostring
(
elem
)))
def
propogate_downward_tag
(
element
,
attribute_name
,
parent_attribute
=
None
):
''' This call is to pass down an attribute to all children. If an element
has this attribute, it will be "inherited" by all of its children. If a
child (A) already has that attribute, A will keep the same attribute and
all of A's children will inherit A's attribute. This is a recursive call.'''
if
(
parent_attribute
is
None
):
#This is the entry call. Select all elements with this attribute
all_attributed_elements
=
element
.
xpath
(
"//*[@"
+
attribute_name
+
"]"
)
for
attributed_element
in
all_attributed_elements
:
attribute_value
=
attributed_element
.
get
(
attribute_name
)
for
child_element
in
attributed_element
:
propogate_downward_tag
(
child_element
,
attribute_name
,
attribute_value
)
else
:
'''The hack below is because we would get _ContentOnlyELements from the
iterator that can't have attributes set. We can't find API for it. If we
ever have an element which subclasses BaseElement, we will not tag it'''
if
not
element
.
get
(
attribute_name
)
and
type
(
element
)
==
etree
.
_Element
:
element
.
set
(
attribute_name
,
parent_attribute
)
for
child_element
in
element
:
propogate_downward_tag
(
child_element
,
attribute_name
,
parent_attribute
)
else
:
#This element would have already been found by Xpath, so we return
#for now and trust that this element will get its turn to propogate
#to its children later.
return
def
course_xml_process
(
tree
):
''' Do basic pre-processing of an XML tree. Assign IDs to all
items without. Propagate due dates, grace periods, etc. to child
items.
'''
process_includes
(
tree
)
replace_custom_tags
(
tree
)
id_tag
(
tree
)
propogate_downward_tag
(
tree
,
"due"
)
propogate_downward_tag
(
tree
,
"graded"
)
propogate_downward_tag
(
tree
,
"graceperiod"
)
propogate_downward_tag
(
tree
,
"showanswer"
)
propogate_downward_tag
(
tree
,
"rerandomize"
)
return
tree
def
process_includes_dir
(
tree
,
dir
):
"""
Process tree to replace all <include file=""> tags
with the contents of the file specified, relative to dir
"""
includes
=
tree
.
findall
(
'.//include'
)
for
inc
in
includes
:
file
=
inc
.
get
(
'file'
)
if
file
is
not
None
:
try
:
ifp
=
open
(
os
.
path
.
join
(
dir
,
file
))
except
Exception
:
log
.
exception
(
'Error in problem xml include:
%
s'
%
(
etree
.
tostring
(
inc
,
pretty_print
=
True
)))
log
.
exception
(
'Cannot find file
%
s in
%
s'
%
(
file
,
dir
))
raise
try
:
# read in and convert to XML
incxml
=
etree
.
XML
(
ifp
.
read
())
except
Exception
:
log
.
exception
(
'Error in problem xml include:
%
s'
%
(
etree
.
tostring
(
inc
,
pretty_print
=
True
)))
log
.
exception
(
'Cannot parse XML in
%
s'
%
(
file
))
raise
# insert new XML into tree in place of inlcude
parent
=
inc
.
getparent
()
parent
.
insert
(
parent
.
index
(
inc
),
incxml
)
parent
.
remove
(
inc
)
def
replace_custom_tags_dir
(
tree
,
dir
):
'''
Process tree to replace all custom tags defined in dir.
'''
tags
=
os
.
listdir
(
dir
)
for
tag
in
tags
:
for
element
in
tree
.
iter
(
tag
):
element
.
tag
=
'customtag'
impl
=
etree
.
SubElement
(
element
,
'impl'
)
impl
.
text
=
tag
def
parse_course_file
(
filename
,
options
,
namespace
):
'''
Parse a course file with the given options, and return the resulting
xml tree object.
Options should be a dictionary including keys
'dev_content': bool,
'groups' : [list, of, user, groups]
namespace is used to in searching for the file. Could be e.g. 'course',
'sections'.
'''
xml
=
etree
.
XML
(
render_to_string
(
filename
,
options
,
namespace
=
namespace
))
return
course_xml_process
(
xml
)
# ==== All Django-specific code below =============================================
def
user_groups
(
user
):
if
not
user
.
is_authenticated
():
return
[]
# TODO: Rewrite in Django
key
=
'user_group_names_{user.id}'
.
format
(
user
=
user
)
cache_expiration
=
60
*
60
# one hour
# Kill caching on dev machines -- we switch groups a lot
group_names
=
cache
.
get
(
key
)
if
group_names
is
None
:
group_names
=
[
u
.
name
for
u
in
UserTestGroup
.
objects
.
filter
(
users
=
user
)]
cache
.
set
(
key
,
group_names
,
cache_expiration
)
return
group_names
def
get_options
(
user
):
return
{
'dev_content'
:
settings
.
DEV_CONTENT
,
'groups'
:
user_groups
(
user
)}
def
process_includes
(
tree
):
'''Replace <include> tags with the contents from the course directory'''
process_includes_dir
(
tree
,
settings
.
DATA_DIR
)
def
replace_custom_tags
(
tree
):
'''Replace custom tags defined in our custom_tags dir'''
replace_custom_tags_dir
(
tree
,
settings
.
DATA_DIR
+
'/custom_tags'
)
def
sections_dir
(
coursename
=
None
):
''' Get directory where sections information is stored.
'''
# if a specific course is specified, then use multicourse to get the
# right path to the course XML directory
xp
=
''
if
coursename
and
settings
.
ENABLE_MULTICOURSE
:
xp
=
multicourse_settings
.
get_course_xmlpath
(
coursename
)
return
settings
.
DATA_DIR
+
xp
+
'/sections/'
lms/djangoapps/courseware/views.py
View file @
2a9eba38
import
logging
import
urllib
from
fs.osfs
import
OSFS
from
django.conf
import
settings
from
django.core.context_processors
import
csrf
from
django.contrib.auth.models
import
User
...
...
@@ -22,7 +20,9 @@ from student.models import UserProfile
from
multicourse
import
multicourse_settings
from
keystore.django
import
keystore
from
courseware
import
grades
,
content_parser
from
util.cache
import
cache
from
student.models
import
UserTestGroup
from
courseware
import
grades
log
=
logging
.
getLogger
(
"mitx.courseware"
)
...
...
@@ -31,9 +31,32 @@ etree.set_default_parser(etree.XMLParser(dtd_validation=False, load_dtd=False,
template_imports
=
{
'urllib'
:
urllib
}
def
user_groups
(
user
):
if
not
user
.
is_authenticated
():
return
[]
# TODO: Rewrite in Django
key
=
'user_group_names_{user.id}'
.
format
(
user
=
user
)
cache_expiration
=
60
*
60
# one hour
# Kill caching on dev machines -- we switch groups a lot
group_names
=
cache
.
get
(
key
)
if
group_names
is
None
:
group_names
=
[
u
.
name
for
u
in
UserTestGroup
.
objects
.
filter
(
users
=
user
)]
cache
.
set
(
key
,
group_names
,
cache_expiration
)
return
group_names
def
format_url_params
(
params
):
return
[
urllib
.
quote
(
string
.
replace
(
' '
,
'_'
))
for
string
in
params
]
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
def
gradebook
(
request
):
if
'course_admin'
not
in
content_parser
.
user_groups
(
request
.
user
):
if
'course_admin'
not
in
user_groups
(
request
.
user
):
raise
Http404
coursename
=
multicourse_settings
.
get_coursename_from_request
(
request
)
...
...
@@ -52,7 +75,7 @@ def gradebook(request):
'id'
:
student
.
id
,
'email'
:
student
.
email
,
'grade_info'
:
grades
.
grade_sheet
(
student
,
course
,
student_module_cache
),
'realname'
:
UserProfile
.
objects
.
get
(
user
=
student
)
.
name
'realname'
:
UserProfile
.
objects
.
get
(
user
=
student
)
.
name
})
return
render_to_response
(
'gradebook.html'
,
{
'students'
:
student_info
})
...
...
@@ -67,7 +90,7 @@ def profile(request, student_id=None):
if
student_id
is
None
:
student
=
request
.
user
else
:
if
'course_admin'
not
in
content_parser
.
user_groups
(
request
.
user
):
if
'course_admin'
not
in
user_groups
(
request
.
user
):
raise
Http404
student
=
User
.
objects
.
get
(
id
=
int
(
student_id
))
...
...
@@ -83,7 +106,7 @@ def profile(request, student_id=None):
'location'
:
user_info
.
location
,
'language'
:
user_info
.
language
,
'email'
:
student
.
email
,
'format_url_params'
:
content_parser
.
format_url_params
,
'format_url_params'
:
format_url_params
,
'csrf'
:
csrf
(
request
)[
'csrf_token'
]
}
context
.
update
(
grades
.
grade_sheet
(
student
,
course
,
student_module_cache
))
...
...
@@ -110,7 +133,7 @@ def render_accordion(request, course, chapter, section):
context
=
dict
([(
'active_chapter'
,
active_chapter
),
(
'toc'
,
toc
),
(
'course_name'
,
course
),
(
'format_url_params'
,
content_parser
.
format_url_params
),
(
'format_url_params'
,
format_url_params
),
(
'csrf'
,
csrf
(
request
)[
'csrf_token'
])]
+
template_imports
.
items
())
return
render_to_string
(
'accordion.html'
,
context
)
...
...
@@ -215,7 +238,8 @@ def jump_to(request, probname=None):
# look for problem of given name
pxml
=
xml
.
xpath
(
'//problem[@filename="
%
s"]'
%
probname
)
if
pxml
:
pxml
=
pxml
[
0
]
if
pxml
:
pxml
=
pxml
[
0
]
# get the parent element
parent
=
pxml
.
getparent
()
...
...
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