Commit 9b3d7efb by Brian Wilson

add first pass at testcenter exam

parent 676e80bd
......@@ -2,6 +2,7 @@ import logging
import urllib
from functools import partial
from time import time
from django.conf import settings
from django.core.context_processors import csrf
......@@ -297,6 +298,140 @@ def index(request, course_id, chapter=None, section=None,
return result
@login_required
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
def testcenter_exam(request, course_id, chapter, section):
"""
Displays only associated content. If course, chapter,
and section are all specified, renders the page, or returns an error if they
are invalid.
Returns an error if these are not all specified and correct.
Arguments:
- request : HTTP request
- course_id : course id (str: ORG/course/URL_NAME)
- chapter : chapter url_name (str)
- section : section url_name (str)
Returns:
- HTTPresponse
"""
course = get_course_with_access(request.user, course_id, 'load', depth=2)
staff_access = has_access(request.user, course, 'staff')
registered = registered_for_course(course, request.user)
if not registered:
log.debug('User %s tried to view course %s but is not enrolled' % (request.user,course.location.url()))
raise # error
try:
student_module_cache = StudentModuleCache.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
# Load the module for the course
course_module = get_module_for_descriptor(request.user, request, course, student_module_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]))
raise # error
if chapter is None:
# return redirect_to_course_position(course_module, first_time)
raise # error
# BW: add this test earlier, and remove later clause
if section is None:
# return redirect_to_course_position(course_module, first_time)
raise # error
context = {
'csrf': csrf(request)['csrf_token'],
# 'accordion': render_accordion(request, course, chapter, section),
'COURSE_TITLE': course.title,
'course': course,
'init': '',
'content': '',
'staff_access': staff_access,
'xqa_server': settings.MITX_FEATURES.get('USE_XQA_SERVER','http://xqa:server@content-qa.mitx.mit.edu/xqa')
}
chapter_descriptor = course.get_child_by(lambda m: m.url_name == chapter)
if chapter_descriptor is not None:
instance_module = get_instance_module(course_id, request.user, course_module, student_module_cache)
save_child_position(course_module, chapter, instance_module)
else:
raise Http404
chapter_module = course_module.get_child_by(lambda m: m.url_name == chapter)
if chapter_module is None:
# User may be trying to access a chapter that isn't live yet
raise Http404
section_descriptor = chapter_descriptor.get_child_by(lambda m: m.url_name == section)
if section_descriptor is None:
# Specifically asked-for section doesn't exist
raise Http404
# Load all descendents of the section, because we're going to display its
# html, which in general will need all of its children
section_module = get_module(request.user, request, section_descriptor.location,
student_module_cache, course.id, position=None, depth=None)
if section_module is None:
# User may be trying to be clever and access something
# they don't have access to.
raise Http404
# Save where we are in the chapter
# instance_module = get_instance_module(course_id, request.user, chapter_module, student_module_cache)
# save_child_position(chapter_module, section, instance_module)
context['content'] = section_module.get_html()
# figure out when the exam should end. Going forward, this is determined by getting a "normal"
# duration from the test, then doing some math to modify the duration based on accommodations,
# and then use that value as the end. Once we have calculated this, it should be sticky -- we
# use the same value for future requests, unless it's a tester.
# Let's try 600s for now...
context['end_date'] = (time() + 600) * 1000
result = render_to_response('courseware/testcenter_exam.html', context)
except Exception as e:
if isinstance(e, Http404):
# let it propagate
raise
# In production, don't want to let a 500 out for any reason
if settings.DEBUG:
raise
else:
log.exception("Error in exam view: user={user}, course={course},"
" chapter={chapter} section={section}"
"position={position}".format(
user=request.user,
course=course,
chapter=chapter,
section=section
))
try:
result = render_to_response('courseware/courseware-error.html',
{'staff_access': staff_access,
'course' : course})
except:
# Let the exception propagate, relying on global config to at
# at least return a nice error message
log.exception("Error while rendering courseware-error page")
raise
return result
@ensure_csrf_cookie
def jump_to(request, course_id, location):
'''
......
<%inherit file="/main_nonav.html" />
<%namespace name='static' file='/static_content.html'/>
<%block name="bodyclass">courseware ${course.css_class}</%block>
<%block name="title"><title>${course.number} Exam</title></%block>
<%block name="headextra">
<%static:css group='course'/>
<%include file="../discussion/_js_head_dependencies.html" />
</%block>
<%block name="js_extra">
<script type="text/javascript" src="${static.url('js/vendor/jquery.scrollTo-1.4.2-min.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script>
## codemirror
<script type="text/javascript" src="${static.url('js/vendor/codemirror-compressed.js')}"></script>
## alternate codemirror
## <script type="text/javascript" src="${static.url('js/vendor/CodeMirror-2.25/lib/codemirror.js')}"></script>
## <script type="text/javascript" src="${static.url('js/vendor/CodeMirror-2.25/mode/xml/xml.js')}"></script>
## <script type="text/javascript" src="${static.url('js/vendor/CodeMirror-2.25/mode/python/python.js')}"></script>
<%static:js group='courseware'/>
<%static:js group='discussion'/>
<%include file="../discussion/_js_body_dependencies.html" />
% if staff_access:
<%include file="xqa_interface.html"/>
% endif
<!-- TODO: http://docs.jquery.com/Plugins/Validation -->
<script type="text/javascript">
document.write('\x3Cscript type="text/javascript" src="' +
document.location.protocol + '//www.youtube.com/player_api">\x3C/script>');
</script>
<script type="text/javascript">
var $$course_id = "${course.id}";
$(function(){
$(".ui-accordion-header a, .ui-accordion-content .subtitle").each(function() {
var elemText = $(this).text().replace(/^\s+|\s+$/g,''); // Strip leading and trailing whitespace
var wordArray = elemText.split(" ");
var finalTitle = "";
if (wordArray.length > 0) {
for (i=0;i<=wordArray.length-1;i++) {
finalTitle += wordArray[i];
if (i == (wordArray.length-2)) {
finalTitle += "&nbsp;";
} else if (i == (wordArray.length-1)) {
// Do nothing
} else {
finalTitle += " ";
}
}
}
$(this).html(finalTitle);
});
});
</script>
<script type="text/javascript">
function getRemainingTime(){
function pretty_time_string(num) {
return ( num < 10 ? "0" : "" ) + num;
}
// set the end time when the template is rendered
var endTime = new Date(${end_date});
var currentTime = new Date();
var remaining_secs = Math.floor((endTime - currentTime)/1000);
// check to see if time has expired. If so, we need
// to go to the exit URL.
// TBD...
if (remaining_secs <= 0) {
return "00:00:00";
}
// count down in terms of hours, minutes, and seconds:
var hours = pretty_time_string(Math.floor(remaining_secs / 3600));
remaining_secs = remaining_secs % 3600;
var minutes = pretty_time_string(Math.floor(remaining_secs / 60));
remaining_secs = remaining_secs % 60;
var seconds = pretty_time_string(Math.floor(remaining_secs));
var remainingTimeString = hours + ":" + minutes + ":" + seconds;
return remainingTimeString;
}
setInterval(function(){
$('#exam_timer').text(getRemainingTime()); }, 1000);
// presumably we need to call something to clear the interval once
// the time has expired? Pass the object that the setInterval() returns
// to clearInterval()
</script>
</%block>
<!-- %include file="/courseware/course_navigation.html" args="active_page='courseware'" / -->
<span id="exam_timer">&nbsp;</span>
<section class="container">
<div class="course-wrapper">
<section class="course-content">
${content}
</section>
</div>
</section>
% if course.show_calculator:
<div class="calc-main">
<a aria-label="Open Calculator" href="#" class="calc">Calculator</a>
<div id="calculator_wrapper">
<form id="calculator">
<div class="input-wrapper">
<input type="text" id="calculator_input" />
<div class="help-wrapper">
<a href="#">Hints</a>
<dl class="help">
<dt>Suffixes:</dt>
<dd> %kMGTcmunp</dd>
<dt>Operations:</dt>
<dd>^ * / + - ()</dd>
<dt>Functions:</dt>
<dd>sin, cos, tan, sqrt, log10, log2, ln, arccos, arcsin, arctan, abs </dd>
<dt>Constants</dt>
<dd>e, pi</dd>
<!-- Students won't know what parallel means at this time. Complex numbers aren't well tested in the courseware, so we would prefer to not expose them. If you read the comments in the source, feel free to use them. If you run into a bug, please let us know. But we can't officially support them right now.
<dt>Unsupported:</dt> <dd>||, j </dd> -->
</dl>
</div>
</div>
<input id="calculator_button" type="submit" value="="/>
<input type="text" id="calculator_output" readonly />
</form>
</div>
</div>
% endif
<%namespace name='static' file='static_content.html'/>
<!DOCTYPE html>
<html>
<head>
<%block name="title"><title>edX</title></%block>
<!-- TODO: remove the link here, so there is no navigation at all on the page -->
<link rel="icon" type="image/x-icon" href="${static.url('images/favicon.ico')}" />
<%static:css group='application'/>
<%static:js group='main_vendor'/>
<%block name="headextra"/>
<!--[if lt IE 9]>
<script src="${static.url('js/html5shiv.js')}"></script>
<![endif]-->
<!--[if lte IE 9]>
<%static:css group='ie-fixes'/>
<![endif]-->
<meta name="path_prefix" content="${MITX_ROOT_URL}">
<meta name="google-site-verification" content="_mipQ4AtZQDNmbtOkwehQDOgCxUUV2fb_C0b6wbiRHY" />
% if not course:
<%include file="google_analytics.html" />
% endif
</head>
<body class="<%block name='bodyclass'/>">
<!-- %include file="navigation.html" / -->
<section class="content-wrapper">
${self.body()}
<%block name="bodyextra"/>
</section>
<!-- %include file="footer.html" / -->
<%static:js group='application'/>
<%static:js group='module-js'/>
<%block name="js_extra"/>
</body>
</html>
......@@ -217,6 +217,10 @@ if settings.COURSEWARE_ENABLED:
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/about$',
'courseware.views.course_about', name="about_course"),
# testcenter exam:
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/testcenter_exam/(?P<chapter>[^/]*)/(?P<section>[^/]*)/$',
'courseware.views.testcenter_exam', name="testcenter_exam"),
#Inside the course
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/$',
'courseware.views.course_info', name="course_root"),
......
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