Commit b8d50e51 by Matthew Mongeau

Course navigation work

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