From 7b65f56121f5bc7627890a057d377d6073ecf8d3 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Thu, 17 Jan 2013 15:15:58 -0500 Subject: [PATCH 01/97] Add service to query controller for eta of submission and to check if name is unique --- .../controller_query_service.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 lms/djangoapps/open_ended_grading/controller_query_service.py diff --git a/lms/djangoapps/open_ended_grading/controller_query_service.py b/lms/djangoapps/open_ended_grading/controller_query_service.py new file mode 100644 index 0000000000..608e37ea09 --- /dev/null +++ b/lms/djangoapps/open_ended_grading/controller_query_service.py @@ -0,0 +1,37 @@ +import json +import logging +import requests +from requests.exceptions import RequestException, ConnectionError, HTTPError +import sys +from grading_service import GradingService +from grading_service import GradingServiceError + +from django.conf import settings +from django.http import HttpResponse, Http404 + +log = logging.getLogger(__name__) + +class ControllerQueryService(GradingService): + """ + Interface to staff grading backend. + """ + def __init__(self, config): + super(ControllerQuery, self).__init__(config) + self.check_eta_url = self.url + '/get_submission_eta/' + self.is_unique_url = self.url + '/is_name_unique/' + + def check_if_name_is_unique(self, location, problem_id, course_id): + params = { + 'course_id': course_id, + 'location' : location, + 'problem_id' : problem_id + } + response = self.get(self.is_unique_url, params) + return response + + def check_for_eta(self, location): + params = { + 'location' : location, + } + response = self.get(self.check_eta_url, params) + return response From 43783e4ff07c9a2ff9f9a11b92515d49e66abcb2 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Thu, 17 Jan 2013 15:18:39 -0500 Subject: [PATCH 02/97] Add in an item to check for combined notifications --- .../open_ended_grading/controller_query_service.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lms/djangoapps/open_ended_grading/controller_query_service.py b/lms/djangoapps/open_ended_grading/controller_query_service.py index 608e37ea09..7ab8712c71 100644 --- a/lms/djangoapps/open_ended_grading/controller_query_service.py +++ b/lms/djangoapps/open_ended_grading/controller_query_service.py @@ -19,6 +19,7 @@ class ControllerQueryService(GradingService): super(ControllerQuery, self).__init__(config) self.check_eta_url = self.url + '/get_submission_eta/' self.is_unique_url = self.url + '/is_name_unique/' + self.combined_notifications_url = self.url + '/combined_notifications/' def check_if_name_is_unique(self, location, problem_id, course_id): params = { @@ -35,3 +36,12 @@ class ControllerQueryService(GradingService): } response = self.get(self.check_eta_url, params) return response + + def check_combined_notifications(self, course_id, student_id): + params= { + 'student_id' : student_id, + 'course_id' : course_id, + } + response = self.get(self.combined_notifications_url,params) + return response + From c62ce7822e282ac4c34e9deb38d91ca3ecc9ab17 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Thu, 17 Jan 2013 16:16:13 -0500 Subject: [PATCH 03/97] Add in service support for getting the grading status list --- .../open_ended_grading/controller_query_service.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lms/djangoapps/open_ended_grading/controller_query_service.py b/lms/djangoapps/open_ended_grading/controller_query_service.py index 7ab8712c71..220bc276db 100644 --- a/lms/djangoapps/open_ended_grading/controller_query_service.py +++ b/lms/djangoapps/open_ended_grading/controller_query_service.py @@ -20,6 +20,7 @@ class ControllerQueryService(GradingService): self.check_eta_url = self.url + '/get_submission_eta/' self.is_unique_url = self.url + '/is_name_unique/' self.combined_notifications_url = self.url + '/combined_notifications/' + self.grading_status_list_url = self.url + '/get_grading_status_list/' def check_if_name_is_unique(self, location, problem_id, course_id): params = { @@ -37,11 +38,20 @@ class ControllerQueryService(GradingService): response = self.get(self.check_eta_url, params) return response - def check_combined_notifications(self, course_id, student_id): + def check_combined_notifications(self, course_id, student_id, user_is_staff, last_time_viewed): params= { 'student_id' : student_id, 'course_id' : course_id, + 'user_is_staff' : user_is_staff, + 'last_time_viewed' : last_time_viewed, } response = self.get(self.combined_notifications_url,params) return response + def get_grading_status_list(self, course_id, student_id): + params = { + 'student_id' : student_id, + 'course_id' : course_id, + } + + response = self.get(self.grading_status_list_url, params) From d28228639ec86b7733ec23057fa78a04eca3c28b Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Thu, 17 Jan 2013 16:58:35 -0500 Subject: [PATCH 04/97] Add in controller query stuff --- lms/djangoapps/courseware/tabs.py | 75 ++++++++++++++++------ lms/djangoapps/open_ended_grading/views.py | 40 ++++++++++++ 2 files changed, 95 insertions(+), 20 deletions(-) diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index 2ece7f0404..fe37dcde39 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -18,20 +18,12 @@ from django.core.urlresolvers import reverse from fs.errors import ResourceNotFoundError -from lxml.html import rewrite_links - -from module_render import get_module from courseware.access import has_access from static_replace import replace_urls -from xmodule.modulestore import Location -from xmodule.modulestore.django import modulestore -from xmodule.modulestore.xml import XMLModuleStore -from xmodule.x_module import XModule - - from open_ended_grading.peer_grading_service import PeerGradingService from open_ended_grading.staff_grading_service import StaffGradingService +from open_ended_grading.controller_query_service import ControllerQueryService from student.models import unique_id_for_user log = logging.getLogger(__name__) @@ -161,6 +153,38 @@ def _peer_grading(tab, user, course, active_page): return tab return [] +def _combined_open_ended_grading(tab, user, course, active_page): + if user.is_authenticated: + link = reverse('peer_grading', args=[course.id]) + peer_grading_url = settings.PEER_GRADING_INTERFACE + split_url = peer_grading_url.split("/") + controller_url = "http://" + split_url[2] + "/grading_controller" + log.debug(controller_url) + peer_gs = ControllerQueryService(controller_url) + student_id = unique_id_for_user(user) + course_id = course.id + user_is_staff = has_access(user, course, 'staff') + last_time_viewed = 1 + pending_grading= False + tab_name = "Peer grading" + img_path= "" + try: + notifications = json.loads(peer_gs.get_notifications(course.id,)) + if notifications['success']: + if notifications['student_needs_to_peer_grade']: + pending_grading=True + except: + #Non catastrophic error, so no real action + log.info("Problem with getting notifications from peer grading service.") + + if pending_grading: + img_path = "/static/images/slider-handle.png" + + tab = [CourseTab(tab_name, link, active_page == "peer_grading", pending_grading, img_path)] + return tab + return [] + + #### Validators @@ -314,16 +338,27 @@ def get_static_tab_by_slug(course, tab_slug): return None -def get_static_tab_contents(request, cache, course, tab): - loc = Location(course.location.tag, course.location.org, course.location.course, 'static_tab', tab['url_slug']) - tab_module = get_module(request.user, request, loc, cache, course.id) +def get_static_tab_contents(course, tab): + """ + Given a course and a static tab config dict, load the tab contents, + returning None if not found. - logging.debug('course_module = {0}'.format(tab_module)) - - html = '' - - if tab_module is not None: - html = tab_module.get_html() - - return html + Looks in tabs/{course_url_name}/{tab_slug}.html first, then tabs/{tab_slug}.html. + """ + slug = tab['url_slug'] + paths = ['tabs/{0}/{1}.html'.format(course.url_name, slug), + 'tabs/{0}.html'.format(slug)] + fs = course.system.resources_fs + for p in paths: + if fs.exists(p): + try: + with fs.open(p) as tabfile: + # TODO: redundant with module_render.py. Want to be helper methods in static_replace or something. + text = tabfile.read().decode('utf-8') + contents = replace_urls(text, course.metadata['data_dir']) + return replace_urls(contents, staticfiles_prefix='/courses/'+course.id, replace_prefix='/course/') + except (ResourceNotFoundError) as err: + log.exception("Couldn't load tab contents from '{0}': {1}".format(p, err)) + return None + return None diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index 858c9a4fd5..c92ce21e21 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -114,5 +114,45 @@ def peer_grading_problem(request, course_id): 'ajax_url': ajax_url, # Checked above 'staff_access': False, }) + +@cache_control(no_cache=True, no_store=True, must_revalidate=True) +def student_problem_list(request, course_id, student_id): + ''' + Show a student problem list + ''' + course = get_course_with_access(request.user, course_id, 'load') + + # call problem list service + success = False + error_text = "" + problem_list = [] + try: + problem_list_json = peer_gs.get_problem_list(course_id, unique_id_for_user(request.user)) + problem_list_dict = json.loads(problem_list_json) + success = problem_list_dict['success'] + if 'error' in problem_list_dict: + error_text = problem_list_dict['error'] + + problem_list = problem_list_dict['problem_list'] + + except GradingServiceError: + error_text = "Error occured while contacting the grading service" + success = False + # catch error if if the json loads fails + except ValueError: + error_text = "Could not get problem list" + success = False + + ajax_url = _reverse_with_slash('peer_grading', course_id) + + return render_to_response('peer_grading/peer_grading.html', { + 'course': course, + 'course_id': course_id, + 'ajax_url': ajax_url, + 'success': success, + 'problem_list': problem_list, + 'error_text': error_text, + # Checked above + 'staff_access': False, }) From 5e63a4690be87a50ed5c6678faa578b18c4396de Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 10:18:04 -0500 Subject: [PATCH 05/97] Work on getting combined notifications --- lms/djangoapps/courseware/tabs.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index fe37dcde39..90c7687142 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -25,6 +25,8 @@ from open_ended_grading.peer_grading_service import PeerGradingService from open_ended_grading.staff_grading_service import StaffGradingService from open_ended_grading.controller_query_service import ControllerQueryService from student.models import unique_id_for_user +from models import StudentModule +import datetime log = logging.getLogger(__name__) @@ -160,27 +162,31 @@ def _combined_open_ended_grading(tab, user, course, active_page): split_url = peer_grading_url.split("/") controller_url = "http://" + split_url[2] + "/grading_controller" log.debug(controller_url) - peer_gs = ControllerQueryService(controller_url) + controller_qs = ControllerQueryService(controller_url) student_id = unique_id_for_user(user) course_id = course.id user_is_staff = has_access(user, course, 'staff') - last_time_viewed = 1 + + min_time_to_query = user.last_login + last_module_seen = StudentModule.objects.all(student=user, course_id = course_id, modified>min_time_to_query).values('modified').order_by('-modified')[0] + + last_time_viewed = last_module_seen['modified'] pending_grading= False - tab_name = "Peer grading" + tab_name = "Open Ended Questions" img_path= "" try: - notifications = json.loads(peer_gs.get_notifications(course.id,)) + notifications = json.loads(controller_qs.get_notifications(course.id,student_id, user_is_staff, last_time_viewed)) if notifications['success']: if notifications['student_needs_to_peer_grade']: pending_grading=True except: #Non catastrophic error, so no real action - log.info("Problem with getting notifications from peer grading service.") + log.info("Problem with getting notifications from controller query service.") if pending_grading: img_path = "/static/images/slider-handle.png" - tab = [CourseTab(tab_name, link, active_page == "peer_grading", pending_grading, img_path)] + tab = [CourseTab(tab_name, link, active_page == "controller_query", pending_grading, img_path)] return tab return [] From fe77bb00c411c88597ba5c9ea13e94b557487447 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 10:19:34 -0500 Subject: [PATCH 06/97] Fix naming for overall need to check --- lms/djangoapps/courseware/tabs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index 90c7687142..1850ae3faf 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -177,7 +177,7 @@ def _combined_open_ended_grading(tab, user, course, active_page): try: notifications = json.loads(controller_qs.get_notifications(course.id,student_id, user_is_staff, last_time_viewed)) if notifications['success']: - if notifications['student_needs_to_peer_grade']: + if notifications['overall_need_to_check']: pending_grading=True except: #Non catastrophic error, so no real action From 2191f3e228548119ca624ffb13870c0a3d14123a Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 10:30:03 -0500 Subject: [PATCH 07/97] Add in open ended problems view --- lms/djangoapps/courseware/tabs.py | 2 +- lms/djangoapps/open_ended_grading/views.py | 9 +++-- .../open_ended_problems.html | 36 +++++++++++++++++++ lms/urls.py | 6 +++- 4 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 lms/templates/open_ended_problems/open_ended_problems.html diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index 1850ae3faf..80c353c748 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -157,7 +157,7 @@ def _peer_grading(tab, user, course, active_page): def _combined_open_ended_grading(tab, user, course, active_page): if user.is_authenticated: - link = reverse('peer_grading', args=[course.id]) + link = reverse('open_ended_problems', args=[course.id]) peer_grading_url = settings.PEER_GRADING_INTERFACE split_url = peer_grading_url.split("/") controller_url = "http://" + split_url[2] + "/grading_controller" diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index c92ce21e21..471e00f5f0 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -13,6 +13,7 @@ from courseware.courses import get_course_with_access from peer_grading_service import PeerGradingService from peer_grading_service import MockPeerGradingService +from controller_query_service import ControllerQueryService from grading_service import GradingServiceError import json from .staff_grading import StaffGrading @@ -26,6 +27,8 @@ if settings.MOCK_PEER_GRADING: else: peer_gs = PeerGradingService(settings.PEER_GRADING_INTERFACE) +controller_qs = ControllerQueryService(settings.PEER_GRADING_INTERFACE) + """ Reverses the URL from the name and the course id, and then adds a trailing slash if it does not exist yet @@ -127,7 +130,7 @@ def student_problem_list(request, course_id, student_id): error_text = "" problem_list = [] try: - problem_list_json = peer_gs.get_problem_list(course_id, unique_id_for_user(request.user)) + problem_list_json = controller_qs.get_grading_status_list(course_id, unique_id_for_user(request.user)) problem_list_dict = json.loads(problem_list_json) success = problem_list_dict['success'] if 'error' in problem_list_dict: @@ -143,9 +146,9 @@ def student_problem_list(request, course_id, student_id): error_text = "Could not get problem list" success = False - ajax_url = _reverse_with_slash('peer_grading', course_id) + ajax_url = _reverse_with_slash('open_ended_problems', course_id) - return render_to_response('peer_grading/peer_grading.html', { + return render_to_response('open_ended_problems/open_ended_problems.html', { 'course': course, 'course_id': course_id, 'ajax_url': ajax_url, diff --git a/lms/templates/open_ended_problems/open_ended_problems.html b/lms/templates/open_ended_problems/open_ended_problems.html new file mode 100644 index 0000000000..ec648afab8 --- /dev/null +++ b/lms/templates/open_ended_problems/open_ended_problems.html @@ -0,0 +1,36 @@ +<%inherit file="/main.html" /> +<%block name="bodyclass">${course.css_class} +<%namespace name='static' file='/static_content.html'/> + +<%block name="headextra"> +<%static:css group='course'/> + + +<%block name="title">${course.number} Open Ended Problems + +<%include file="/courseware/course_navigation.html" args="active_page='open_ended_problems'" /> + + +
+
+
${error_text}
+

Open Ended Problems

+

Instructions

+

Here are a list of open ended problems for this course.

+ % if success: + % if len(problem_list) == 0: +
+ You have not attempted any open ended problems yet. +
+ %else: + + %endif + %endif +
+
\ No newline at end of file diff --git a/lms/urls.py b/lms/urls.py index f92b63aac2..c7c4f231f9 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -282,7 +282,11 @@ if settings.COURSEWARE_ENABLED: url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/peer_grading/save_calibration_essay$', 'open_ended_grading.peer_grading_service.save_calibration_essay', name='peer_grading_save_calibration_essay'), - # Cohorts management + # Open Ended problem list + url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/open_ended_problems$', + 'open_ended_grading.views.student_problem_list', name='open_ended_problems'), + + # Cohorts management url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/cohorts$', 'course_groups.views.list_cohorts', name="cohorts"), url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/cohorts/add$', From b0599ea133d00bdff3b54975258d786620dd746f Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 10:34:48 -0500 Subject: [PATCH 08/97] Fix queries and some controller query stuff --- lms/djangoapps/courseware/tabs.py | 2 +- lms/djangoapps/open_ended_grading/controller_query_service.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index 80c353c748..75bb61b59a 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -168,7 +168,7 @@ def _combined_open_ended_grading(tab, user, course, active_page): user_is_staff = has_access(user, course, 'staff') min_time_to_query = user.last_login - last_module_seen = StudentModule.objects.all(student=user, course_id = course_id, modified>min_time_to_query).values('modified').order_by('-modified')[0] + last_module_seen = StudentModule.objects.all(student=user, course_id = course_id, modified__gt=min_time_to_query).values('modified').order_by('-modified')[0] last_time_viewed = last_module_seen['modified'] pending_grading= False diff --git a/lms/djangoapps/open_ended_grading/controller_query_service.py b/lms/djangoapps/open_ended_grading/controller_query_service.py index 220bc276db..649f65dfac 100644 --- a/lms/djangoapps/open_ended_grading/controller_query_service.py +++ b/lms/djangoapps/open_ended_grading/controller_query_service.py @@ -16,7 +16,7 @@ class ControllerQueryService(GradingService): Interface to staff grading backend. """ def __init__(self, config): - super(ControllerQuery, self).__init__(config) + super(ControllerQueryService, self).__init__(config) self.check_eta_url = self.url + '/get_submission_eta/' self.is_unique_url = self.url + '/is_name_unique/' self.combined_notifications_url = self.url + '/combined_notifications/' From e6dd07a41e3b2b31c9317ab5b22445db605781f2 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 10:39:49 -0500 Subject: [PATCH 09/97] Fix parameter passing --- lms/djangoapps/open_ended_grading/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index 471e00f5f0..27be3d0939 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -17,6 +17,7 @@ from controller_query_service import ControllerQueryService from grading_service import GradingServiceError import json from .staff_grading import StaffGrading +from student.models import unique_id_for_user log = logging.getLogger(__name__) @@ -119,11 +120,12 @@ def peer_grading_problem(request, course_id): 'staff_access': False, }) @cache_control(no_cache=True, no_store=True, must_revalidate=True) -def student_problem_list(request, course_id, student_id): +def student_problem_list(request, course_id): ''' Show a student problem list ''' course = get_course_with_access(request.user, course_id, 'load') + student_id = unique_id_for_user(request.user) # call problem list service success = False From 693337593e928c2bb8d52d42b7691908b4f4b9e5 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 10:43:08 -0500 Subject: [PATCH 10/97] Properly parse url for grading controller --- lms/djangoapps/courseware/tabs.py | 7 +++---- lms/djangoapps/open_ended_grading/open_ended_util.py | 7 +++++++ lms/djangoapps/open_ended_grading/views.py | 5 ++++- 3 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 lms/djangoapps/open_ended_grading/open_ended_util.py diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index 75bb61b59a..01742092aa 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -24,6 +24,7 @@ from static_replace import replace_urls from open_ended_grading.peer_grading_service import PeerGradingService from open_ended_grading.staff_grading_service import StaffGradingService from open_ended_grading.controller_query_service import ControllerQueryService +from open_ended_grading import open_ended_util from student.models import unique_id_for_user from models import StudentModule import datetime @@ -158,10 +159,8 @@ def _peer_grading(tab, user, course, active_page): def _combined_open_ended_grading(tab, user, course, active_page): if user.is_authenticated: link = reverse('open_ended_problems', args=[course.id]) - peer_grading_url = settings.PEER_GRADING_INTERFACE - split_url = peer_grading_url.split("/") - controller_url = "http://" + split_url[2] + "/grading_controller" - log.debug(controller_url) + + controller_url = open_ended_util.get_controller_url() controller_qs = ControllerQueryService(controller_url) student_id = unique_id_for_user(user) course_id = course.id diff --git a/lms/djangoapps/open_ended_grading/open_ended_util.py b/lms/djangoapps/open_ended_grading/open_ended_util.py new file mode 100644 index 0000000000..b50cf3afb2 --- /dev/null +++ b/lms/djangoapps/open_ended_grading/open_ended_util.py @@ -0,0 +1,7 @@ +from django.conf import settings + +def get_controller_url(): + peer_grading_url = settings.PEER_GRADING_INTERFACE + split_url = peer_grading_url.split("/") + controller_url = "http://" + split_url[2] + "/grading_controller" + return controller_url diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index 27be3d0939..3928fb7b85 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -19,6 +19,8 @@ import json from .staff_grading import StaffGrading from student.models import unique_id_for_user +import open_ended_util + log = logging.getLogger(__name__) @@ -28,7 +30,8 @@ if settings.MOCK_PEER_GRADING: else: peer_gs = PeerGradingService(settings.PEER_GRADING_INTERFACE) -controller_qs = ControllerQueryService(settings.PEER_GRADING_INTERFACE) +controller_url = open_ended_util.get_controller_url() +controller_qs = ControllerQueryService(controller_url) """ Reverses the URL from the name and the course id, and then adds a trailing slash if From f4574c75db61af0db9a99d571b7569ad11a60d4e Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 10:54:14 -0500 Subject: [PATCH 11/97] Proper config dictionary generation for controller query --- lms/djangoapps/open_ended_grading/open_ended_util.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lms/djangoapps/open_ended_grading/open_ended_util.py b/lms/djangoapps/open_ended_grading/open_ended_util.py index b50cf3afb2..772e3cd08e 100644 --- a/lms/djangoapps/open_ended_grading/open_ended_util.py +++ b/lms/djangoapps/open_ended_grading/open_ended_util.py @@ -1,7 +1,12 @@ from django.conf import settings +import logging + +log=logging.getLogger(__name__) def get_controller_url(): - peer_grading_url = settings.PEER_GRADING_INTERFACE + peer_grading_url = settings.PEER_GRADING_INTERFACE['url'] split_url = peer_grading_url.split("/") controller_url = "http://" + split_url[2] + "/grading_controller" - return controller_url + controller_settings=settings.PEER_GRADING_INTERFACE + controller_settings['url'] = controller_url + return controller_settings From 61d62f274e526fe6a366312dc2b90285fd4a4c8b Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 10:57:20 -0500 Subject: [PATCH 12/97] Fix issue with parsing of open ended list --- lms/djangoapps/open_ended_grading/controller_query_service.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lms/djangoapps/open_ended_grading/controller_query_service.py b/lms/djangoapps/open_ended_grading/controller_query_service.py index 649f65dfac..a111cfe58d 100644 --- a/lms/djangoapps/open_ended_grading/controller_query_service.py +++ b/lms/djangoapps/open_ended_grading/controller_query_service.py @@ -55,3 +55,4 @@ class ControllerQueryService(GradingService): } response = self.get(self.grading_status_list_url, params) + return response From 68db8b0d77f906994108a5c876260e26867b74e7 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 11:46:46 -0500 Subject: [PATCH 13/97] Refactor tab logic, start adding in combined notifications view --- lms/djangoapps/courseware/tabs.py | 64 ++--------------- .../open_ended_notifications.py | 72 +++++++++++++++++++ lms/djangoapps/open_ended_grading/views.py | 4 +- .../combined_notifications.html | 41 +++++++++++ 4 files changed, 121 insertions(+), 60 deletions(-) create mode 100644 lms/djangoapps/open_ended_grading/open_ended_notifications.py create mode 100644 lms/templates/open_ended_problems/combined_notifications.html diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index 01742092aa..326c1a5cbd 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -21,13 +21,7 @@ from fs.errors import ResourceNotFoundError from courseware.access import has_access from static_replace import replace_urls -from open_ended_grading.peer_grading_service import PeerGradingService -from open_ended_grading.staff_grading_service import StaffGradingService -from open_ended_grading.controller_query_service import ControllerQueryService -from open_ended_grading import open_ended_util -from student.models import unique_id_for_user -from models import StudentModule -import datetime +from open_ended_grading import open_ended_notifications log = logging.getLogger(__name__) @@ -113,21 +107,8 @@ def _textbooks(tab, user, course, active_page): def _staff_grading(tab, user, course, active_page): if has_access(user, course, 'staff'): link = reverse('staff_grading', args=[course.id]) - staff_gs = StaffGradingService(settings.STAFF_GRADING_INTERFACE) - pending_grading=False tab_name = "Staff grading" - img_path= "" - try: - notifications = json.loads(staff_gs.get_notifications(course.id)) - if notifications['success']: - if notifications['staff_needs_to_grade']: - pending_grading=True - except: - #Non catastrophic error, so no real action - log.info("Problem with getting notifications from staff grading service.") - - if pending_grading: - img_path = "/static/images/slider-handle.png" + pending_grading, img_path = open_ended_notifications.staff_grading_notifications(course) tab = [CourseTab(tab_name, link, active_page == "staff_grading", pending_grading, img_path)] return tab @@ -136,21 +117,8 @@ def _staff_grading(tab, user, course, active_page): def _peer_grading(tab, user, course, active_page): if user.is_authenticated(): link = reverse('peer_grading', args=[course.id]) - peer_gs = PeerGradingService(settings.PEER_GRADING_INTERFACE) - pending_grading=False tab_name = "Peer grading" - img_path= "" - try: - notifications = json.loads(peer_gs.get_notifications(course.id,unique_id_for_user(user))) - if notifications['success']: - if notifications['student_needs_to_peer_grade']: - pending_grading=True - except: - #Non catastrophic error, so no real action - log.info("Problem with getting notifications from peer grading service.") - - if pending_grading: - img_path = "/static/images/slider-handle.png" + pending_grading, img_path = open_ended_notifications.peer_grading_notifications(course, user) tab = [CourseTab(tab_name, link, active_page == "peer_grading", pending_grading, img_path)] return tab @@ -159,31 +127,9 @@ def _peer_grading(tab, user, course, active_page): def _combined_open_ended_grading(tab, user, course, active_page): if user.is_authenticated: link = reverse('open_ended_problems', args=[course.id]) - - controller_url = open_ended_util.get_controller_url() - controller_qs = ControllerQueryService(controller_url) - student_id = unique_id_for_user(user) - course_id = course.id - user_is_staff = has_access(user, course, 'staff') - - min_time_to_query = user.last_login - last_module_seen = StudentModule.objects.all(student=user, course_id = course_id, modified__gt=min_time_to_query).values('modified').order_by('-modified')[0] - - last_time_viewed = last_module_seen['modified'] - pending_grading= False tab_name = "Open Ended Questions" - img_path= "" - try: - notifications = json.loads(controller_qs.get_notifications(course.id,student_id, user_is_staff, last_time_viewed)) - if notifications['success']: - if notifications['overall_need_to_check']: - pending_grading=True - except: - #Non catastrophic error, so no real action - log.info("Problem with getting notifications from controller query service.") - - if pending_grading: - img_path = "/static/images/slider-handle.png" + + pending_grading, img_path = open_ended_notifications.combined_notifications(course, user) tab = [CourseTab(tab_name, link, active_page == "controller_query", pending_grading, img_path)] return tab diff --git a/lms/djangoapps/open_ended_grading/open_ended_notifications.py b/lms/djangoapps/open_ended_grading/open_ended_notifications.py new file mode 100644 index 0000000000..68f1509891 --- /dev/null +++ b/lms/djangoapps/open_ended_grading/open_ended_notifications.py @@ -0,0 +1,72 @@ +from django.conf import settings +from staff_grading_service import StaffGradingService +from peer_grading_service import PeerGradingService +from open_ended_grading.controller_query_service import ControllerQueryService +import json +from student.models import unique_id_for_user +import open_ended_util +from courseware.models import StudentModule + +def staff_grading_notifications(course): + staff_gs = StaffGradingService(settings.STAFF_GRADING_INTERFACE) + pending_grading=False + img_path= "" + try: + notifications = json.loads(staff_gs.get_notifications(course.id)) + if notifications['success']: + if notifications['staff_needs_to_grade']: + pending_grading=True + except: + #Non catastrophic error, so no real action + log.info("Problem with getting notifications from staff grading service.") + + if pending_grading: + img_path = "/static/images/slider-handle.png" + + return pending_grading, img_path + +def peer_grading_notifications(course, user): + peer_gs = PeerGradingService(settings.PEER_GRADING_INTERFACE) + pending_grading=False + img_path= "" + try: + notifications = json.loads(peer_gs.get_notifications(course.id,unique_id_for_user(user))) + if notifications['success']: + if notifications['student_needs_to_peer_grade']: + pending_grading=True + except: + #Non catastrophic error, so no real action + log.info("Problem with getting notifications from peer grading service.") + + if pending_grading: + img_path = "/static/images/slider-handle.png" + + return pending_grading, img_path + +def combined_notifications(course, user): + controller_url = open_ended_util.get_controller_url() + controller_qs = ControllerQueryService(controller_url) + student_id = unique_id_for_user(user) + course_id = course.id + user_is_staff = has_access(user, course, 'staff') + + min_time_to_query = user.last_login + last_module_seen = StudentModule.objects.all(student=user, course_id = course_id, modified__gt=min_time_to_query).values('modified').order_by('-modified')[0] + + last_time_viewed = last_module_seen['modified'] + pending_grading= False + + img_path= "" + try: + notifications = json.loads(controller_qs.get_notifications(course.id,student_id, user_is_staff, last_time_viewed)) + if notifications['success']: + if notifications['overall_need_to_check']: + pending_grading=True + except: + #Non catastrophic error, so no real action + log.info("Problem with getting notifications from controller query service.") + + if pending_grading: + img_path = "/static/images/slider-handle.png" + + return pending_grading, img_path \ 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 3928fb7b85..3da1fb0835 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -21,7 +21,6 @@ from student.models import unique_id_for_user import open_ended_util - log = logging.getLogger(__name__) template_imports = {'urllib': urllib} @@ -162,5 +161,8 @@ def student_problem_list(request, course_id): 'error_text': error_text, # Checked above 'staff_access': False, }) + +def combined_notifications(request, course_id): + pass diff --git a/lms/templates/open_ended_problems/combined_notifications.html b/lms/templates/open_ended_problems/combined_notifications.html new file mode 100644 index 0000000000..6cd2a095dc --- /dev/null +++ b/lms/templates/open_ended_problems/combined_notifications.html @@ -0,0 +1,41 @@ +<%inherit file="/main.html" /> +<%block name="bodyclass">${course.css_class} +<%namespace name='static' file='/static_content.html'/> + +<%block name="headextra"> +<%static:css group='course'/> + + +<%block name="title">${course.number} Combined Notifications + +<%include file="/courseware/course_navigation.html" args="active_page='combined_notifications'" /> + + +
+
+
${error_text}
+

