From 59e36476925899081d7a945e7298a3f74136b7ac Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 20 Feb 2013 13:28:37 -0500 Subject: [PATCH 01/10] Add in support for getting and displaying ETA --- .../open_ended_grading/open_ended_grading_util.py | 12 ++++++++++++ lms/djangoapps/open_ended_grading/views.py | 13 +++++++++++++ .../open_ended_problems/open_ended_problems.html | 6 +++++- 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 lms/djangoapps/open_ended_grading/open_ended_grading_util.py diff --git a/lms/djangoapps/open_ended_grading/open_ended_grading_util.py b/lms/djangoapps/open_ended_grading/open_ended_grading_util.py new file mode 100644 index 0000000000..f3871feec5 --- /dev/null +++ b/lms/djangoapps/open_ended_grading/open_ended_grading_util.py @@ -0,0 +1,12 @@ +def convert_seconds_to_human_readable(seconds): + if seconds < 60: + human_string = "{0} seconds".format(seconds) + elif seconds < 60 * 60: + human_string = "{0} minutes".format(round(seconds/60,1)) + elif seconds < (24*60*60): + human_string = "{0} hours".format(round(seconds/(60*60),1)) + else: + human_string = "{0} days".format(round(seconds/(60*60*24),1)) + + eta_string = "In {0}.".format(human_string) + return eta_string \ No newline at end of file diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index 77c1cda6bc..b19b526b0f 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -22,6 +22,7 @@ from xmodule.modulestore.django import modulestore from xmodule.modulestore import search from django.http import HttpResponse, Http404, HttpResponseRedirect +import open_ended_grading_util log = logging.getLogger(__name__) @@ -150,6 +151,18 @@ def student_problem_list(request, course_id): problem_url_parts = search.path_to_location(modulestore(), course.id, problem_list[i]['location']) problem_url = generate_problem_url(problem_url_parts, base_course_url) problem_list[i].update({'actual_url': problem_url}) + eta_available = problem_list[i]['eta_available'] + if isinstance(eta_available, basestring): + eta_available = (eta_available.lower() == "true") + + eta_string = "N/A" + if eta_available: + try: + eta_string = open_ended_grading_util.convert_seconds_to_human_readable(int(problem_list[i]['eta'])) + except: + #This is a student_facing_error + eta_string = "Error getting ETA." + problem_list[i].update({'eta_string' : eta_string}) except GradingServiceError: #This is a student_facing_error diff --git a/lms/templates/open_ended_problems/open_ended_problems.html b/lms/templates/open_ended_problems/open_ended_problems.html index 07d379fe32..3709fb2de6 100644 --- a/lms/templates/open_ended_problems/open_ended_problems.html +++ b/lms/templates/open_ended_problems/open_ended_problems.html @@ -27,7 +27,8 @@ Problem Name Status - Type of Grading + Grader Type + ETA %for problem in problem_list: @@ -40,6 +41,9 @@ ${problem['grader_type']} + + ${problem['eta_string']} + %endfor From 3db3d7b74080635a7475a9fc556e5c8577f58aa2 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 20 Feb 2013 13:31:06 -0500 Subject: [PATCH 02/10] Fix eta message slightly --- lms/djangoapps/open_ended_grading/open_ended_grading_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/djangoapps/open_ended_grading/open_ended_grading_util.py b/lms/djangoapps/open_ended_grading/open_ended_grading_util.py index f3871feec5..1826ecaedb 100644 --- a/lms/djangoapps/open_ended_grading/open_ended_grading_util.py +++ b/lms/djangoapps/open_ended_grading/open_ended_grading_util.py @@ -8,5 +8,5 @@ def convert_seconds_to_human_readable(seconds): else: human_string = "{0} days".format(round(seconds/(60*60*24),1)) - eta_string = "In {0}.".format(human_string) + eta_string = "{0}".format(human_string) return eta_string \ No newline at end of file From 59b2f2ccd7d22dbd35699f14f0227d9ff413cbe9 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 20 Feb 2013 16:19:17 -0500 Subject: [PATCH 03/10] Move controller query service to xmodule side to prepare for ETA message displays --- .../controller_query_service.py | 19 ++++++++++++++++--- .../openendedchild.py | 13 +++++++++++++ .../open_ended_grading_util.py | 12 ------------ .../open_ended_notifications.py | 5 +++-- lms/djangoapps/open_ended_grading/views.py | 9 +++++---- 5 files changed, 37 insertions(+), 21 deletions(-) rename {lms/djangoapps/open_ended_grading => common/lib/xmodule/xmodule/open_ended_grading_classes}/controller_query_service.py (81%) delete mode 100644 lms/djangoapps/open_ended_grading/open_ended_grading_util.py diff --git a/lms/djangoapps/open_ended_grading/controller_query_service.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/controller_query_service.py similarity index 81% rename from lms/djangoapps/open_ended_grading/controller_query_service.py rename to common/lib/xmodule/xmodule/open_ended_grading_classes/controller_query_service.py index 1b124fc116..6e08971d9d 100644 --- a/lms/djangoapps/open_ended_grading/controller_query_service.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/controller_query_service.py @@ -1,7 +1,6 @@ import logging from xmodule.open_ended_grading_classes.grading_service_module import GradingService -from xmodule.x_module import ModuleSystem from mitxmako.shortcuts import render_to_string log = logging.getLogger(__name__) @@ -11,8 +10,9 @@ class ControllerQueryService(GradingService): """ Interface to staff grading backend. """ - def __init__(self, config): - config['system'] = ModuleSystem(None, None, None, render_to_string, None) + def __init__(self, config, system): + config['system'] = system + #ModuleSystem(None, None, None, render_to_string, None) super(ControllerQueryService, self).__init__(config) self.url = config['url'] + config['grading_controller'] self.login_url = self.url + '/login/' @@ -77,3 +77,16 @@ class ControllerQueryService(GradingService): response = self.post(self.take_action_on_flags_url, params) return response + +def convert_seconds_to_human_readable(seconds): + if seconds < 60: + human_string = "{0} seconds".format(seconds) + elif seconds < 60 * 60: + human_string = "{0} minutes".format(round(seconds/60,1)) + elif seconds < (24*60*60): + human_string = "{0} hours".format(round(seconds/(60*60),1)) + else: + human_string = "{0} days".format(round(seconds/(60*60*24),1)) + + eta_string = "{0}".format(human_string) + return eta_string diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py index dd8fa2a54e..6b7954e198 100644 --- a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py @@ -23,6 +23,7 @@ from xmodule.xml_module import XmlDescriptor from xmodule.modulestore import Location from capa.util import * from peer_grading_service import PeerGradingService +import controller_query_service from datetime import datetime @@ -106,8 +107,10 @@ class OpenEndedChild(object): # completion (doesn't matter if you self-assessed correct/incorrect). self._max_score = static_data['max_score'] self.peer_gs = PeerGradingService(system.open_ended_grading_interface, system) + self.controller_qs = controller_query_service.ControllerQueryService(system.open_ended_grading_interface,system) self.system = system + self.location = location self.setup_response(system, location, definition, descriptor) def setup_response(self, system, location, definition, descriptor): @@ -446,3 +449,13 @@ class OpenEndedChild(object): error_message = error_string.format(count_required-count_graded, count_graded, count_required, student_sub_count) return success, allowed_to_submit, error_message + def get_eta(self): + response = self.controller_qs.check_for_eta(self.location.url()) + try: + response = json.loads(response) + except: + pass + + + + diff --git a/lms/djangoapps/open_ended_grading/open_ended_grading_util.py b/lms/djangoapps/open_ended_grading/open_ended_grading_util.py deleted file mode 100644 index 1826ecaedb..0000000000 --- a/lms/djangoapps/open_ended_grading/open_ended_grading_util.py +++ /dev/null @@ -1,12 +0,0 @@ -def convert_seconds_to_human_readable(seconds): - if seconds < 60: - human_string = "{0} seconds".format(seconds) - elif seconds < 60 * 60: - human_string = "{0} minutes".format(round(seconds/60,1)) - elif seconds < (24*60*60): - human_string = "{0} hours".format(round(seconds/(60*60),1)) - else: - human_string = "{0} days".format(round(seconds/(60*60*24),1)) - - eta_string = "{0}".format(human_string) - return eta_string \ No newline at end of file diff --git a/lms/djangoapps/open_ended_grading/open_ended_notifications.py b/lms/djangoapps/open_ended_grading/open_ended_notifications.py index c4054895d3..b4ca20079f 100644 --- a/lms/djangoapps/open_ended_grading/open_ended_notifications.py +++ b/lms/djangoapps/open_ended_grading/open_ended_notifications.py @@ -1,7 +1,7 @@ from django.conf import settings from xmodule.open_ended_grading_classes import peer_grading_service from staff_grading_service import StaffGradingService -from open_ended_grading.controller_query_service import ControllerQueryService +from xmodule.open_ended_grading_classes.controller_query_service import ControllerQueryService import json from student.models import unique_id_for_user from courseware.models import StudentModule @@ -93,7 +93,8 @@ def peer_grading_notifications(course, user): def combined_notifications(course, user): - controller_qs = ControllerQueryService(settings.OPEN_ENDED_GRADING_INTERFACE) + system = ModuleSystem(None, None, None, render_to_string, None) + controller_qs = ControllerQueryService(settings.OPEN_ENDED_GRADING_INTERFACE, system) student_id = unique_id_for_user(user) user_is_staff = has_access(user, course, 'staff') course_id = course.id diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index b19b526b0f..0cf498599d 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -11,7 +11,8 @@ from django.core.urlresolvers import reverse from student.models import unique_id_for_user from courseware.courses import get_course_with_access -from controller_query_service import ControllerQueryService +from xmodule.x_module import ModuleSystem +from xmodule.open_ended_grading_classes.controller_query_service import ControllerQueryService, convert_seconds_to_human_readable from xmodule.open_ended_grading_classes.grading_service_module import GradingServiceError import json from student.models import unique_id_for_user @@ -22,13 +23,13 @@ from xmodule.modulestore.django import modulestore from xmodule.modulestore import search from django.http import HttpResponse, Http404, HttpResponseRedirect -import open_ended_grading_util log = logging.getLogger(__name__) template_imports = {'urllib': urllib} -controller_qs = ControllerQueryService(settings.OPEN_ENDED_GRADING_INTERFACE) +system = ModuleSystem(None, None, None, render_to_string, None) +controller_qs = ControllerQueryService(settings.OPEN_ENDED_GRADING_INTERFACE, system) """ Reverses the URL from the name and the course id, and then adds a trailing slash if @@ -158,7 +159,7 @@ def student_problem_list(request, course_id): eta_string = "N/A" if eta_available: try: - eta_string = open_ended_grading_util.convert_seconds_to_human_readable(int(problem_list[i]['eta'])) + eta_string = convert_seconds_to_human_readable(int(problem_list[i]['eta'])) except: #This is a student_facing_error eta_string = "Error getting ETA." From 2f29d85efc2dc16e74d5e59d4b6bd7a559abc2ae Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 20 Feb 2013 16:22:22 -0500 Subject: [PATCH 04/10] Finish function to get eta value --- .../open_ended_grading_classes/openendedchild.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py index 6b7954e198..c79d57b650 100644 --- a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py @@ -456,6 +456,17 @@ class OpenEndedChild(object): except: pass - + success = response['success'] + if isinstance(success, basestring): + success = (success.lower()=="true") + + if success: + eta = controller_query_service.convert_seconds_to_human_readable(response['eta']) + eta_string = "Please check back for your response in approximately " + else: + eta_string = "" + + return eta_string + From 111ef30f05206e5186570e91e2fd717ed52fc9c9 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 20 Feb 2013 16:30:44 -0500 Subject: [PATCH 05/10] Render to string fix, display ETA message when student submits --- .../open_ended_grading_classes/open_ended_module.py | 5 +++++ lms/djangoapps/open_ended_grading/views.py | 1 + lms/templates/open_ended.html | 7 ++++++- 3 files changed, 12 insertions(+), 1 deletion(-) 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 96d75b366c..780194a41e 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 @@ -663,17 +663,21 @@ class OpenEndedModule(openendedchild.OpenEndedChild): Output: Rendered HTML """ #set context variables and render template + eta_string = None 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(system) score = self.latest_score() correct = 'correct' if self.is_submission_correct(score) else 'incorrect' + if self.state == self.ASSESSING: + eta_string = self.get_eta() else: post_assessment = "" correct = "" previous_answer = self.initial_display + context = { 'prompt': self.prompt, 'previous_answer': previous_answer, @@ -686,6 +690,7 @@ class OpenEndedModule(openendedchild.OpenEndedChild): 'child_type': 'openended', 'correct': correct, 'accept_file_upload': self.accept_file_upload, + 'eta_message' : eta_string, } html = system.render_template('open_ended.html', context) return html diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index 0cf498599d..76919d4103 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -23,6 +23,7 @@ from xmodule.modulestore.django import modulestore from xmodule.modulestore import search from django.http import HttpResponse, Http404, HttpResponseRedirect +from mitxmako.shortcuts import render_to_string log = logging.getLogger(__name__) diff --git a/lms/templates/open_ended.html b/lms/templates/open_ended.html index 64defedda4..9fb136cee6 100644 --- a/lms/templates/open_ended.html +++ b/lms/templates/open_ended.html @@ -15,7 +15,12 @@ % elif state in ['done', 'post_assessment'] and correct == 'incorrect':

