Commit 44cfcb88 by Chris Dodge

Merge branch 'master' into feature/cdodge/cms-master-merge4

parents 0e2d8be4 7ac36d2f
......@@ -272,8 +272,9 @@ class TestCenterUserForm(ModelForm):
new_user = self.save(commit=False)
# create additional values here:
new_user.user_updated_at = datetime.utcnow()
new_user.upload_status = ''
new_user.save()
log.info("Updated demographic information for user's test center exam registration: username \"{}\" ".format(new_user.username))
log.info("Updated demographic information for user's test center exam registration: username \"{}\" ".format(new_user.user.username))
# add validation:
......@@ -534,6 +535,7 @@ class TestCenterRegistrationForm(ModelForm):
registration = self.save(commit=False)
# create additional values here:
registration.user_updated_at = datetime.utcnow()
registration.upload_status = ''
registration.save()
log.info("Updated registration information for user's test center exam registration: username \"{}\" course \"{}\", examcode \"{}\"".format(registration.testcenter_user.user.username, registration.course_id, registration.exam_series_code))
......
......@@ -632,15 +632,18 @@ def begin_exam_registration(request, course_id):
user = request.user
try:
course = (course_from_id(course_id))
course = course_from_id(course_id)
except ItemNotFoundError:
# TODO: do more than just log!! The rest will fail, so we should fail right now.
log.error("User {0} enrolled in non-existent course {1}"
.format(user.username, course_id))
log.error("User {0} enrolled in non-existent course {1}".format(user.username, course_id))
raise Http404
# get the exam to be registered for:
# (For now, we just assume there is one at most.)
# if there is no exam now (because someone bookmarked this stupid page),
# then return a 404:
exam_info = course.current_test_center_exam
if exam_info is None:
raise Http404
# determine if the user is registered for this course:
registration = exam_registration_info(user, course)
......@@ -675,11 +678,18 @@ def create_exam_registration(request, post_override=None):
username = post_vars['username']
user = User.objects.get(username=username)
course_id = post_vars['course_id']
course = (course_from_id(course_id)) # assume it will be found....
course = course_from_id(course_id) # assume it will be found....
# make sure that any demographic data values received from the page have been stripped.
# Whitespace is not an acceptable response for any of these values
demographic_data = {}
for fieldname in TestCenterUser.user_provided_fields():
if fieldname in post_vars:
demographic_data[fieldname] = (post_vars[fieldname]).strip()
try:
testcenter_user = TestCenterUser.objects.get(user=user)
needs_updating = testcenter_user.needs_update(post_vars)
needs_updating = testcenter_user.needs_update(demographic_data)
log.info("User {0} enrolled in course {1} {2}updating demographic info for exam registration".format(user.username, course_id, "" if needs_updating else "not "))
except TestCenterUser.DoesNotExist:
# do additional initialization here:
......@@ -691,7 +701,7 @@ def create_exam_registration(request, post_override=None):
if needs_updating:
# first perform validation on the user information
# using a Django Form.
form = TestCenterUserForm(instance=testcenter_user, data=post_vars)
form = TestCenterUserForm(instance=testcenter_user, data=demographic_data)
if form.is_valid():
form.update_and_save()
else:
......
......@@ -22,8 +22,6 @@ from xmodule.modulestore import Location
import self_assessment_module
import open_ended_module
from mitxmako.shortcuts import render_to_string
log = logging.getLogger("mitx.courseware")
# Set the default number of max attempts. Should be 1 for production
......@@ -319,7 +317,7 @@ class CombinedOpenEndedModule(XModule):
Output: HTML rendered directly via Mako
"""
context = self.get_context()
html = render_to_string('combined_open_ended.html', context)
html = self.system.render_template('combined_open_ended.html', context)
return html
def get_html_base(self):
......@@ -369,17 +367,17 @@ class CombinedOpenEndedModule(XModule):
self.static_data, instance_state=task_state)
last_response = task.latest_answer()
last_score = task.latest_score()
last_post_assessment = task.latest_post_assessment()
last_post_assessment = task.latest_post_assessment(self.system)
last_post_feedback = ""
if task_type == "openended":
last_post_assessment = task.latest_post_assessment(short_feedback=False, join_feedback=False)
last_post_assessment = task.latest_post_assessment(self.system, short_feedback=False, join_feedback=False)
if isinstance(last_post_assessment, list):
eval_list = []
for i in xrange(0, len(last_post_assessment)):
eval_list.append(task.format_feedback_with_evaluation(last_post_assessment[i]))
eval_list.append(task.format_feedback_with_evaluation(self.system, last_post_assessment[i]))
last_post_evaluation = "".join(eval_list)
else:
last_post_evaluation = task.format_feedback_with_evaluation(last_post_assessment)
last_post_evaluation = task.format_feedback_with_evaluation(self.system, last_post_assessment)
last_post_assessment = last_post_evaluation
last_correctness = task.is_last_response_correct()
max_score = task.max_score()
......@@ -442,7 +440,7 @@ class CombinedOpenEndedModule(XModule):
self.update_task_states()
response_dict = self.get_last_response(task_number)
context = {'results': response_dict['post_assessment'], 'task_number': task_number + 1}
html = render_to_string('combined_open_ended_results.html', context)
html = self.system.render_template('combined_open_ended_results.html', context)
return {'html': html, 'success': True}
def handle_ajax(self, dispatch, get):
......
from mitxmako.shortcuts import render_to_string
import logging
from lxml import etree
log=logging.getLogger(__name__)
class CombinedOpenEndedRubric:
class CombinedOpenEndedRubric(object):
@staticmethod
def render_rubric(rubric_xml):
def render_rubric(rubric_xml, system):
try:
rubric_categories = CombinedOpenEndedRubric.extract_rubric_categories(rubric_xml)
html = render_to_string('open_ended_rubric.html', {'rubric_categories' : rubric_categories})
html = system.render_template('open_ended_rubric.html', {'rubric_categories' : rubric_categories})
except:
log.exception("Could not parse the rubric.")
html = rubric_xml
......
......@@ -24,11 +24,10 @@ class GraphicalSliderToolModule(XModule):
'''
js = {
'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee')],
'js': [
# 3rd party libraries used by graphic slider tool.
# TODO - where to store them - outside xmodule?
resource_string(__name__, 'js/src/graphical_slider_tool/jstat-1.0.0.min.js'),
resource_string(__name__, 'js/src/graphical_slider_tool/gst_main.js'),
resource_string(__name__, 'js/src/graphical_slider_tool/state.js'),
resource_string(__name__, 'js/src/graphical_slider_tool/logme.js'),
......@@ -38,8 +37,8 @@ class GraphicalSliderToolModule(XModule):
resource_string(__name__, 'js/src/graphical_slider_tool/graph.js'),
resource_string(__name__, 'js/src/graphical_slider_tool/el_output.js'),
resource_string(__name__, 'js/src/graphical_slider_tool/g_label_el_output.js'),
resource_string(__name__, 'js/src/graphical_slider_tool/gst.js')
]
}
js_module_name = "GraphicalSliderTool"
......
......@@ -401,7 +401,7 @@ define('Graph', ['logme'], function (logme) {
return false;
}
} else {
logme('MESSAGE: "xticks" were not specified. Using defaults.');
// logme('MESSAGE: "xticks" were not specified. Using defaults.');
return false;
}
......@@ -416,7 +416,7 @@ define('Graph', ['logme'], function (logme) {
return false;
}
} else {
logme('MESSAGE: "yticks" were not specified. Using defaults.');
// logme('MESSAGE: "yticks" were not specified. Using defaults.');
return false;
}
......
......@@ -14,7 +14,9 @@ window.GraphicalSliderTool = function (el) {
// with a unique DOM ID), we will iterate over all children, and for
// each match, we will call GstMain module.
$(el).children('.graphical_slider_tool').each(function (index, value) {
GstMain($(value).attr('id'));
JavascriptLoader.executeModuleScripts($(value), function(){
GstMain($(value).attr('id'));
});
});
});
};
......@@ -19,7 +19,7 @@ define(
if ($('#' + gstId).attr('data-processed') !== 'processed') {
$('#' + gstId).attr('data-processed', 'processed');
} else {
logme('MESSAGE: Already processed GST with ID ' + gstId + '. Skipping.');
// logme('MESSAGE: Already processed GST with ID ' + gstId + '. Skipping.');
return;
}
......
......@@ -20,9 +20,9 @@ define('Sliders', ['logme'], function (logme) {
} else if (sliderDiv.length > 1) {
logme('ERROR: Found more than one slider for the parameter "' + paramName + '".');
logme('sliderDiv.length = ', sliderDiv.length);
} else {
logme('MESSAGE: Did not find a slider for the parameter "' + paramName + '".');
}
} // else {
// logme('MESSAGE: Did not find a slider for the parameter "' + paramName + '".');
// }
}
function createSlider(sliderDiv, paramName) {
......
......@@ -24,7 +24,7 @@ define('State', ['logme'], function (logme) {
dynamicElByElId = {};
stateInst += 1;
logme('MESSAGE: Creating state instance # ' + stateInst + '.');
// logme('MESSAGE: Creating state instance # ' + stateInst + '.');
// Initially, there are no parameters to track. So, we will instantiate
// an empty object.
......
......@@ -30,7 +30,6 @@ from xmodule.modulestore import Location
from capa.util import *
import openendedchild
from mitxmako.shortcuts import render_to_string
from numpy import median
from datetime import datetime
......@@ -256,7 +255,7 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
@param system: Modulesystem
@return: Boolean True (not useful currently)
"""
new_score_msg = self._parse_score_msg(score_msg)
new_score_msg = self._parse_score_msg(score_msg, system)
if not new_score_msg['valid']:
score_msg['feedback'] = 'Invalid grader reply. Please contact the course staff.'
......@@ -370,7 +369,7 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
return u"\n".join([feedback_list_part1, feedback_list_part2])
def _format_feedback(self, response_items):
def _format_feedback(self, response_items, system):
"""
Input:
Dictionary called feedback. Must contain keys seen below.
......@@ -382,13 +381,13 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
rubric_feedback=""
feedback = self._convert_longform_feedback_to_html(response_items)
if response_items['rubric_scores_complete']==True:
rubric_feedback = CombinedOpenEndedRubric.render_rubric(response_items['rubric_xml'])
rubric_feedback = CombinedOpenEndedRubric.render_rubric(response_items['rubric_xml'], system)
if not response_items['success']:
return system.render_template("open_ended_error.html",
{'errors': feedback})
feedback_template = render_to_string("open_ended_feedback.html", {
feedback_template = system.render_template("open_ended_feedback.html", {
'grader_type': response_items['grader_type'],
'score': "{0} / {1}".format(response_items['score'], self.max_score()),
'feedback': feedback,
......@@ -398,7 +397,7 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
return feedback_template
def _parse_score_msg(self, score_msg, join_feedback=True):
def _parse_score_msg(self, score_msg, system, join_feedback=True):
"""
Grader reply is a JSON-dump of the following dict
{ 'correct': True/False,
......@@ -450,7 +449,7 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
'rubric_scores_complete' : score_result['rubric_scores_complete'],
'rubric_xml' : score_result['rubric_xml'],
}
feedback_items.append(self._format_feedback(new_score_result))
feedback_items.append(self._format_feedback(new_score_result, system))
if join_feedback:
feedback = "".join(feedback_items)
else:
......@@ -458,7 +457,7 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
score = int(median(score_result['score']))
else:
#This is for instructor and ML grading
feedback = self._format_feedback(score_result)
feedback = self._format_feedback(score_result, system)
score = score_result['score']
self.submission_id = score_result['submission_id']
......@@ -466,7 +465,7 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
return {'valid': True, 'score': score, 'feedback': feedback}
def latest_post_assessment(self, short_feedback=False, join_feedback=True):
def latest_post_assessment(self, system, short_feedback=False, join_feedback=True):
"""
Gets the latest feedback, parses, and returns
@param short_feedback: If the long feedback is wanted or not
......@@ -475,7 +474,7 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
if not self.history:
return ""
feedback_dict = self._parse_score_msg(self.history[-1].get('post_assessment', ""), join_feedback=join_feedback)
feedback_dict = self._parse_score_msg(self.history[-1].get('post_assessment', ""), system, join_feedback=join_feedback)
if not short_feedback:
return feedback_dict['feedback'] if feedback_dict['valid'] else ''
if feedback_dict['valid']:
......@@ -483,14 +482,14 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
json.loads(self.history[-1].get('post_assessment', "")))
return short_feedback if feedback_dict['valid'] else ''
def format_feedback_with_evaluation(self, feedback):
def format_feedback_with_evaluation(self, system, feedback):
"""
Renders a given html feedback into an evaluation template
@param feedback: HTML feedback
@return: Rendered html
"""
context = {'msg': feedback, 'id': "1", 'rows': 50, 'cols': 50}
html = render_to_string('open_ended_evaluation.html', context)
html = system.render_template('open_ended_evaluation.html', context)
return html
def handle_ajax(self, dispatch, get, system):
......@@ -582,7 +581,7 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
if self.state != self.INITIAL:
latest = self.latest_answer()
previous_answer = latest if latest is not None else self.initial_display
post_assessment = self.latest_post_assessment()
post_assessment = self.latest_post_assessment(system)
score = self.latest_score()
correct = 'correct' if self.is_submission_correct(score) else 'incorrect'
else:
......
......@@ -35,7 +35,7 @@ MAX_ATTEMPTS = 1
# Overriden by max_score specified in xml.
MAX_SCORE = 1
class OpenEndedChild():
class OpenEndedChild(object):
"""
States:
......@@ -123,7 +123,7 @@ class OpenEndedChild():
return None
return self.history[-1].get('score')
def latest_post_assessment(self):
def latest_post_assessment(self, system):
"""None if not available"""
if not self.history:
return ""
......
......@@ -122,7 +122,7 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
if self.state == self.INITIAL:
return ''
rubric_html = CombinedOpenEndedRubric.render_rubric(self.rubric)
rubric_html = CombinedOpenEndedRubric.render_rubric(self.rubric, system)
# we'll render it
context = {'rubric': rubric_html,
......@@ -147,7 +147,7 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
if self.state == self.DONE:
# display the previous hint
latest = self.latest_post_assessment()
latest = self.latest_post_assessment(system)
hint = latest if latest is not None else ''
else:
hint = ''
......
......@@ -194,30 +194,9 @@
margin-bottom: 40px;
h3 {
background: url('/static/images/bullet-closed.png') no-repeat left 0.25em;
font-family: $sans-serif;
font-weight: 700;
margin-bottom: 10px;
padding-left: 20px;
cursor: pointer;
}
.answer {
display: none;
color: #3c3c3c;
padding-left: 16px;
font-family: $serif;
li {
line-height: 1.6em;
}
}
// opened states
&.opened {
h3 {
background: url('/static/images/bullet-open.png') no-repeat left 0.25em;
}
margin-bottom: 15px;
}
}
}
......
......@@ -426,6 +426,14 @@
font-size: 1.2rem;
font-weight: bold;
}
strong {
font-weight: 700;
a {
font-weight: 700;
}
}
}
.actions {
......
.static-container.help {
section.questions {
float: left;
width: flex-grid(9);
margin-right: flex-gutter();
@include clearfix;
article {
margin-bottom: 40px;
nav.categories {
border: 1px solid rgb(220,220,220);
@include box-sizing(border-box);
float: left;
margin-left: flex-gutter();
padding: 20px;
width: flex-grid(3);
h2 {
border-bottom: 1px solid rgb(220,220,220);
margin-bottom: 40px;
padding-bottom: 20px;
a {
display: block;
letter-spacing: 1px;
margin: 0px -20px;
padding: 12px 0px 12px 20px;
text-align: left;
&:hover {
background: rgb(245,245,245);
text-decoration: none;
}
}
}
}
section.emails {
border: 1px solid rgb(220,220,220);
@include box-sizing(border-box);
float: left;
padding: 20px;
width: flex-grid(3);
.responses {
float: left;
width: flex-grid(9);
ul {
margin-left: 0;
padding-left: 0;
list-style: none;
.category {
padding-top: 40px;
li {
margin-bottom: 1em;
&:first-child {
padding-top: 0px;
}
> h2 {
border-bottom: 1px solid rgb(220,220,220);
margin-bottom: 40px;
padding-bottom: 20px;
}
}
.response {
margin-bottom: 40px;
h3 {
background: url('/static/images/bullet-closed.png') no-repeat left 0.25em;
font-family: $sans-serif;
font-weight: 700;
margin-bottom: 10px;
padding-left: 20px;
cursor: pointer;
}
.answer {
display: none;
color: #3c3c3c;
padding-left: 16px;
font-family: $serif;
li {
line-height: 1.6em;
}
}
// opened states
&.opened {
h3 {
background: url('/static/images/bullet-open.png') no-repeat left 0.25em;
}
}
}
}
}
}
......@@ -232,8 +232,9 @@ $red: rgb(178, 6, 16);
}
input, textarea {
height: 100%;
width: 100%;
padding: $baseline ($baseline*.75);
padding: ($baseline/2);
&.long {
width: 100%;
......
......@@ -243,22 +243,15 @@
% endif
% if registration.is_rejected:
<div class="message message-status is-shown exam-schedule">
<p class="message-copy">Your
<a href="${testcenter_register_target}" id="exam_register_link">registration for the Pearson exam</a>
has been rejected. Please check the information you provided, and try to correct any demographic errors. Otherwise
contact edX for further help.</p>
<a href="mailto:exam-help@edx.org?subject=Pearson VUE Exam - ${get_course_about_section(course, 'university')} ${course.number}" class="button contact-button">Contact exam-help@edx.org</a>
<p class="message-copy"><strong>Your registration for the Pearson exam has been rejected. Please <a href="${testcenter_register_target}" id="exam_register_link">see your registration status details</a></strong>. Otherwise <a class="contact-link" href="mailto:exam-help@edx.org?subject=Pearson VUE Exam - ${get_course_about_section(course, 'university')} ${course.number}">contact edX at exam-help@edx.org</a> for further help.</p>
</div>
% endif
% if not registration.is_accepted and not registration.is_rejected:
<div class="message message-status is-shown">
<p class="message-copy">Your
<a href="${testcenter_register_target}" id="exam_register_link">registration for the Pearson exam</a>
is pending. Within a few days, you should see a confirmation number here, which can be used to schedule your exam.</p>
<p class="message-copy"><strong>Your <a href="${testcenter_register_target}" id="exam_register_link">registration for the Pearson exam</a> is pending</strong>. Within a few days, you should see a confirmation number here, which can be used to schedule your exam.</p>
</div>
% endif
% endif
% endif
<%
......
......@@ -164,7 +164,7 @@
<section id="video-modal" class="modal home-page-video-modal video-modal">
<div class="inner-wrapper">
<iframe width="640" height="360" src="http://www.youtube.com/embed/IlNU60ZKj3I?showinfo=0" frameborder="0" allowfullscreen></iframe>
<iframe width="640" height="360" src="http://www.youtube.com/embed/XNaiOGxWeto?showinfo=0" frameborder="0" allowfullscreen></iframe>
</div>
</section>
......
......@@ -128,7 +128,7 @@
% if registration.registration_is_rejected:
<section class="status message message-flash registration-rejected message-action is-shown">
<h3 class="message-title">Your registration for the Pearson exam has been rejected</h3>
<p class="message-copy">Please see your registration status details for more information.</p>
<p class="message-copy">Please see your <strong>registration status</strong> details for more information.</p>
</section>
% endif
......@@ -246,25 +246,25 @@
<li class="field-group phoneinfo">
<div class="field required" id="field-phone">
<label for="phone">Phone Number</label>
<input id="phone" type="tel" name="phone" value="${testcenteruser.phone}" placeholder="e.g. 1-55-555-5555" />
<input id="phone" type="tel" name="phone" value="${testcenteruser.phone}" />
</div>
<div class="field" id="field-extension">
<label for="extension">Extension</label>
<input id="extension" class="short" type="tel" name="extension" value="${testcenteruser.extension}" placeholder="e.g. 555" />
<input id="extension" class="short" type="tel" name="extension" value="${testcenteruser.extension}" />
</div>
<div class="field required" id="field-phone_country_code">
<label for="phone_country_code">Phone Country Code</label>
<input id="phone_country_code" class="short" type="text" name="phone_country_code" value="${testcenteruser.phone_country_code}" placeholder="e.g. 1, 44, 976" />
<input id="phone_country_code" class="short" type="text" name="phone_country_code" value="${testcenteruser.phone_country_code}" />
</div>
</li>
<li class="field-group faxinfo">
<div class="field" id="field-fax">
<label for="fax">Fax Number</label>
<input id="fax" type="tel" class="short" name="fax" value="${testcenteruser.fax}" placeholder="e.g. 1-55-555-5555" />
<input id="fax" type="tel" class="short" name="fax" value="${testcenteruser.fax}" />
</div>
<div class="field" id="field-fax_country_code">
<label for="fax_country_code">Fax Country Code</label>
<input id="fax_country_code" class="short" type="text" name="fax_country_code" value="${testcenteruser.fax_country_code}" placeholder="e.g. 1, 44, 976" />
<input id="fax_country_code" class="short" type="text" name="fax_country_code" value="${testcenteruser.fax_country_code}" />
</div>
</li>
<li class="field" id="field-company_name">
......@@ -474,7 +474,7 @@
<div class="details details-contact">
<h4>Questions</h4>
<p>If you have a specific question pertaining to your registration, you may contact <a class="contact-link" href="${exam_help_href}">exam-help@edx.org</a>.</p>
<p>If you have a specific question pertaining to your registration, you may <a class="contact-link" href="${exam_help_href}">contact edX at exam-help@edx.org</a>.</p>
</div>
</aside>
</section>
......@@ -52,8 +52,7 @@ pil==1.1.7
nltk==2.0.4
django-debug-toolbar-mongo
dogstatsd-python==0.2.1
# Taking out MySQL-python for now because it requires mysql to be installed, so breaks updates on content folks' envs.
# MySQL-python
MySQL-python==1.2.4c1
sphinx==1.1.3
factory_boy
Shapely==1.2.16
......
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