Open Ended Console

+

Instructions

+

Here are items that could potentially need your attention.

+ % if success: + % if len(item_list) == 0: +
+ No items require attention at the moment. +
+ %else: + + %endif + %endif +
+
\ No newline at end of file From 4112f8ad8e0949823863f3af1e016536fe0fbc66 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 11:53:46 -0500 Subject: [PATCH 14/97] Pass back dictionaries where needed from notifications functions --- lms/djangoapps/courseware/tabs.py | 16 ++++++++++++---- .../open_ended_notifications.py | 6 +++--- lms/djangoapps/open_ended_grading/views.py | 4 +++- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index 326c1a5cbd..dfe5cb14b9 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -108,7 +108,10 @@ def _staff_grading(tab, user, course, active_page): if has_access(user, course, 'staff'): link = reverse('staff_grading', args=[course.id]) tab_name = "Staff grading" - pending_grading, img_path = open_ended_notifications.staff_grading_notifications(course) + + notifications = open_ended_notifications.staff_grading_notifications(course) + pending_grading = notifications['pending_grading'] + img_path = notifications['img_path'] tab = [CourseTab(tab_name, link, active_page == "staff_grading", pending_grading, img_path)] return tab @@ -118,7 +121,10 @@ def _peer_grading(tab, user, course, active_page): if user.is_authenticated(): link = reverse('peer_grading', args=[course.id]) tab_name = "Peer grading" - pending_grading, img_path = open_ended_notifications.peer_grading_notifications(course, user) + + notifications = open_ended_notifications.peer_grading_notifications(course, user) + pending_grading = notifications['pending_grading'] + img_path = notifications['img_path'] tab = [CourseTab(tab_name, link, active_page == "peer_grading", pending_grading, img_path)] return tab @@ -128,8 +134,10 @@ def _combined_open_ended_grading(tab, user, course, active_page): if user.is_authenticated: link = reverse('open_ended_problems', args=[course.id]) tab_name = "Open Ended Questions" - - pending_grading, img_path = open_ended_notifications.combined_notifications(course, user) + + notifications = open_ended_notifications.combined_notifications(course, user) + pending_grading = notifications['pending_grading'] + img_path = notifications['img_path'] tab = [CourseTab(tab_name, link, active_page == "controller_query", pending_grading, img_path)] return tab diff --git a/lms/djangoapps/open_ended_grading/open_ended_notifications.py b/lms/djangoapps/open_ended_grading/open_ended_notifications.py index 68f1509891..d394769f1e 100644 --- a/lms/djangoapps/open_ended_grading/open_ended_notifications.py +++ b/lms/djangoapps/open_ended_grading/open_ended_notifications.py @@ -23,7 +23,7 @@ def staff_grading_notifications(course): if pending_grading: img_path = "/static/images/slider-handle.png" - return pending_grading, img_path + return {'pending_grading' : pending_grading, 'img_path' : img_path, 'response' : notifications} def peer_grading_notifications(course, user): peer_gs = PeerGradingService(settings.PEER_GRADING_INTERFACE) @@ -41,7 +41,7 @@ def peer_grading_notifications(course, user): if pending_grading: img_path = "/static/images/slider-handle.png" - return pending_grading, img_path + return {'pending_grading' : pending_grading, 'img_path' : img_path, 'response' : notifications} def combined_notifications(course, user): controller_url = open_ended_util.get_controller_url() @@ -69,4 +69,4 @@ def combined_notifications(course, user): if pending_grading: img_path = "/static/images/slider-handle.png" - return pending_grading, img_path \ No newline at end of file + return {'pending_grading' : pending_grading, 'img_path' : img_path, 'response' : notifications} \ 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 3da1fb0835..e6841ccbd3 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -20,6 +20,7 @@ from .staff_grading import StaffGrading from student.models import unique_id_for_user import open_ended_util +import open_ended_notifications log = logging.getLogger(__name__) @@ -163,6 +164,7 @@ def student_problem_list(request, course_id): 'staff_access': False, }) def combined_notifications(request, course_id): - pass + user = request.user + From 22a2bdaa3d735b175d312cf26e85f066239775dc Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 11:57:26 -0500 Subject: [PATCH 15/97] Disable student problem list caching, build out notifications --- lms/djangoapps/courseware/tabs.py | 8 ++++---- .../open_ended_grading/open_ended_notifications.py | 11 +++++------ lms/djangoapps/open_ended_grading/views.py | 3 +++ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index dfe5cb14b9..7a8367a42b 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -108,8 +108,8 @@ def _staff_grading(tab, user, course, active_page): if has_access(user, course, 'staff'): link = reverse('staff_grading', args=[course.id]) tab_name = "Staff grading" - - notifications = open_ended_notifications.staff_grading_notifications(course) + + notifications = open_ended_notifications.staff_grading_notifications(course_id) pending_grading = notifications['pending_grading'] img_path = notifications['img_path'] @@ -122,7 +122,7 @@ def _peer_grading(tab, user, course, active_page): link = reverse('peer_grading', args=[course.id]) tab_name = "Peer grading" - notifications = open_ended_notifications.peer_grading_notifications(course, user) + notifications = open_ended_notifications.peer_grading_notifications(course_id, user) pending_grading = notifications['pending_grading'] img_path = notifications['img_path'] @@ -135,7 +135,7 @@ def _combined_open_ended_grading(tab, user, course, active_page): link = reverse('open_ended_problems', args=[course.id]) tab_name = "Open Ended Questions" - notifications = open_ended_notifications.combined_notifications(course, user) + notifications = open_ended_notifications.combined_notifications(course_id, user) pending_grading = notifications['pending_grading'] img_path = notifications['img_path'] diff --git a/lms/djangoapps/open_ended_grading/open_ended_notifications.py b/lms/djangoapps/open_ended_grading/open_ended_notifications.py index d394769f1e..31b7a40dff 100644 --- a/lms/djangoapps/open_ended_grading/open_ended_notifications.py +++ b/lms/djangoapps/open_ended_grading/open_ended_notifications.py @@ -7,12 +7,12 @@ from student.models import unique_id_for_user import open_ended_util from courseware.models import StudentModule -def staff_grading_notifications(course): +def staff_grading_notifications(course_id): staff_gs = StaffGradingService(settings.STAFF_GRADING_INTERFACE) pending_grading=False img_path= "" try: - notifications = json.loads(staff_gs.get_notifications(course.id)) + notifications = json.loads(staff_gs.get_notifications(course_id)) if notifications['success']: if notifications['staff_needs_to_grade']: pending_grading=True @@ -25,12 +25,12 @@ def staff_grading_notifications(course): return {'pending_grading' : pending_grading, 'img_path' : img_path, 'response' : notifications} -def peer_grading_notifications(course, user): +def peer_grading_notifications(course_id, user): peer_gs = PeerGradingService(settings.PEER_GRADING_INTERFACE) pending_grading=False img_path= "" try: - notifications = json.loads(peer_gs.get_notifications(course.id,unique_id_for_user(user))) + notifications = json.loads(peer_gs.get_notifications(course_id,unique_id_for_user(user))) if notifications['success']: if notifications['student_needs_to_peer_grade']: pending_grading=True @@ -43,11 +43,10 @@ def peer_grading_notifications(course, user): return {'pending_grading' : pending_grading, 'img_path' : img_path, 'response' : notifications} -def combined_notifications(course, user): +def combined_notifications(course_id, user): controller_url = open_ended_util.get_controller_url() controller_qs = ControllerQueryService(controller_url) student_id = unique_id_for_user(user) - course_id = course.id user_is_staff = has_access(user, course, 'staff') min_time_to_query = user.last_login diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index e6841ccbd3..3797c2fbb2 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -163,8 +163,11 @@ def student_problem_list(request, course_id): # Checked above 'staff_access': False, }) +@cache_control(no_cache=True, no_store=True, must_revalidate=True) def combined_notifications(request, course_id): user = request.user + notifications = open_ended_notifications.combined_notifications(course_id, user) + response = notifications['response'] From 6b7ba3799993c2a8a48d78f6b39fccc4e303ae5b Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 12:09:34 -0500 Subject: [PATCH 16/97] Combined notification view --- .../open_ended_notifications.py | 6 +++++ lms/djangoapps/open_ended_grading/views.py | 25 +++++++++++++++++++ .../combined_notifications.html | 6 ++--- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/lms/djangoapps/open_ended_grading/open_ended_notifications.py b/lms/djangoapps/open_ended_grading/open_ended_notifications.py index 31b7a40dff..516b19e326 100644 --- a/lms/djangoapps/open_ended_grading/open_ended_notifications.py +++ b/lms/djangoapps/open_ended_grading/open_ended_notifications.py @@ -7,6 +7,12 @@ from student.models import unique_id_for_user import open_ended_util from courseware.models import StudentModule +NOTIFICATION_TYPES = ( + ('student_needs_to_peer_grade', 'peer_grading', 'Peer Grading'), + ('staff_needs_to_grade', 'staff_grading', 'Staff Grading'), + ('overall_need_to_check', 'open_ended_problems', 'Problems you have submitted') + ) + def staff_grading_notifications(course_id): staff_gs = StaffGradingService(settings.STAFF_GRADING_INTERFACE) pending_grading=False diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index 3797c2fbb2..a1907ae230 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -168,6 +168,31 @@ def combined_notifications(request, course_id): user = request.user notifications = open_ended_notifications.combined_notifications(course_id, user) response = notifications['response'] + notificaton_tuples=open_ended_notifications.NOTIFICATION_TYPES + notification_list = [] + for response_num in xrange(0,len(notification_tuples)): + tag=notification_tuples[response_num][0] + if tag in response: + url_name = notification_tuples[response_num][1] + human_name = notification_tuples[response_num][2] + url = _reverse_with_slash(url_name, course_id) + has_img = response[tag] + img_path = "/static/images/slider-handle.png" + + notification_item = { + 'url' : url, + 'name' : human_name, + 'has_img' : has_img, + 'img' : img_path, + } + notification_list.append(notification_item) + + combined_dict = { + 'error_text' : "", + 'notification_list' : notification_list, + } + + return combined_dict diff --git a/lms/templates/open_ended_problems/combined_notifications.html b/lms/templates/open_ended_problems/combined_notifications.html index 6cd2a095dc..9fdedb2555 100644 --- a/lms/templates/open_ended_problems/combined_notifications.html +++ b/lms/templates/open_ended_problems/combined_notifications.html @@ -18,7 +18,7 @@