Incorrect.

% elif state == 'assessing': - Submitted for grading. + Submitted for grading. + % if eta_message is not None: + ${eta_message} + % endif + + % endif % if hidden: From 26a2e059c823793ae35794bcabca876c68866d96 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 20 Feb 2013 16:36:40 -0500 Subject: [PATCH 06/10] Actually display ETA message --- .../xmodule/open_ended_grading_classes/openendedchild.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py index c79d57b650..7d97ec6d5f 100644 --- a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py @@ -462,7 +462,7 @@ class OpenEndedChild(object): if success: eta = controller_query_service.convert_seconds_to_human_readable(response['eta']) - eta_string = "Please check back for your response in approximately " + eta_string = "Please check back for your response in at most {0}.".format(eta) else: eta_string = "" From a8fadb0ecc7c624e70f8bd113f12b96b86913a6c Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 20 Feb 2013 17:16:38 -0500 Subject: [PATCH 07/10] Remove render to string import --- .../open_ended_grading_classes/controller_query_service.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/controller_query_service.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/controller_query_service.py index 6e08971d9d..929eda5228 100644 --- a/common/lib/xmodule/xmodule/open_ended_grading_classes/controller_query_service.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/controller_query_service.py @@ -1,8 +1,6 @@ import logging from xmodule.open_ended_grading_classes.grading_service_module import GradingService -from mitxmako.shortcuts import render_to_string - log = logging.getLogger(__name__) @@ -12,7 +10,6 @@ class ControllerQueryService(GradingService): """ def __init__(self, config, system): config['system'] = system - #ModuleSystem(None, None, None, render_to_string, None) super(ControllerQueryService, self).__init__(config) self.url = config['url'] + config['grading_controller'] self.login_url = self.url + '/login/' From 7b604aa0268157dce312879b0776d603768e47e6 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 20 Feb 2013 17:57:09 -0500 Subject: [PATCH 08/10] Fix an import statement --- .../open_ended_grading_classes/controller_query_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/controller_query_service.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/controller_query_service.py index 929eda5228..1dd5c57ad4 100644 --- a/common/lib/xmodule/xmodule/open_ended_grading_classes/controller_query_service.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/controller_query_service.py @@ -1,5 +1,5 @@ import logging -from xmodule.open_ended_grading_classes.grading_service_module import GradingService +from grading_service_module import GradingService log = logging.getLogger(__name__) From 9bc8dbd7ca3517dfb8ad8b5d8ada65ba0928e019 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 20 Feb 2013 18:04:25 -0500 Subject: [PATCH 09/10] Fix location strings, re-order checkboxes --- .../xmodule/open_ended_grading_classes/openendedchild.py | 6 +++--- lms/templates/peer_grading/peer_grading_problem.html | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py index 780f80a7a7..47a0980a83 100644 --- a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py @@ -437,14 +437,14 @@ class OpenEndedChild(object): error_string = ("You need to peer grade {0} more in order to make another submission. " "You have graded {1}, and {2} are required. You have made {3} successful peer grading submissions.") try: - response = self.peer_gs.get_data_for_location(location, student_id) + response = self.peer_gs.get_data_for_location(location_string, student_id) count_graded = response['count_graded'] count_required = response['count_required'] student_sub_count = response['student_sub_count'] success = True except: #This is a dev_facing_error - log.error("Could not contact external open ended graders for location {0} and student {1}".format(location,student_id)) + log.error("Could not contact external open ended graders for location {0} and student {1}".format(location_string,student_id)) #This is a student_facing_error error_message = "Could not contact the graders. Please notify course staff." return success, allowed_to_submit, error_message @@ -457,7 +457,7 @@ class OpenEndedChild(object): return success, allowed_to_submit, error_message def get_eta(self): - response = self.controller_qs.check_for_eta(self.location.url()) + response = self.controller_qs.check_for_eta(self.location_string) try: response = json.loads(response) except: diff --git a/lms/templates/peer_grading/peer_grading_problem.html b/lms/templates/peer_grading/peer_grading_problem.html index 853fa750e8..87559ec877 100644 --- a/lms/templates/peer_grading/peer_grading_problem.html +++ b/lms/templates/peer_grading/peer_grading_problem.html @@ -43,8 +43,8 @@

Please include some written feedback as well.

-

Flag this submission for review by course staff (use if the submission contains inappropriate content):

-

I do not know how to grade this question:

+
Flag this submission for review by course staff (use if the submission contains inappropriate content)
+
I do not know how to grade this question
From 9d5a08fc6d5e411b355a222931a420121f269791 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 20 Feb 2013 18:07:24 -0500 Subject: [PATCH 10/10] Fix location string --- .../xmodule/open_ended_grading_classes/openendedchild.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py index 47a0980a83..42f5dfa1d7 100644 --- a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py +++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py @@ -437,14 +437,14 @@ class OpenEndedChild(object): error_string = ("You need to peer grade {0} more in order to make another submission. " "You have graded {1}, and {2} are required. You have made {3} successful peer grading submissions.") try: - response = self.peer_gs.get_data_for_location(location_string, student_id) + response = self.peer_gs.get_data_for_location(self.location_string, student_id) count_graded = response['count_graded'] count_required = response['count_required'] student_sub_count = response['student_sub_count'] success = True except: #This is a dev_facing_error - log.error("Could not contact external open ended graders for location {0} and student {1}".format(location_string,student_id)) + log.error("Could not contact external open ended graders for location {0} and student {1}".format(self.location_string,student_id)) #This is a student_facing_error error_message = "Could not contact the graders. Please notify course staff." return success, allowed_to_submit, error_message