diff --git a/cms/djangoapps/contentstore/views.py b/cms/djangoapps/contentstore/views.py index 2d3c90d6b8..34003d71a4 100644 --- a/cms/djangoapps/contentstore/views.py +++ b/cms/djangoapps/contentstore/views.py @@ -68,6 +68,10 @@ log = logging.getLogger(__name__) COMPONENT_TYPES = ['customtag', 'discussion', 'html', 'problem', 'video'] +ADVANCED_COMPONENT_TYPES = ['annotatable','combinedopenended', 'peergrading'] +ADVANCED_COMPONENT_CATEGORY = 'advanced' +ADVANCED_COMPONENT_POLICY_KEY = 'advanced_modules' + # cdodge: these are categories which should not be parented, they are detached from the hierarchy DETACHED_CATEGORIES = ['about', 'static_tab', 'course_info'] @@ -281,10 +285,31 @@ def edit_unit(request, location): component_templates = defaultdict(list) + # Check if there are any advanced modules specified in the course policy. These modules + # should be specified as a list of strings, where the strings are the names of the modules + # in ADVANCED_COMPONENT_TYPES that should be enabled for the course. + course_metadata = CourseMetadata.fetch(course.location) + course_advanced_keys = course_metadata.get(ADVANCED_COMPONENT_POLICY_KEY, []) + + # Set component types according to course policy file + component_types = list(COMPONENT_TYPES) + if isinstance(course_advanced_keys, list): + course_advanced_keys = [c for c in course_advanced_keys if c in ADVANCED_COMPONENT_TYPES] + if len(course_advanced_keys) > 0: + component_types.append(ADVANCED_COMPONENT_CATEGORY) + else: + log.error("Improper format for course advanced keys! {0}".format(course_advanced_keys)) + templates = modulestore().get_items(Location('i4x', 'edx', 'templates')) for template in templates: - if template.location.category in COMPONENT_TYPES: - component_templates[template.location.category].append(( + category = template.location.category + + if category in course_advanced_keys: + category = ADVANCED_COMPONENT_CATEGORY + + if category in component_types: + #This is a hack to create categories for different xmodules + component_templates[category].append(( template.display_name, template.location.url(), 'markdown' in template.metadata, diff --git a/cms/static/img/large-advanced-icon.png b/cms/static/img/large-advanced-icon.png new file mode 100644 index 0000000000..c6a19ea5a9 Binary files /dev/null and b/cms/static/img/large-advanced-icon.png differ diff --git a/cms/static/img/large-annotations-icon.png b/cms/static/img/large-annotations-icon.png new file mode 100644 index 0000000000..249193521f Binary files /dev/null and b/cms/static/img/large-annotations-icon.png differ diff --git a/cms/static/img/large-openended-icon.png b/cms/static/img/large-openended-icon.png new file mode 100644 index 0000000000..4d31815413 Binary files /dev/null and b/cms/static/img/large-openended-icon.png differ diff --git a/cms/static/sass/_graphics.scss b/cms/static/sass/_graphics.scss index 4ed22c570d..300cf3b692 100644 --- a/cms/static/sass/_graphics.scss +++ b/cms/static/sass/_graphics.scss @@ -254,6 +254,30 @@ background: url(../img/html-icon.png) center no-repeat; } +.large-openended-icon { + display: inline-block; + width: 100px; + height: 60px; + margin-right: 5px; + background: url(../img/large-openended-icon.png) center no-repeat; +} + +.large-annotations-icon { + display: inline-block; + width: 100px; + height: 60px; + margin-right: 5px; + background: url(../img/large-annotations-icon.png) center no-repeat; +} + +.large-advanced-icon { + display: inline-block; + width: 100px; + height: 60px; + margin-right: 5px; + background: url(../img/large-advanced-icon.png) center no-repeat; +} + .large-textbook-icon { display: inline-block; width: 100px; diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_modulev1.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_modulev1.py index 171441c562..5c3bfa5b2a 100644 --- a/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_modulev1.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_modulev1.py @@ -79,6 +79,9 @@ class CombinedOpenEndedV1Module(): INTERMEDIATE_DONE = 'intermediate_done' DONE = 'done' + #Where the templates live for this problem + TEMPLATE_DIR = "combinedopenended" + def __init__(self, system, location, definition, descriptor, instance_state=None, shared_state=None, metadata = None, static_data = None, **kwargs): @@ -343,7 +346,7 @@ class CombinedOpenEndedV1Module(): Output: rendered html """ context = self.get_context() - html = self.system.render_template('combined_open_ended.html', context) + html = self.system.render_template('{0}/combined_open_ended.html'.format(self.TEMPLATE_DIR), context) return html def get_html_nonsystem(self): @@ -354,7 +357,7 @@ class CombinedOpenEndedV1Module(): Output: HTML rendered directly via Mako """ context = self.get_context() - html = self.system.render_template('combined_open_ended.html', context) + html = self.system.render_template('{0}/combined_open_ended.html'.format(self.TEMPLATE_DIR), context) return html def get_html_base(self): @@ -531,7 +534,7 @@ class CombinedOpenEndedV1Module(): 'task_name' : 'Scored Rubric', 'class_name' : 'combined-rubric-container' } - html = self.system.render_template('combined_open_ended_results.html', context) + html = self.system.render_template('{0}/combined_open_ended_results.html'.format(self.TEMPLATE_DIR), context) return {'html': html, 'success': True} def get_legend(self, get): @@ -543,7 +546,7 @@ class CombinedOpenEndedV1Module(): context = { 'legend_list' : LEGEND_LIST, } - html = self.system.render_template('combined_open_ended_legend.html', context) + html = self.system.render_template('{0}/combined_open_ended_legend.html'.format(self.TEMPLATE_DIR), context) return {'html': html, 'success': True} def get_results(self, get): @@ -574,7 +577,7 @@ class CombinedOpenEndedV1Module(): 'submission_id' : ri['submission_ids'][i], } context_list.append(context) - feedback_table = self.system.render_template('open_ended_result_table.html', { + feedback_table = self.system.render_template('{0}/open_ended_result_table.html'.format(self.TEMPLATE_DIR), { 'context_list' : context_list, 'grader_type_image_dict' : GRADER_TYPE_IMAGE_DICT, 'human_grader_types' : HUMAN_GRADER_TYPE, @@ -586,7 +589,7 @@ class CombinedOpenEndedV1Module(): 'task_name' : "Feedback", 'class_name' : "result-container", } - html = self.system.render_template('combined_open_ended_results.html', context) + html = self.system.render_template('{0}/combined_open_ended_results.html'.format(self.TEMPLATE_DIR), context) return {'html': html, 'success': True} def get_status_ajax(self, get): @@ -700,7 +703,7 @@ class CombinedOpenEndedV1Module(): 'legend_list' : LEGEND_LIST, 'render_via_ajax' : render_via_ajax, } - status_html = self.system.render_template("combined_open_ended_status.html", context) + status_html = self.system.render_template("{0}/combined_open_ended_status.html".format(self.TEMPLATE_DIR), context) return status_html diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_rubric.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_rubric.py index f756b2b853..8d1bd376fb 100644 --- a/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_rubric.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_rubric.py @@ -30,6 +30,8 @@ class RubricParsingError(Exception): class CombinedOpenEndedRubric(object): + TEMPLATE_DIR = "combinedopenended/openended" + def __init__ (self, system, view_only = False): self.has_score = False self.view_only = view_only @@ -57,9 +59,9 @@ class CombinedOpenEndedRubric(object): rubric_scores = [cat['score'] for cat in rubric_categories] max_scores = map((lambda cat: cat['options'][-1]['points']), rubric_categories) max_score = max(max_scores) - rubric_template = 'open_ended_rubric.html' + rubric_template = '{0}/open_ended_rubric.html'.format(self.TEMPLATE_DIR) if self.view_only: - rubric_template = 'open_ended_view_only_rubric.html' + rubric_template = '{0}/open_ended_view_only_rubric.html'.format(self.TEMPLATE_DIR) html = self.system.render_template(rubric_template, {'categories': rubric_categories, 'has_score': self.has_score, @@ -207,7 +209,7 @@ class CombinedOpenEndedRubric(object): for grader_type in tuple[3]: rubric_categories[i]['options'][j]['grader_types'].append(grader_type) - html = self.system.render_template('open_ended_combined_rubric.html', + html = self.system.render_template('{0}/open_ended_combined_rubric.html'.format(self.TEMPLATE_DIR), {'categories': rubric_categories, 'has_score': True, 'view_only': True, diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/open_ended_module.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/open_ended_module.py index 974d23965f..aa805a5290 100644 --- a/common/lib/xmodule/xmodule/open_ended_grading_classes/open_ended_module.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/open_ended_module.py @@ -40,6 +40,8 @@ class OpenEndedModule(openendedchild.OpenEndedChild): """ + TEMPLATE_DIR = "combinedopenended/openended" + def setup_response(self, system, location, definition, descriptor): """ Sets up the response type. @@ -397,10 +399,10 @@ class OpenEndedModule(openendedchild.OpenEndedChild): rubric_scores = rubric_dict['rubric_scores'] if not response_items['success']: - return system.render_template("open_ended_error.html", + return system.render_template("{0}/open_ended_error.html".format(self.TEMPLATE_DIR), {'errors': feedback}) - feedback_template = system.render_template("open_ended_feedback.html", { + feedback_template = system.render_template("{0}/open_ended_feedback.html".format(self.TEMPLATE_DIR), { 'grader_type': response_items['grader_type'], 'score': "{0} / {1}".format(response_items['score'], self.max_score()), 'feedback': feedback, @@ -558,7 +560,7 @@ class OpenEndedModule(openendedchild.OpenEndedChild): @return: Rendered html """ context = {'msg': feedback, 'id': "1", 'rows': 50, 'cols': 50} - html = system.render_template('open_ended_evaluation.html', context) + html = system.render_template('{0}/open_ended_evaluation.html'.format(self.TEMPLATE_DIR), context) return html def handle_ajax(self, dispatch, get, system): @@ -692,7 +694,7 @@ class OpenEndedModule(openendedchild.OpenEndedChild): 'accept_file_upload': self.accept_file_upload, 'eta_message' : eta_string, } - html = system.render_template('open_ended.html', context) + html = system.render_template('{0}/open_ended.html'.format(self.TEMPLATE_DIR), context) return html diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/self_assessment_module.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/self_assessment_module.py index 7ecb3c4d5e..f4be426667 100644 --- a/common/lib/xmodule/xmodule/open_ended_grading_classes/self_assessment_module.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/self_assessment_module.py @@ -32,6 +32,8 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild): """ + TEMPLATE_DIR = "combinedopenended/selfassessment" + def setup_response(self, system, location, definition, descriptor): """ Sets up the module @@ -68,7 +70,7 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild): 'accept_file_upload': self.accept_file_upload, } - html = system.render_template('self_assessment_prompt.html', context) + html = system.render_template('{0}/self_assessment_prompt.html'.format(self.TEMPLATE_DIR), context) return html @@ -129,7 +131,7 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild): #This is a dev_facing_error raise ValueError("Self assessment module is in an illegal state '{0}'".format(self.state)) - return system.render_template('self_assessment_rubric.html', context) + return system.render_template('{0}/self_assessment_rubric.html'.format(self.TEMPLATE_DIR), context) def get_hint_html(self, system): """ @@ -155,7 +157,7 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild): #This is a dev_facing_error raise ValueError("Self Assessment module is in an illegal state '{0}'".format(self.state)) - return system.render_template('self_assessment_hint.html', context) + return system.render_template('{0}/self_assessment_hint.html'.format(self.TEMPLATE_DIR), context) def save_answer(self, get, system): diff --git a/common/lib/xmodule/xmodule/peer_grading_module.py b/common/lib/xmodule/xmodule/peer_grading_module.py index 97abfdbfba..1e52dcf070 100644 --- a/common/lib/xmodule/xmodule/peer_grading_module.py +++ b/common/lib/xmodule/xmodule/peer_grading_module.py @@ -471,6 +471,9 @@ class PeerGradingModule(XModule): #This is a student_facing_error error_text = "Could not get list of problems to peer grade. Please notify course staff." success = False + except: + log.exception("Could not contact peer grading service.") + success = False def _find_corresponding_module_for_location(location): @@ -589,7 +592,6 @@ class PeerGradingDescriptor(XmlDescriptor, EditingDescriptor): 'task_xml': dictionary of xml strings, } """ - log.debug("In definition") expected_children = [] for child in expected_children: if len(xml_object.xpath(child)) == 0: diff --git a/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml b/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml new file mode 100644 index 0000000000..f2aba0e18b --- /dev/null +++ b/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml @@ -0,0 +1,44 @@ +--- +metadata: + display_name: Open Ended Response + max_attempts: 1 + max_score: 1 + is_graded: False + version: 1 + display_name: Open Ended Response + skip_spelling_checks: False + accept_file_upload: False +data: | + + + + + Category 1 + + + + + + +

