Course navigation work
This commit is contained in:
@@ -67,7 +67,7 @@ def info(request, course_id=None):
|
||||
# We're bypassing the templating system for this part. We should cache
|
||||
# this.
|
||||
sections = ["updates", "handouts", "guest_updates", "guest_handouts"]
|
||||
sections_to_content = {}
|
||||
sections_to_content = { 'course': course }
|
||||
for section in sections:
|
||||
filename = section + ".html"
|
||||
with open(course.path / "info" / filename) as f:
|
||||
|
||||
@@ -137,20 +137,20 @@ def user_groups(user):
|
||||
|
||||
# return [u.name for u in UserTestGroup.objects.raw("select * from auth_user, student_usertestgroup, student_usertestgroup_users where auth_user.id = student_usertestgroup_users.user_id and student_usertestgroup_users.usertestgroup_id = student_usertestgroup.id and auth_user.id = %s", [user.id])]
|
||||
|
||||
def replace_custom_tags(tree):
|
||||
tags = os.listdir(settings.DATA_DIR+'/custom_tags')
|
||||
def replace_custom_tags(course, tree):
|
||||
tags = os.listdir(course.path+'/custom_tags')
|
||||
for tag in tags:
|
||||
for element in tree.iter(tag):
|
||||
element.tag = 'customtag'
|
||||
impl = etree.SubElement(element, 'impl')
|
||||
impl.text = tag
|
||||
|
||||
def course_xml_process(tree):
|
||||
def course_xml_process(course, tree):
|
||||
''' Do basic pre-processing of an XML tree. Assign IDs to all
|
||||
items without. Propagate due dates, grace periods, etc. to child
|
||||
items.
|
||||
'''
|
||||
replace_custom_tags(tree)
|
||||
replace_custom_tags(course, tree)
|
||||
id_tag(tree)
|
||||
propogate_downward_tag(tree, "due")
|
||||
propogate_downward_tag(tree, "graded")
|
||||
@@ -159,18 +159,18 @@ def course_xml_process(tree):
|
||||
propogate_downward_tag(tree, "rerandomize")
|
||||
return tree
|
||||
|
||||
def course_file(user,coursename=None):
|
||||
def course_file(user,course=None):
|
||||
''' Given a user, return course.xml'''
|
||||
|
||||
if user.is_authenticated():
|
||||
filename = UserProfile.objects.get(user=user).courseware # user.profile_cache.courseware
|
||||
filename = os.path.basename(course.path)+"/"+UserProfile.objects.get(user=user).courseware # user.profile_cache.courseware
|
||||
else:
|
||||
filename = 'guest_course.xml'
|
||||
|
||||
# if a specific course is specified, then use multicourse to get the right path to the course XML directory
|
||||
if coursename and settings.ENABLE_MULTICOURSE:
|
||||
xp = multicourse_settings.get_course_xmlpath(coursename)
|
||||
filename = xp + filename # prefix the filename with the path
|
||||
# if coursename and settings.ENABLE_MULTICOURSE:
|
||||
# xp = multicourse_settings.get_course_xmlpath(coursename)
|
||||
# filename = xp + filename # prefix the filename with the path
|
||||
|
||||
groups = user_groups(user)
|
||||
options = {'dev_content':settings.DEV_CONTENT,
|
||||
@@ -188,7 +188,7 @@ def course_file(user,coursename=None):
|
||||
# print '[courseware.content_parser.course_file] tree_string = ',tree_string
|
||||
|
||||
if not tree_string:
|
||||
tree = course_xml_process(etree.XML(render_to_string(filename, options, namespace = 'course')))
|
||||
tree = course_xml_process(course, etree.XML(render_to_string(filename, options, namespace = 'course')))
|
||||
tree_string = etree.tostring(tree)
|
||||
|
||||
cache.set(cache_key, tree_string, 60)
|
||||
@@ -197,7 +197,7 @@ def course_file(user,coursename=None):
|
||||
|
||||
return tree
|
||||
|
||||
def section_file(user, section, coursename=None, dironly=False):
|
||||
def section_file(user, section, course=None, dironly=False):
|
||||
'''
|
||||
Given a user and the name of a section, return that section.
|
||||
This is done specific to each course.
|
||||
@@ -221,7 +221,7 @@ def section_file(user, section, coursename=None, dironly=False):
|
||||
options = {'dev_content':settings.DEV_CONTENT,
|
||||
'groups' : user_groups(user)}
|
||||
|
||||
tree = course_xml_process(etree.XML(render_to_string(filename, options, namespace = 'sections')))
|
||||
tree = course_xml_process(course, etree.XML(render_to_string(filename, options, namespace = 'sections')))
|
||||
return tree
|
||||
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ course_settings = Settings()
|
||||
|
||||
|
||||
|
||||
def grade_sheet(student,coursename=None):
|
||||
def grade_sheet(student,course=None):
|
||||
"""
|
||||
This pulls a summary of all problems in the course. It returns a dictionary with two datastructures:
|
||||
|
||||
@@ -77,9 +77,9 @@ def grade_sheet(student,coursename=None):
|
||||
|
||||
- grade_summary is the output from the course grader. More information on the format is in the docstring for CourseGrader.
|
||||
"""
|
||||
dom=content_parser.course_file(student,coursename)
|
||||
course = dom.xpath('//course/@name')[0]
|
||||
xmlChapters = dom.xpath('//course[@name=$course]/chapter', course=course)
|
||||
dom=content_parser.course_file(student,course)
|
||||
dom_course = dom.xpath('//course/@name')[0]
|
||||
xmlChapters = dom.xpath('//course[@name=$course]/chapter', course=dom_course)
|
||||
|
||||
responses=StudentModule.objects.filter(student=student)
|
||||
response_by_id = {}
|
||||
@@ -95,15 +95,15 @@ def grade_sheet(student,coursename=None):
|
||||
|
||||
|
||||
for s in dom.xpath('//course[@name=$course]/chapter[@name=$chname]/section',
|
||||
course=course, chname=chname):
|
||||
course=dom_course, chname=chname):
|
||||
problems=dom.xpath('//course[@name=$course]/chapter[@name=$chname]/section[@name=$section]//problem',
|
||||
course=course, chname=chname, section=s.get('name'))
|
||||
course=dom_course, chname=chname, section=s.get('name'))
|
||||
|
||||
graded = True if s.get('graded') == "true" else False
|
||||
scores=[]
|
||||
if len(problems)>0:
|
||||
for p in problems:
|
||||
(correct,total) = get_score(student, p, response_by_id, coursename=coursename)
|
||||
(correct,total) = get_score(student, p, response_by_id, course=course)
|
||||
|
||||
if settings.GENERATE_PROFILE_SCORES:
|
||||
if total > 1:
|
||||
@@ -146,7 +146,7 @@ def grade_sheet(student,coursename=None):
|
||||
return {'courseware_summary' : chapters,
|
||||
'grade_summary' : grade_summary}
|
||||
|
||||
def get_score(user, problem, cache, coursename=None):
|
||||
def get_score(user, problem, cache, course=None):
|
||||
## HACK: assumes max score is fixed per problem
|
||||
id = problem.get('id')
|
||||
correct = 0.0
|
||||
@@ -177,7 +177,7 @@ def get_score(user, problem, cache, coursename=None):
|
||||
# TODO: These are no longer correct params for I4xSystem -- figure out what this code
|
||||
# does, clean it up.
|
||||
from module_render import I4xSystem
|
||||
system = I4xSystem(None, None, None, coursename=coursename)
|
||||
system = I4xSystem(None, None, None, course=course)
|
||||
total=float(xmodule.capa_module.Module(system, etree.tostring(problem), "id").max_score())
|
||||
response.max_grade = total
|
||||
response.save()
|
||||
|
||||
@@ -35,7 +35,7 @@ class I4xSystem(object):
|
||||
'''
|
||||
def __init__(self, ajax_url, track_function, render_function,
|
||||
module_from_xml, render_template, request=None,
|
||||
filestore=None):
|
||||
filestore=None, course=None):
|
||||
'''
|
||||
Create a closure around the system environment.
|
||||
|
||||
@@ -56,6 +56,7 @@ class I4xSystem(object):
|
||||
filestore - A filestore ojbect. Defaults to an instance of OSFS based at
|
||||
settings.DATA_DIR.
|
||||
'''
|
||||
self.course = course
|
||||
self.ajax_url = ajax_url
|
||||
self.track_function = track_function
|
||||
if not filestore:
|
||||
@@ -169,14 +170,14 @@ def get_module(user, request, module_xml, student_module_cache, position=None):
|
||||
state = smod.state if smod else None
|
||||
|
||||
# get coursename if present in request
|
||||
coursename = multicourse_settings.get_coursename_from_request(request)
|
||||
# coursename = multicourse_settings.get_coursename_from_request(request)
|
||||
|
||||
if coursename and settings.ENABLE_MULTICOURSE:
|
||||
# path to XML for the course
|
||||
xp = multicourse_settings.get_course_xmlpath(coursename)
|
||||
data_root = settings.DATA_DIR + xp
|
||||
else:
|
||||
data_root = settings.DATA_DIR
|
||||
# if coursename and settings.ENABLE_MULTICOURSE:
|
||||
# # path to XML for the course
|
||||
# xp = multicourse_settings.get_course_xmlpath(coursename)
|
||||
# data_root = settings.DATA_DIR + xp
|
||||
# else:
|
||||
data_root = settings.DATA_DIR+"/"+os.path.basename(course.path)
|
||||
|
||||
# Setup system context for module instance
|
||||
ajax_url = settings.MITX_ROOT_URL + '/modx/' + module_type + '/' + module_id + '/'
|
||||
|
||||
@@ -46,24 +46,24 @@ def gradebook(request):
|
||||
if 'course_admin' not in content_parser.user_groups(request.user):
|
||||
raise Http404
|
||||
|
||||
coursename = multicourse_settings.get_coursename_from_request(request)
|
||||
course = settings.COURSES_BY_ID[course_id]
|
||||
|
||||
student_objects = User.objects.all()[:100]
|
||||
student_info = [{'username': s.username,
|
||||
'id': s.id,
|
||||
'email': s.email,
|
||||
'grade_info': grades.grade_sheet(s, coursename),
|
||||
'grade_info': grades.grade_sheet(s, course),
|
||||
'realname': UserProfile.objects.get(user = s).name
|
||||
} for s in student_objects]
|
||||
|
||||
return render_to_response('gradebook.html', {'students': student_info})
|
||||
return render_to_response('gradebook.html', {'students': student_info, 'course': course})
|
||||
|
||||
@login_required
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
def profile(request, student_id=None):
|
||||
def profile(request, course_id=None, student_id=None):
|
||||
''' User profile. Show username, location, etc, as well as grades .
|
||||
We need to allow the user to change some of these settings .'''
|
||||
|
||||
course = settings.COURSES_BY_ID[course_id]
|
||||
if student_id is None:
|
||||
student = request.user
|
||||
else:
|
||||
@@ -73,17 +73,18 @@ def profile(request, student_id=None):
|
||||
|
||||
user_info = UserProfile.objects.get(user=student) # request.user.profile_cache #
|
||||
|
||||
coursename = multicourse_settings.get_coursename_from_request(request)
|
||||
# coursename = multicourse_settings.get_coursename_from_request(request)
|
||||
|
||||
context = {'name': user_info.name,
|
||||
'username': student.username,
|
||||
'location': user_info.location,
|
||||
'language': user_info.language,
|
||||
'email': student.email,
|
||||
'course': course,
|
||||
'format_url_params': content_parser.format_url_params,
|
||||
'csrf': csrf(request)['csrf_token']
|
||||
}
|
||||
context.update(grades.grade_sheet(student, coursename))
|
||||
context.update(grades.grade_sheet(student, course))
|
||||
|
||||
return render_to_response('profile.html', context)
|
||||
|
||||
@@ -95,8 +96,8 @@ def render_accordion(request, course, chapter, section):
|
||||
If chapter and section are '' or None, renders a default accordion.
|
||||
|
||||
Returns (initialization_javascript, content)'''
|
||||
if not course:
|
||||
course = "6.002 Spring 2012"
|
||||
# if not course:
|
||||
# course = "6.002 Spring 2012"
|
||||
|
||||
toc = content_parser.toc_from_xml(
|
||||
content_parser.course_file(request.user, course), chapter, section)
|
||||
@@ -106,9 +107,11 @@ def render_accordion(request, course, chapter, section):
|
||||
if toc[i]['active']:
|
||||
active_chapter = i
|
||||
|
||||
log.info(course.title)
|
||||
context=dict([('active_chapter', active_chapter),
|
||||
('toc', toc),
|
||||
('course_name', course),
|
||||
('course_name', course.title),
|
||||
('course_id', course.id),
|
||||
('format_url_params', content_parser.format_url_params),
|
||||
('csrf', csrf(request)['csrf_token'])] +
|
||||
template_imports.items())
|
||||
@@ -133,7 +136,7 @@ def render_section(request, section):
|
||||
|
||||
context = {
|
||||
'csrf': csrf(request)['csrf_token'],
|
||||
'accordion': render_accordion(request, '', '', '')
|
||||
'accordion': render_accordion(request, course, '', '')
|
||||
}
|
||||
|
||||
module_ids = dom.xpath("//@id")
|
||||
@@ -288,12 +291,16 @@ def index(request, course=None, chapter=None, section=None,
|
||||
if not settings.COURSEWARE_ENABLED:
|
||||
return redirect('/')
|
||||
|
||||
course = clean(get_course(request, course))
|
||||
if not multicourse_settings.is_valid_course(course):
|
||||
return redirect('/')
|
||||
# course = clean(get_course(request, course))
|
||||
# if not multicourse_settings.is_valid_course(course):
|
||||
# return redirect('/')
|
||||
try:
|
||||
course = settings.COURSES_BY_ID[course_id]
|
||||
except KeyError:
|
||||
raise Http404("Course not found")
|
||||
|
||||
# keep track of current course being viewed in django's request.session
|
||||
request.session['coursename'] = course
|
||||
request.session['coursename'] = course.title
|
||||
|
||||
chapter = clean(chapter)
|
||||
section = clean(section)
|
||||
@@ -301,7 +308,8 @@ def index(request, course=None, chapter=None, section=None,
|
||||
context = {
|
||||
'csrf': csrf(request)['csrf_token'],
|
||||
'accordion': render_accordion(request, course, chapter, section),
|
||||
'COURSE_TITLE': multicourse_settings.get_course_title(course),
|
||||
'COURSE_TITLE': course.title,
|
||||
'course': course,
|
||||
'init': '',
|
||||
'content': ''
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from mitxmako.shortcuts import render_to_response
|
||||
from django.conf import settings
|
||||
|
||||
@login_required
|
||||
def index(request, page=0):
|
||||
return render_to_response('staticbook.html',{'page':int(page)})
|
||||
def index(request, course_id=None, page=0):
|
||||
course = settings.COURSES_BY_ID[course_id]
|
||||
return render_to_response('staticbook.html',{'page':int(page), 'course': course})
|
||||
|
||||
def index_shifted(request, page):
|
||||
return index(request, int(page)+24)
|
||||
|
||||
@@ -6,19 +6,22 @@ def url_class(url):
|
||||
return "active"
|
||||
return ""
|
||||
%>
|
||||
<%!
|
||||
from django.core.urlresolvers import reverse
|
||||
%>
|
||||
|
||||
<nav class="${active_page} course-material">
|
||||
<div class="inner-wrapper">
|
||||
<ol class="course-tabs">
|
||||
<li class="courseware"><a href="${ MITX_ROOT_URL }/courseware/" class="${url_class('courseware')}">Courseware</a></li>
|
||||
<li class="info"><a href="${ MITX_ROOT_URL }/info" class="${url_class('info')}">Course Info</a></li>
|
||||
<li class="courseware"><a href="${reverse('courseware', args=[course.id])}" class="${url_class('courseware')}">Courseware</a></li>
|
||||
<li class="info"><a href="${reverse('info', args=[course.id])}" class="${url_class('info')}">Course Info</a></li>
|
||||
% if user.is_authenticated():
|
||||
<li class="book"><a href="${ MITX_ROOT_URL }/book" class="${url_class('book')}">Textbook</a></li>
|
||||
<li class="book"><a href="${reverse('book', args=[course.id])}" class="${url_class('book')}">Textbook</a></li>
|
||||
<li class="discussion"><a href="${ MITX_ROOT_URL }/discussion/questions/">Discussion</a></li>
|
||||
% endif
|
||||
<li class="wiki"><a href="${ MITX_ROOT_URL }/wiki/view/" class="${url_class('wiki')}">Wiki</a></li>
|
||||
<li class="wiki"><a href="${reverse('wiki_root')}" class="${url_class('wiki')}">Wiki</a></li>
|
||||
% if user.is_authenticated():
|
||||
<li class="profile"><a href="${ MITX_ROOT_URL }/profile" class="${url_class('profile')}">Profile</a></li>
|
||||
<li class="profile"><a href="${reverse('profile', args=[course.id])}" class="${url_class('profile')}">Profile</a></li>
|
||||
% endif
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
13
lms/urls.py
13
lms/urls.py
@@ -49,18 +49,15 @@ if settings.PERFSTATS:
|
||||
|
||||
if settings.COURSEWARE_ENABLED:
|
||||
urlpatterns += (
|
||||
url(r'^courseware/$', 'courseware.views.index', name="courseware"),
|
||||
url(r'^wiki/', include('simplewiki.urls')),
|
||||
url(r'^masquerade/', include('masquerade.urls')),
|
||||
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/(?P<section>[^/]*)/(?P<position>[^/]*)$', 'courseware.views.index'),
|
||||
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/(?P<section>[^/]*)/$', 'courseware.views.index', name="courseware_section"),
|
||||
# url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/(?P<section>[^/]*)/$', 'courseware.views.index', name="courseware_section"),
|
||||
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/$', 'courseware.views.index', name="courseware_chapter"),
|
||||
url(r'^courseware/(?P<course>[^/]*)/$', 'courseware.views.index', name="courseware_course"),
|
||||
url(r'^jumpto/(?P<probname>[^/]+)/$', 'courseware.views.jump_to'),
|
||||
url(r'^section/(?P<section>[^/]*)/$', 'courseware.views.render_section'),
|
||||
url(r'^modx/(?P<module>[^/]*)/(?P<id>[^/]*)/(?P<dispatch>[^/]*)$', 'courseware.module_render.modx_dispatch'), #reset_problem'),
|
||||
url(r'^profile$', 'courseware.views.profile'),
|
||||
url(r'^profile/(?P<student_id>[^/]*)/$', 'courseware.views.profile'),
|
||||
url(r'^change_setting$', 'student.views.change_setting'),
|
||||
url(r'^s/(?P<template>[^/]*)$', 'static_template_view.views.auth_index'),
|
||||
url(r'^book/(?P<page>[^/]*)$', 'staticbook.views.index'),
|
||||
@@ -75,8 +72,12 @@ if settings.COURSEWARE_ENABLED:
|
||||
|
||||
# Multicourse related:
|
||||
url(r'^courses$', 'courseware.views.courses'),
|
||||
url(r'^courses/(?P<course_id>[^/]*)/info$', 'util.views.info'),
|
||||
url(r'^courses/(?P<course_id>[^/]*)/courseware$', 'courseware.views.index'),
|
||||
url(r'^courses/(?P<course_id>[^/]*)/info$', 'util.views.info', name="info"),
|
||||
url(r'^courses/(?P<course_id>[^/]*)/book$', 'staticbook.views.index', name="book"),
|
||||
url(r'^courses/(?P<course_id>[^/]*)/courseware/?$', 'courseware.views.index', name="courseware"),
|
||||
url(r'^courses/(?P<course_id>[^/]*)/courseware/(?P<chapter>[^/]*)/(?P<section>[^/]*)/$', 'courseware.views.index', name="courseware_section"),
|
||||
url(r'^courses/(?P<course_id>[^/]*)/profile$', 'courseware.views.profile', name="profile"),
|
||||
url(r'^courses/(?P<course_id>[^/]*)/profile/(?P<student_id>[^/]*)/$', 'courseware.views.profile'),
|
||||
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user