Instructions

Here are items that could potentially need your attention.

% if success: - % if len(item_list) == 0: + % if len(notification_list) == 0:
No items require attention at the moment.
@@ -28,8 +28,8 @@
  • {notification['name']} - % if notification.has_img == True: - + % if notification['has_img'] == True: + %endif
  • From 0f212cc8f291847efa799c329dcc66dddac93b83 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 12:53:20 -0500 Subject: [PATCH 17/97] Fix course id passing, template rendering --- lms/djangoapps/courseware/tabs.py | 6 +++--- .../open_ended_notifications.py | 21 ++++++++++++++----- lms/djangoapps/open_ended_grading/views.py | 11 +++++++--- lms/urls.py | 5 ++++- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index 7a8367a42b..3aa502e95e 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -109,7 +109,7 @@ def _staff_grading(tab, user, course, active_page): link = reverse('staff_grading', args=[course.id]) tab_name = "Staff grading" - notifications = open_ended_notifications.staff_grading_notifications(course_id) + notifications = open_ended_notifications.staff_grading_notifications(course) pending_grading = notifications['pending_grading'] img_path = notifications['img_path'] @@ -122,7 +122,7 @@ def _peer_grading(tab, user, course, active_page): link = reverse('peer_grading', args=[course.id]) tab_name = "Peer grading" - notifications = open_ended_notifications.peer_grading_notifications(course_id, user) + notifications = open_ended_notifications.peer_grading_notifications(course, user) pending_grading = notifications['pending_grading'] img_path = notifications['img_path'] @@ -135,7 +135,7 @@ def _combined_open_ended_grading(tab, user, course, active_page): link = reverse('open_ended_problems', args=[course.id]) tab_name = "Open Ended Questions" - notifications = open_ended_notifications.combined_notifications(course_id, user) + notifications = open_ended_notifications.combined_notifications(course, user) pending_grading = notifications['pending_grading'] img_path = notifications['img_path'] diff --git a/lms/djangoapps/open_ended_grading/open_ended_notifications.py b/lms/djangoapps/open_ended_grading/open_ended_notifications.py index 516b19e326..9ab75833ca 100644 --- a/lms/djangoapps/open_ended_grading/open_ended_notifications.py +++ b/lms/djangoapps/open_ended_grading/open_ended_notifications.py @@ -6,6 +6,10 @@ import json from student.models import unique_id_for_user import open_ended_util from courseware.models import StudentModule +import logging +from courseware.access import has_access + +log=logging.getLogger(__name__) NOTIFICATION_TYPES = ( ('student_needs_to_peer_grade', 'peer_grading', 'Peer Grading'), @@ -13,10 +17,11 @@ NOTIFICATION_TYPES = ( ('overall_need_to_check', 'open_ended_problems', 'Problems you have submitted') ) -def staff_grading_notifications(course_id): +def staff_grading_notifications(course): staff_gs = StaffGradingService(settings.STAFF_GRADING_INTERFACE) pending_grading=False img_path= "" + course_id = course.id try: notifications = json.loads(staff_gs.get_notifications(course_id)) if notifications['success']: @@ -24,6 +29,7 @@ def staff_grading_notifications(course_id): pending_grading=True except: #Non catastrophic error, so no real action + notifications = {} log.info("Problem with getting notifications from staff grading service.") if pending_grading: @@ -31,10 +37,12 @@ def staff_grading_notifications(course_id): return {'pending_grading' : pending_grading, 'img_path' : img_path, 'response' : notifications} -def peer_grading_notifications(course_id, user): +def peer_grading_notifications(course, user): peer_gs = PeerGradingService(settings.PEER_GRADING_INTERFACE) pending_grading=False img_path= "" + course_id = course.id + try: notifications = json.loads(peer_gs.get_notifications(course_id,unique_id_for_user(user))) if notifications['success']: @@ -42,6 +50,7 @@ def peer_grading_notifications(course_id, user): pending_grading=True except: #Non catastrophic error, so no real action + notifications = {} log.info("Problem with getting notifications from peer grading service.") if pending_grading: @@ -49,14 +58,15 @@ def peer_grading_notifications(course_id, user): return {'pending_grading' : pending_grading, 'img_path' : img_path, 'response' : notifications} -def combined_notifications(course_id, user): +def combined_notifications(course, user): controller_url = open_ended_util.get_controller_url() controller_qs = ControllerQueryService(controller_url) student_id = unique_id_for_user(user) - user_is_staff = has_access(user, course, 'staff') + user_is_staff = has_access(user, course, 'staff') + course_id = course.id min_time_to_query = user.last_login - last_module_seen = StudentModule.objects.all(student=user, course_id = course_id, modified__gt=min_time_to_query).values('modified').order_by('-modified')[0] + last_module_seen = StudentModule.objects.filter(student=user, course_id = course_id, modified__gt=min_time_to_query).values('modified').order_by('-modified')[0] last_time_viewed = last_module_seen['modified'] pending_grading= False @@ -69,6 +79,7 @@ def combined_notifications(course_id, user): pending_grading=True except: #Non catastrophic error, so no real action + notifications = {} log.info("Problem with getting notifications from controller query service.") if pending_grading: diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index a1907ae230..c617eaac3f 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -165,10 +165,12 @@ def student_problem_list(request, course_id): @cache_control(no_cache=True, no_store=True, must_revalidate=True) def combined_notifications(request, course_id): + course = get_course_with_access(request.user, course_id, 'load') user = request.user - notifications = open_ended_notifications.combined_notifications(course_id, user) + notifications = open_ended_notifications.combined_notifications(course, user) response = notifications['response'] - notificaton_tuples=open_ended_notifications.NOTIFICATION_TYPES + notification_tuples=open_ended_notifications.NOTIFICATION_TYPES + notification_list = [] for response_num in xrange(0,len(notification_tuples)): @@ -191,8 +193,11 @@ def combined_notifications(request, course_id): combined_dict = { 'error_text' : "", 'notification_list' : notification_list, + 'course' : course, } - return combined_dict + return render_to_response('open_ended_problems/combined_notifications.html', + combined_dict + ) diff --git a/lms/urls.py b/lms/urls.py index c7c4f231f9..4b3cc94cab 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -285,7 +285,7 @@ if settings.COURSEWARE_ENABLED: # Open Ended problem list url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/open_ended_problems$', 'open_ended_grading.views.student_problem_list', name='open_ended_problems'), - + # Cohorts management url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/cohorts$', 'course_groups.views.list_cohorts', name="cohorts"), @@ -305,6 +305,9 @@ if settings.COURSEWARE_ENABLED: 'course_groups.views.debug_cohort_mgmt', name="debug_cohort_mgmt"), + # Open Ended Notifications + url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/open_ended_notifications$', + 'open_ended_grading.views.combined_notifications', name='open_ended_notifications'), ) # discussion forums live within courseware, so courseware must be enabled first From 8602e1595bf7819dd7ff1aad13f4c350d18e63a4 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 13:13:57 -0500 Subject: [PATCH 18/97] Pass proper parameters, fix templating --- .../open_ended_notifications.py | 6 ++-- .../open_ended_grading/open_ended_util.py | 2 +- lms/djangoapps/open_ended_grading/views.py | 7 +++- .../combined_notifications.html | 36 +++++++++---------- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/lms/djangoapps/open_ended_grading/open_ended_notifications.py b/lms/djangoapps/open_ended_grading/open_ended_notifications.py index 9ab75833ca..a5faef1011 100644 --- a/lms/djangoapps/open_ended_grading/open_ended_notifications.py +++ b/lms/djangoapps/open_ended_grading/open_ended_notifications.py @@ -73,14 +73,16 @@ def combined_notifications(course, user): img_path= "" try: - notifications = json.loads(controller_qs.get_notifications(course.id,student_id, user_is_staff, last_time_viewed)) + controller_response = controller_qs.check_combined_notifications(course.id,student_id, user_is_staff, last_time_viewed) + log.debug(controller_response) + notifications = json.loads(controller_response) if notifications['success']: if notifications['overall_need_to_check']: pending_grading=True except: #Non catastrophic error, so no real action notifications = {} - log.info("Problem with getting notifications from controller query service.") + log.exception("Problem with getting notifications from controller query service.") if pending_grading: img_path = "/static/images/slider-handle.png" diff --git a/lms/djangoapps/open_ended_grading/open_ended_util.py b/lms/djangoapps/open_ended_grading/open_ended_util.py index 772e3cd08e..07744d7d2c 100644 --- a/lms/djangoapps/open_ended_grading/open_ended_util.py +++ b/lms/djangoapps/open_ended_grading/open_ended_util.py @@ -7,6 +7,6 @@ def get_controller_url(): peer_grading_url = settings.PEER_GRADING_INTERFACE['url'] split_url = peer_grading_url.split("/") controller_url = "http://" + split_url[2] + "/grading_controller" - controller_settings=settings.PEER_GRADING_INTERFACE + controller_settings=settings.PEER_GRADING_INTERFACE.copy() controller_settings['url'] = controller_url return controller_settings diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index c617eaac3f..bfa7d89337 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -168,10 +168,10 @@ def combined_notifications(request, course_id): course = get_course_with_access(request.user, course_id, 'load') user = request.user notifications = open_ended_notifications.combined_notifications(course, user) + log.debug(notifications) response = notifications['response'] notification_tuples=open_ended_notifications.NOTIFICATION_TYPES - notification_list = [] for response_num in xrange(0,len(notification_tuples)): tag=notification_tuples[response_num][0] @@ -190,12 +190,17 @@ def combined_notifications(request, course_id): } notification_list.append(notification_item) + ajax_url = _reverse_with_slash('open_ended_notifications', course_id) combined_dict = { 'error_text' : "", 'notification_list' : notification_list, 'course' : course, + 'success' : True, + 'ajax_url' : ajax_url, } + log.debug(combined_dict) + return render_to_response('open_ended_problems/combined_notifications.html', combined_dict ) diff --git a/lms/templates/open_ended_problems/combined_notifications.html b/lms/templates/open_ended_problems/combined_notifications.html index 9fdedb2555..d14b2b9d9c 100644 --- a/lms/templates/open_ended_problems/combined_notifications.html +++ b/lms/templates/open_ended_problems/combined_notifications.html @@ -18,24 +18,24 @@

    Instructions

    Here are items that could potentially need your attention.

    % if success: - % if len(notification_list) == 0: -
    - No items require attention at the moment. -
    - %else: - - %endif + % if len(notification_list) == 0: +
    + No items require attention at the moment. +
    + %else: + + %endif %endif \ No newline at end of file From f47c431fafb4bba475ab0b093910aa07b21174c6 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 13:22:30 -0500 Subject: [PATCH 19/97] Fix templating --- .../open_ended_grading/controller_query_service.py | 1 + lms/djangoapps/open_ended_grading/views.py | 7 +++++-- .../open_ended_problems/combined_notifications.html | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lms/djangoapps/open_ended_grading/controller_query_service.py b/lms/djangoapps/open_ended_grading/controller_query_service.py index a111cfe58d..7d515e2475 100644 --- a/lms/djangoapps/open_ended_grading/controller_query_service.py +++ b/lms/djangoapps/open_ended_grading/controller_query_service.py @@ -45,6 +45,7 @@ class ControllerQueryService(GradingService): 'user_is_staff' : user_is_staff, 'last_time_viewed' : last_time_viewed, } + log.debug(self.combined_notifications_url) response = self.get(self.combined_notifications_url,params) return response diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index bfa7d89337..84bf14bf0e 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -39,11 +39,14 @@ it does not exist yet """ def _reverse_with_slash(url_name, course_id): - ajax_url = reverse(url_name, kwargs={'course_id': course_id}) + ajax_url = _reverse_without_slash(url_name, course_id) if not ajax_url.endswith('/'): ajax_url += '/' return ajax_url +def _reverse_without_slash(url_name, course_id): + ajax_url = reverse(url_name, kwargs={'course_id': course_id}) + return ajax_url @cache_control(no_cache=True, no_store=True, must_revalidate=True) def staff_grading(request, course_id): @@ -178,7 +181,7 @@ def combined_notifications(request, course_id): if tag in response: url_name = notification_tuples[response_num][1] human_name = notification_tuples[response_num][2] - url = _reverse_with_slash(url_name, course_id) + url = _reverse_without_slash(url_name, course_id) has_img = response[tag] img_path = "/static/images/slider-handle.png" diff --git a/lms/templates/open_ended_problems/combined_notifications.html b/lms/templates/open_ended_problems/combined_notifications.html index d14b2b9d9c..6d8541b567 100644 --- a/lms/templates/open_ended_problems/combined_notifications.html +++ b/lms/templates/open_ended_problems/combined_notifications.html @@ -27,7 +27,7 @@ %for notification in notification_list:
  • - {notification['name']} + ${notification['name']} % if notification['has_img'] == True: %endif From 457afaaedab2f57fe7a872b5ef37ebc2323c7e75 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 14:14:28 -0500 Subject: [PATCH 20/97] Making tab render properly for open ended notifications --- lms/djangoapps/courseware/tabs.py | 1 + lms/djangoapps/open_ended_grading/views.py | 19 ++++++++++++++++++- .../open_ended_problems.html | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index 3aa502e95e..b1e56ead08 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -181,6 +181,7 @@ VALID_TAB_TYPES = { 'static_tab': TabImpl(key_checker(['name', 'url_slug']), _static_tab), 'peer_grading': TabImpl(null_validator, _peer_grading), 'staff_grading': TabImpl(null_validator, _staff_grading), + 'open_ended': TabImpl(null_validator, _combined_open_ended_grading), } diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index 84bf14bf0e..29c3c3ebd3 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -22,6 +22,9 @@ from student.models import unique_id_for_user import open_ended_util import open_ended_notifications +from xmodule.modulestore.django import modulestore +from xmodule.modulestore import search + log = logging.getLogger(__name__) template_imports = {'urllib': urllib} @@ -137,6 +140,8 @@ def student_problem_list(request, course_id): success = False error_text = "" problem_list = [] + base_course_url = reverse('courses') + try: problem_list_json = controller_qs.get_grading_status_list(course_id, unique_id_for_user(request.user)) problem_list_dict = json.loads(problem_list_json) @@ -146,6 +151,19 @@ def student_problem_list(request, course_id): problem_list = problem_list_dict['problem_list'] + for i in xrange(0,len(problem_list)): + problem_url_parts = search.path_to_location(modulestore(), course.id, problem_list[i]['location']) + log.debug(problem_url_parts) + problem_url = base_course_url + "/" + for z in xrange(0,len(problem_url_parts)): + part = problem_url_parts[z] + if part is not None: + if z==1: + problem_url += "courseware/" + problem_url += part + "/" + + problem_list[i].update({'actual_url' : problem_url}) + except GradingServiceError: error_text = "Error occured while contacting the grading service" success = False @@ -171,7 +189,6 @@ def combined_notifications(request, course_id): course = get_course_with_access(request.user, course_id, 'load') user = request.user notifications = open_ended_notifications.combined_notifications(course, user) - log.debug(notifications) response = notifications['response'] notification_tuples=open_ended_notifications.NOTIFICATION_TYPES diff --git a/lms/templates/open_ended_problems/open_ended_problems.html b/lms/templates/open_ended_problems/open_ended_problems.html index ec648afab8..da309664eb 100644 --- a/lms/templates/open_ended_problems/open_ended_problems.html +++ b/lms/templates/open_ended_problems/open_ended_problems.html @@ -26,7 +26,7 @@ From d3d4e557d69da545f26d20d724a46853056295ec Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 14:16:18 -0500 Subject: [PATCH 21/97] Fix notification display --- lms/djangoapps/courseware/tabs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index b1e56ead08..7224657b60 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -132,8 +132,8 @@ def _peer_grading(tab, user, course, active_page): def _combined_open_ended_grading(tab, user, course, active_page): if user.is_authenticated: - link = reverse('open_ended_problems', args=[course.id]) - tab_name = "Open Ended Questions" + link = reverse('open_ended_notifications', args=[course.id]) + tab_name = "Open Ended Panel" notifications = open_ended_notifications.combined_notifications(course, user) pending_grading = notifications['pending_grading'] From bb55792b2bbf333812f0a3f4fbfdd9cd082102f7 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 14:21:17 -0500 Subject: [PATCH 22/97] Make things less noisy (remove debug statements) --- lms/djangoapps/open_ended_grading/views.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index 29c3c3ebd3..55f4907687 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -153,7 +153,6 @@ def student_problem_list(request, course_id): for i in xrange(0,len(problem_list)): problem_url_parts = search.path_to_location(modulestore(), course.id, problem_list[i]['location']) - log.debug(problem_url_parts) problem_url = base_course_url + "/" for z in xrange(0,len(problem_url_parts)): part = problem_url_parts[z] @@ -219,8 +218,6 @@ def combined_notifications(request, course_id): 'ajax_url' : ajax_url, } - log.debug(combined_dict) - return render_to_response('open_ended_problems/combined_notifications.html', combined_dict ) From 6412eb40809ed2140192a2764abfd9556d489471 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 10:19:34 -0500 Subject: [PATCH 23/97] Fix naming for overall need to check --- lms/djangoapps/courseware/tabs.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index 7224657b60..a53e4bfb0a 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -107,6 +107,7 @@ def _textbooks(tab, user, course, active_page): def _staff_grading(tab, user, course, active_page): if has_access(user, course, 'staff'): link = reverse('staff_grading', args=[course.id]) + tab_name = "Staff grading" notifications = open_ended_notifications.staff_grading_notifications(course) @@ -118,6 +119,7 @@ def _staff_grading(tab, user, course, active_page): return [] def _peer_grading(tab, user, course, active_page): + if user.is_authenticated(): link = reverse('peer_grading', args=[course.id]) tab_name = "Peer grading" From 0630f59c06bba9c75d6ba8cef9ac75e2ad7e5c69 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 13:13:57 -0500 Subject: [PATCH 24/97] Pass proper parameters, fix templating --- lms/djangoapps/open_ended_grading/views.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index 55f4907687..ad59262536 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -188,6 +188,7 @@ def combined_notifications(request, course_id): course = get_course_with_access(request.user, course_id, 'load') user = request.user notifications = open_ended_notifications.combined_notifications(course, user) + log.debug(notifications) response = notifications['response'] notification_tuples=open_ended_notifications.NOTIFICATION_TYPES @@ -218,6 +219,8 @@ def combined_notifications(request, course_id): 'ajax_url' : ajax_url, } + log.debug(combined_dict) + return render_to_response('open_ended_problems/combined_notifications.html', combined_dict ) From 33003e65d443cd6d36c0de6bceb045a035160cf1 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 14:21:17 -0500 Subject: [PATCH 25/97] Make things less noisy (remove debug statements) --- lms/djangoapps/open_ended_grading/views.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/lms/djangoapps/open_ended_grading/views.py b/lms/djangoapps/open_ended_grading/views.py index ad59262536..931cbb7337 100644 --- a/lms/djangoapps/open_ended_grading/views.py +++ b/lms/djangoapps/open_ended_grading/views.py @@ -219,8 +219,6 @@ def combined_notifications(request, course_id): 'ajax_url' : ajax_url, } - log.debug(combined_dict) - return render_to_response('open_ended_problems/combined_notifications.html', combined_dict ) From 5291271591e8eb856517b6c3f13e893509fb51db Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 14:33:18 -0500 Subject: [PATCH 26/97] Add in some minimal checking to make sure that the max score and scores for each rubric point are 3 --- .../lib/xmodule/xmodule/combined_open_ended_module.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index aa4b1f18ad..98018e5d80 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -141,11 +141,11 @@ class CombinedOpenEndedModule(XModule): self._max_score = int(self.metadata.get('max_score', MAX_SCORE)) rubric_renderer = CombinedOpenEndedRubric(system, True) - try: - rubric_feedback = rubric_renderer.render_rubric(stringify_children(definition['rubric'])) - except RubricParsingError: - log.error("Failed to parse rubric in location: {1}".format(location)) - raise + success, rubric_feedback = rubric_renderer.render_rubric(stringify_children(definition['rubric'])) + if not success: + error_message="Could not parse rubric : {0}".format(definition['rubric']) + log.exception(error_message) + raise Exception #Static data is passed to the child modules to render self.static_data = { 'max_score': self._max_score, From 29f738f7ce3480dd17f971fb4a7dc9f785cfb9ac Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 14:34:08 -0500 Subject: [PATCH 27/97] Minor count fix --- .../xmodule/combined_open_ended_module.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index 98018e5d80..53bfcf7673 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -35,6 +35,9 @@ MAX_ATTEMPTS = 10000 # Overriden by max_score specified in xml. MAX_SCORE = 1 +#The highest score allowed for the overall xmodule and for each rubric point +MAX_SCORE_ALLOWED = 3 + class CombinedOpenEndedModule(XModule): """ This is a module that encapsulates all open ended grading (self assessment, peer assessment, etc). @@ -140,12 +143,25 @@ class CombinedOpenEndedModule(XModule): # completion (doesn't matter if you self-assessed correct/incorrect). self._max_score = int(self.metadata.get('max_score', MAX_SCORE)) + if self._max_score>MAX_SCORE_ALLOWED: + error_message="Max score {0} is higher than max score allowed {1}".format(self._max_score, MAX_SCORE_ALLOWED) + log.exception(error_message) + raise Exception + rubric_renderer = CombinedOpenEndedRubric(system, True) success, rubric_feedback = rubric_renderer.render_rubric(stringify_children(definition['rubric'])) if not success: error_message="Could not parse rubric : {0}".format(definition['rubric']) log.exception(error_message) raise Exception + + rubric_categories = rubric_renderer.extract_categories(stringify_children(definition['rubric'])) + for category in rubric_categories: + if len(category['options'])>MAX_SCORE_ALLOWED: + error_message="Number of score points in rubric higher than the max allowed, which is {0} : {1}".format(MAX_SCORE_ALLOWED, definition['rubric']) + log.exception(error_message) + raise Exception + #Static data is passed to the child modules to render self.static_data = { 'max_score': self._max_score, From 3531bce7d3c0726d2bcf0ad4bbf0fa357768eff0 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 15:10:12 -0500 Subject: [PATCH 28/97] Fix score checking, latest post assessment scraping --- common/lib/xmodule/xmodule/combined_open_ended_module.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index 53bfcf7673..df8efc30c6 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -157,8 +157,8 @@ class CombinedOpenEndedModule(XModule): rubric_categories = rubric_renderer.extract_categories(stringify_children(definition['rubric'])) for category in rubric_categories: - if len(category['options'])>MAX_SCORE_ALLOWED: - error_message="Number of score points in rubric higher than the max allowed, which is {0} : {1}".format(MAX_SCORE_ALLOWED, definition['rubric']) + if len(category['options'])>(MAX_SCORE_ALLOWED+1): + error_message="Number of score points in rubric {0} higher than the max allowed, which is {1}".format(len(category['options']) , MAX_SCORE_ALLOWED) log.exception(error_message) raise Exception From 8b8c1dbe60b71997e2149ac882fe9c576738f715 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 17:29:09 -0500 Subject: [PATCH 29/97] Fix query error --- .../open_ended_grading/open_ended_notifications.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lms/djangoapps/open_ended_grading/open_ended_notifications.py b/lms/djangoapps/open_ended_grading/open_ended_notifications.py index a5faef1011..3529e124b4 100644 --- a/lms/djangoapps/open_ended_grading/open_ended_notifications.py +++ b/lms/djangoapps/open_ended_grading/open_ended_notifications.py @@ -66,9 +66,14 @@ def combined_notifications(course, user): course_id = course.id min_time_to_query = user.last_login - last_module_seen = StudentModule.objects.filter(student=user, course_id = course_id, modified__gt=min_time_to_query).values('modified').order_by('-modified')[0] + last_module_seen = StudentModule.objects.filter(student=user, course_id = course_id, modified__gt=min_time_to_query).values('modified').order_by('-modified') + last_module_seen_count = last_module_seen.count() + + if last_module_seen_count>0: + last_time_viewed = last_module_seen[0]['modified'] + else: + last_time_viewed = user.last_login - last_time_viewed = last_module_seen['modified'] pending_grading= False img_path= "" From 68f563a178e09be74aa0cd447972aa4d2e94ba77 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Tue, 22 Jan 2013 17:35:40 -0500 Subject: [PATCH 30/97] Fix naming issue --- lms/djangoapps/open_ended_grading/open_ended_notifications.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/djangoapps/open_ended_grading/open_ended_notifications.py b/lms/djangoapps/open_ended_grading/open_ended_notifications.py index 3529e124b4..d6621e468a 100644 --- a/lms/djangoapps/open_ended_grading/open_ended_notifications.py +++ b/lms/djangoapps/open_ended_grading/open_ended_notifications.py @@ -14,7 +14,7 @@ log=logging.getLogger(__name__) NOTIFICATION_TYPES = ( ('student_needs_to_peer_grade', 'peer_grading', 'Peer Grading'), ('staff_needs_to_grade', 'staff_grading', 'Staff Grading'), - ('overall_need_to_check', 'open_ended_problems', 'Problems you have submitted') + ('new_student_grading_to_view', 'open_ended_problems', 'Problems you have submitted') ) def staff_grading_notifications(course): From 665fb707b1f6c81c645c49d4efced853d7bb25fc Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Wed, 23 Jan 2013 10:43:45 -0500 Subject: [PATCH 31/97] Cache notifications for 5 mins so that we don't hit the grading server on every web request --- lms/djangoapps/courseware/tabs.py | 2 +- .../open_ended_notifications.py | 72 +++++++++++++++++-- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index a53e4bfb0a..b52324b360 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -110,7 +110,7 @@ def _staff_grading(tab, user, course, active_page): tab_name = "Staff grading" - notifications = open_ended_notifications.staff_grading_notifications(course) + notifications = open_ended_notifications.staff_grading_notifications(course, user) pending_grading = notifications['pending_grading'] img_path = notifications['img_path'] diff --git a/lms/djangoapps/open_ended_grading/open_ended_notifications.py b/lms/djangoapps/open_ended_grading/open_ended_notifications.py index d6621e468a..80f17352e9 100644 --- a/lms/djangoapps/open_ended_grading/open_ended_notifications.py +++ b/lms/djangoapps/open_ended_grading/open_ended_notifications.py @@ -8,20 +8,31 @@ import open_ended_util from courseware.models import StudentModule import logging from courseware.access import has_access +from util.cache import cache log=logging.getLogger(__name__) +NOTIFICATION_CACHE_TIME = 300 +KEY_PREFIX = "open_ended_" + NOTIFICATION_TYPES = ( ('student_needs_to_peer_grade', 'peer_grading', 'Peer Grading'), ('staff_needs_to_grade', 'staff_grading', 'Staff Grading'), ('new_student_grading_to_view', 'open_ended_problems', 'Problems you have submitted') ) -def staff_grading_notifications(course): +def staff_grading_notifications(course, user): staff_gs = StaffGradingService(settings.STAFF_GRADING_INTERFACE) pending_grading=False img_path= "" course_id = course.id + student_id = unique_id_for_user(user) + notification_type = "staff" + + success, notification_dict = get_value_from_cache(student_id, course_id, notification_type) + if success: + return notification_dict + try: notifications = json.loads(staff_gs.get_notifications(course_id)) if notifications['success']: @@ -35,16 +46,26 @@ def staff_grading_notifications(course): if pending_grading: img_path = "/static/images/slider-handle.png" - return {'pending_grading' : pending_grading, 'img_path' : img_path, 'response' : notifications} + notification_dict = {'pending_grading' : pending_grading, 'img_path' : img_path, 'response' : notifications} + + set_value_in_cache(student_id, course_id, notification_type, notification_dict) + + return notification_dict def peer_grading_notifications(course, user): peer_gs = PeerGradingService(settings.PEER_GRADING_INTERFACE) pending_grading=False img_path= "" course_id = course.id + student_id = unique_id_for_user(user) + notification_type = "peer" + + success, notification_dict = get_value_from_cache(student_id, course_id, notification_type) + if success: + return notification_dict try: - notifications = json.loads(peer_gs.get_notifications(course_id,unique_id_for_user(user))) + notifications = json.loads(peer_gs.get_notifications(course_id,student_id)) if notifications['success']: if notifications['student_needs_to_peer_grade']: pending_grading=True @@ -56,7 +77,11 @@ def peer_grading_notifications(course, user): if pending_grading: img_path = "/static/images/slider-handle.png" - return {'pending_grading' : pending_grading, 'img_path' : img_path, 'response' : notifications} + notification_dict = {'pending_grading' : pending_grading, 'img_path' : img_path, 'response' : notifications} + + set_value_in_cache(student_id, course_id, notification_type, notification_dict) + + return notification_dict def combined_notifications(course, user): controller_url = open_ended_util.get_controller_url() @@ -64,6 +89,11 @@ def combined_notifications(course, user): student_id = unique_id_for_user(user) user_is_staff = has_access(user, course, 'staff') course_id = course.id + notification_type = "combined" + + success, notification_dict = get_value_from_cache(student_id, course_id, notification_type) + if success: + return notification_dict min_time_to_query = user.last_login last_module_seen = StudentModule.objects.filter(student=user, course_id = course_id, modified__gt=min_time_to_query).values('modified').order_by('-modified') @@ -92,4 +122,36 @@ def combined_notifications(course, user): if pending_grading: img_path = "/static/images/slider-handle.png" - return {'pending_grading' : pending_grading, 'img_path' : img_path, 'response' : notifications} \ No newline at end of file + notification_dict = {'pending_grading' : pending_grading, 'img_path' : img_path, 'response' : notifications} + + set_value_in_cache(student_id, course_id, notification_type, notification_dict) + + return notification_dict + +def get_value_from_cache(student_id, course_id, notification_type): + key_name = create_key_name(student_id, course_id, notification_type) + success, value = _get_value_from_cache(key_name) + return success, value + +def set_value_in_cache(student_id, course_id, notification_type, value): + key_name = create_key_name(student_id, course_id, notification_type) + _set_value_in_cache(key_name, value) + +def create_key_name(student_id, course_id, notification_type): + key_name = "{prefix}{type}_{course}_{student}".format(prefix=KEY_PREFIX, type=notification_type, course=course_id, student=student_id) + return key_name + +def _get_value_from_cache(key_name): + value = cache.get(key_name) + success = False + if value is None: + return success , value + try: + value = json.loads(value) + success = True + except: + pass + return success , value + +def _set_value_in_cache(key_name, value): + cache.set(key_name, json.dumps(value), NOTIFICATION_CACHE_TIME) \ No newline at end of file From d07bf0157e41cde06d28722832999c99273c9c28 Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Wed, 23 Jan 2013 10:55:30 -0500 Subject: [PATCH 32/97] UI updates to the Open Ended Problems page --- lms/static/sass/course.scss | 2 ++ .../sass/course/_open_ended_grading.scss | 17 +++++++++++++ .../open_ended_problems.html | 25 ++++++++++++++----- 3 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 lms/static/sass/course/_open_ended_grading.scss diff --git a/lms/static/sass/course.scss b/lms/static/sass/course.scss index e900e589b2..17406782fe 100644 --- a/lms/static/sass/course.scss +++ b/lms/static/sass/course.scss @@ -44,6 +44,8 @@ @import "course/gradebook"; @import "course/tabs"; @import "course/staff_grading"; +@import "course/open_ended_grading"; + // instructor @import "course/instructor/instructor"; diff --git a/lms/static/sass/course/_open_ended_grading.scss b/lms/static/sass/course/_open_ended_grading.scss new file mode 100644 index 0000000000..86ab5f4aa0 --- /dev/null +++ b/lms/static/sass/course/_open_ended_grading.scss @@ -0,0 +1,17 @@ +.open-ended-problems, +.combined-notifications +{ + padding: 40px; + .problem-list + { + table-layout: auto; + margin-top: 10px; + width:70%; + text-align: center; + td, th + { + padding: 7px; + } + } + +} diff --git a/lms/templates/open_ended_problems/open_ended_problems.html b/lms/templates/open_ended_problems/open_ended_problems.html index da309664eb..f891947079 100644 --- a/lms/templates/open_ended_problems/open_ended_problems.html +++ b/lms/templates/open_ended_problems/open_ended_problems.html @@ -23,14 +23,27 @@ You have not attempted any open ended problems yet. %else: -