From b8d50e51eeef3242e3df1ec76a2fd81e3715f19a Mon Sep 17 00:00:00 2001 From: Matthew Mongeau Date: Tue, 26 Jun 2012 17:23:16 -0400 Subject: [PATCH] Course navigation work --- common/djangoapps/util/views.py | 2 +- lms/djangoapps/courseware/content_parser.py | 24 ++++++------- lms/djangoapps/courseware/grades.py | 18 +++++----- lms/djangoapps/courseware/module_render.py | 17 ++++----- lms/djangoapps/courseware/views.py | 40 ++++++++++++--------- lms/djangoapps/staticbook/views.py | 6 ++-- lms/templates/course_navigation.html | 13 ++++--- lms/urls.py | 13 +++---- 8 files changed, 74 insertions(+), 59 deletions(-) diff --git a/common/djangoapps/util/views.py b/common/djangoapps/util/views.py index 132f6dfe5a..c60149563d 100644 --- a/common/djangoapps/util/views.py +++ b/common/djangoapps/util/views.py @@ -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: diff --git a/lms/djangoapps/courseware/content_parser.py b/lms/djangoapps/courseware/content_parser.py index 4f96db5284..eac163a5ce 100644 --- a/lms/djangoapps/courseware/content_parser.py +++ b/lms/djangoapps/courseware/content_parser.py @@ -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 diff --git a/lms/djangoapps/courseware/grades.py b/lms/djangoapps/courseware/grades.py index 4a11ec2d51..bfff53453b 100644 --- a/lms/djangoapps/courseware/grades.py +++ b/lms/djangoapps/courseware/grades.py @@ -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() diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 3a6fcbfb45..cf08dd21bd 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -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 + '/' diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py index 40f0eecaf1..b35c4ea5cb 100644 --- a/lms/djangoapps/courseware/views.py +++ b/lms/djangoapps/courseware/views.py @@ -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': '' } diff --git a/lms/djangoapps/staticbook/views.py b/lms/djangoapps/staticbook/views.py index 84fcc79c1f..ebd09059a5 100644 --- a/lms/djangoapps/staticbook/views.py +++ b/lms/djangoapps/staticbook/views.py @@ -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) diff --git a/lms/templates/course_navigation.html b/lms/templates/course_navigation.html index a214e498f0..4e8be9a801 100644 --- a/lms/templates/course_navigation.html +++ b/lms/templates/course_navigation.html @@ -6,19 +6,22 @@ def url_class(url): return "active" return "" %> +<%! + from django.core.urlresolvers import reverse +%>