Why is the sky blue?

+
+ + + + + + + Enter essay here. + This is the answer. + {"grader_settings" : "peer_grading.conf", "problem_id" : "700x/Demo"} + + + +
+ + +children: [] diff --git a/common/lib/xmodule/xmodule/templates/peer_grading/default.yaml b/common/lib/xmodule/xmodule/templates/peer_grading/default.yaml new file mode 100644 index 0000000000..cb8e29dfa2 --- /dev/null +++ b/common/lib/xmodule/xmodule/templates/peer_grading/default.yaml @@ -0,0 +1,13 @@ +--- +metadata: + display_name: Peer Grading Interface + attempts: 1 + use_for_single_location: False + link_to_location: None + is_graded: False + max_grade: 1 +data: | + + + +children: [] diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index 76919d4103..55e8088c3f 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -89,14 +89,24 @@ def peer_grading(request, course_id): Show a peer grading interface ''' + #Get the current course course = get_course_with_access(request.user, course_id, 'load') course_id_parts = course.id.split("/") - course_id_norun = "/".join(course_id_parts[0:2]) - pg_location = "i4x://" + course_id_norun + "/peergrading/init" + false_dict = [False,"False", "false", "FALSE"] + #Reverse the base course url base_course_url = reverse('courses') try: - problem_url_parts = search.path_to_location(modulestore(), course.id, pg_location) + #TODO: This will not work with multiple runs of a course. Make it work. The last key in the Location passed + #to get_items is called revision. Is this the same as run? + #Get the peer grading modules currently in the course + items = modulestore().get_items(['i4x', None, course_id_parts[1], 'peergrading', None]) + #See if any of the modules are centralized modules (ie display info from multiple problems) + items = [i for i in items if i.metadata.get("use_for_single_location", True) in false_dict] + #Get the first one + item_location = items[0].location + #Generate a url for the first module and redirect the user to it + problem_url_parts = search.path_to_location(modulestore(), course.id, item_location) problem_url = generate_problem_url(problem_url_parts, base_course_url) return HttpResponseRedirect(problem_url) diff --git a/lms/templates/combined_open_ended.html b/lms/templates/combinedopenended/combined_open_ended.html similarity index 100% rename from lms/templates/combined_open_ended.html rename to lms/templates/combinedopenended/combined_open_ended.html diff --git a/lms/templates/combined_open_ended_legend.html b/lms/templates/combinedopenended/combined_open_ended_legend.html similarity index 100% rename from lms/templates/combined_open_ended_legend.html rename to lms/templates/combinedopenended/combined_open_ended_legend.html diff --git a/lms/templates/combined_open_ended_results.html b/lms/templates/combinedopenended/combined_open_ended_results.html similarity index 100% rename from lms/templates/combined_open_ended_results.html rename to lms/templates/combinedopenended/combined_open_ended_results.html diff --git a/lms/templates/combined_open_ended_status.html b/lms/templates/combinedopenended/combined_open_ended_status.html similarity index 100% rename from lms/templates/combined_open_ended_status.html rename to lms/templates/combinedopenended/combined_open_ended_status.html diff --git a/lms/templates/open_ended_result_table.html b/lms/templates/combinedopenended/open_ended_result_table.html similarity index 100% rename from lms/templates/open_ended_result_table.html rename to lms/templates/combinedopenended/open_ended_result_table.html diff --git a/lms/templates/open_ended.html b/lms/templates/combinedopenended/openended/open_ended.html similarity index 100% rename from lms/templates/open_ended.html rename to lms/templates/combinedopenended/openended/open_ended.html diff --git a/lms/templates/open_ended_combined_rubric.html b/lms/templates/combinedopenended/openended/open_ended_combined_rubric.html similarity index 100% rename from lms/templates/open_ended_combined_rubric.html rename to lms/templates/combinedopenended/openended/open_ended_combined_rubric.html diff --git a/lms/templates/open_ended_error.html b/lms/templates/combinedopenended/openended/open_ended_error.html similarity index 100% rename from lms/templates/open_ended_error.html rename to lms/templates/combinedopenended/openended/open_ended_error.html diff --git a/lms/templates/open_ended_evaluation.html b/lms/templates/combinedopenended/openended/open_ended_evaluation.html similarity index 100% rename from lms/templates/open_ended_evaluation.html rename to lms/templates/combinedopenended/openended/open_ended_evaluation.html diff --git a/lms/templates/open_ended_feedback.html b/lms/templates/combinedopenended/openended/open_ended_feedback.html similarity index 100% rename from lms/templates/open_ended_feedback.html rename to lms/templates/combinedopenended/openended/open_ended_feedback.html diff --git a/lms/templates/open_ended_rubric.html b/lms/templates/combinedopenended/openended/open_ended_rubric.html similarity index 100% rename from lms/templates/open_ended_rubric.html rename to lms/templates/combinedopenended/openended/open_ended_rubric.html diff --git a/lms/templates/open_ended_view_only_rubric.html b/lms/templates/combinedopenended/openended/open_ended_view_only_rubric.html similarity index 100% rename from lms/templates/open_ended_view_only_rubric.html rename to lms/templates/combinedopenended/openended/open_ended_view_only_rubric.html diff --git a/lms/templates/self_assessment_hint.html b/lms/templates/combinedopenended/selfassessment/self_assessment_hint.html similarity index 100% rename from lms/templates/self_assessment_hint.html rename to lms/templates/combinedopenended/selfassessment/self_assessment_hint.html diff --git a/lms/templates/self_assessment_prompt.html b/lms/templates/combinedopenended/selfassessment/self_assessment_prompt.html similarity index 100% rename from lms/templates/self_assessment_prompt.html rename to lms/templates/combinedopenended/selfassessment/self_assessment_prompt.html diff --git a/lms/templates/self_assessment_rubric.html b/lms/templates/combinedopenended/selfassessment/self_assessment_rubric.html similarity index 100% rename from lms/templates/self_assessment_rubric.html rename to lms/templates/combinedopenended/selfassessment/self_assessment_rubric.html