Commit 33c12647 by Arthur Barrett

Merge branch 'master' into feature/abarrett/annotatable_xmodule

parents 2f68cba2 03a4deb8
import copy
from fs.errors import ResourceNotFoundError
import itertools
import json import json
import logging import logging
from lxml import etree from lxml import etree
from lxml.html import rewrite_links
from path import path
import os
import sys
from pkg_resources import resource_string from pkg_resources import resource_string
from .capa_module import only_one, ComplexEncoder
from .editing_module import EditingDescriptor from .editing_module import EditingDescriptor
from .html_checker import check_html
from progress import Progress
from .stringify import stringify_children
from .x_module import XModule from .x_module import XModule
from .xml_module import XmlDescriptor from .xml_module import XmlDescriptor
from xmodule.modulestore import Location from xmodule.open_ended_grading_classes.combined_open_ended_modulev1 import CombinedOpenEndedV1Module, CombinedOpenEndedV1Descriptor
from combined_open_ended_modulev1 import CombinedOpenEndedV1Module, CombinedOpenEndedV1Descriptor
log = logging.getLogger("mitx.courseware") log = logging.getLogger("mitx.courseware")
......
import copy
from fs.errors import ResourceNotFoundError
import itertools
import json import json
import logging import logging
from lxml import etree from lxml import etree
from lxml.html import rewrite_links from lxml.html import rewrite_links
from path import path
import os
import sys from xmodule.capa_module import only_one, ComplexEncoder
import re from xmodule.editing_module import EditingDescriptor
from xmodule.html_checker import check_html
from pkg_resources import resource_string from xmodule.progress import Progress
from xmodule.stringify import stringify_children
from .capa_module import only_one, ComplexEncoder from xmodule.x_module import XModule
from .editing_module import EditingDescriptor from xmodule.xml_module import XmlDescriptor
from .html_checker import check_html
from progress import Progress
from .stringify import stringify_children
from .x_module import XModule
from .xml_module import XmlDescriptor
from xmodule.modulestore import Location
import self_assessment_module import self_assessment_module
import open_ended_module import open_ended_module
from combined_open_ended_rubric import CombinedOpenEndedRubric, RubricParsingError, GRADER_TYPE_IMAGE_DICT, HUMAN_GRADER_TYPE, LEGEND_LIST from combined_open_ended_rubric import CombinedOpenEndedRubric, GRADER_TYPE_IMAGE_DICT, HUMAN_GRADER_TYPE, LEGEND_LIST
from .stringify import stringify_children
import dateutil import dateutil
import dateutil.parser import dateutil.parser
import datetime from xmodule.timeparse import parse_timedelta
from timeparse import parse_timedelta
log = logging.getLogger("mitx.courseware") log = logging.getLogger("mitx.courseware")
...@@ -73,7 +62,7 @@ class CombinedOpenEndedV1Module(): ...@@ -73,7 +62,7 @@ class CombinedOpenEndedV1Module():
'save_assessment' -- Saves the student assessment (or external grader assessment) 'save_assessment' -- Saves the student assessment (or external grader assessment)
'save_post_assessment' -- saves a post assessment (hint, feedback on feedback, etc) 'save_post_assessment' -- saves a post assessment (hint, feedback on feedback, etc)
ajax actions implemented by combined open ended module are: ajax actions implemented by combined open ended module are:
'reset' -- resets the whole combined open ended module and returns to the first child module 'reset' -- resets the whole combined open ended module and returns to the first child moduleresource_string
'next_problem' -- moves to the next child module 'next_problem' -- moves to the next child module
'get_results' -- gets results from a given child module 'get_results' -- gets results from a given child module
...@@ -90,14 +79,6 @@ class CombinedOpenEndedV1Module(): ...@@ -90,14 +79,6 @@ class CombinedOpenEndedV1Module():
INTERMEDIATE_DONE = 'intermediate_done' INTERMEDIATE_DONE = 'intermediate_done'
DONE = 'done' DONE = 'done'
js = {'coffee': [resource_string(__name__, 'js/src/combinedopenended/display.coffee'),
resource_string(__name__, 'js/src/collapsible.coffee'),
resource_string(__name__, 'js/src/javascript_loader.coffee'),
]}
js_module_name = "CombinedOpenEnded"
css = {'scss': [resource_string(__name__, 'css/combinedopenended/display.scss')]}
def __init__(self, system, location, definition, descriptor, def __init__(self, system, location, definition, descriptor,
instance_state=None, shared_state=None, metadata = None, static_data = None, **kwargs): instance_state=None, shared_state=None, metadata = None, static_data = None, **kwargs):
...@@ -205,6 +186,7 @@ class CombinedOpenEndedV1Module(): ...@@ -205,6 +186,7 @@ class CombinedOpenEndedV1Module():
'display_name': self.display_name, 'display_name': self.display_name,
'accept_file_upload': self.accept_file_upload, 'accept_file_upload': self.accept_file_upload,
'close_date' : self.close_date, 'close_date' : self.close_date,
's3_interface' : self.system.s3_interface,
} }
self.task_xml = definition['task_xml'] self.task_xml = definition['task_xml']
...@@ -798,9 +780,6 @@ class CombinedOpenEndedV1Descriptor(XmlDescriptor, EditingDescriptor): ...@@ -798,9 +780,6 @@ class CombinedOpenEndedV1Descriptor(XmlDescriptor, EditingDescriptor):
has_score = True has_score = True
template_dir_name = "combinedopenended" template_dir_name = "combinedopenended"
js = {'coffee': [resource_string(__name__, 'js/src/html/edit.coffee')]}
js_module_name = "HTMLEditingDescriptor"
@classmethod @classmethod
def definition_from_xml(cls, xml_object, system): def definition_from_xml(cls, xml_object, system):
""" """
......
...@@ -5,7 +5,7 @@ import requests ...@@ -5,7 +5,7 @@ import requests
from requests.exceptions import RequestException, ConnectionError, HTTPError from requests.exceptions import RequestException, ConnectionError, HTTPError
import sys import sys
from xmodule.combined_open_ended_rubric import CombinedOpenEndedRubric, RubricParsingError from combined_open_ended_rubric import CombinedOpenEndedRubric
from lxml import etree from lxml import etree
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -22,8 +22,6 @@ class GradingService(object): ...@@ -22,8 +22,6 @@ class GradingService(object):
def __init__(self, config): def __init__(self, config):
self.username = config['username'] self.username = config['username']
self.password = config['password'] self.password = config['password']
self.url = config['url']
self.login_url = self.url + '/login/'
self.session = requests.session() self.session = requests.session()
self.system = config['system'] self.system = config['system']
......
...@@ -13,11 +13,6 @@ from urlparse import urlparse ...@@ -13,11 +13,6 @@ from urlparse import urlparse
import requests import requests
from boto.s3.connection import S3Connection from boto.s3.connection import S3Connection
from boto.s3.key import Key from boto.s3.key import Key
#TODO: Settings import is needed now in order to specify the URL and keys for amazon s3 (to upload images).
#Eventually, the goal is to replace the global django settings import with settings specifically
#for this module. There is no easy way to do this now, so piggybacking on the django settings
#makes sense.
from django.conf import settings
import pickle import pickle
import logging import logging
import re import re
...@@ -221,7 +216,7 @@ def run_image_tests(image): ...@@ -221,7 +216,7 @@ def run_image_tests(image):
return success return success
def upload_to_s3(file_to_upload, keyname): def upload_to_s3(file_to_upload, keyname, s3_interface):
''' '''
Upload file to S3 using provided keyname. Upload file to S3 using provided keyname.
...@@ -237,8 +232,8 @@ def upload_to_s3(file_to_upload, keyname): ...@@ -237,8 +232,8 @@ def upload_to_s3(file_to_upload, keyname):
#im.save(out_im, 'PNG') #im.save(out_im, 'PNG')
try: try:
conn = S3Connection(settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY) conn = S3Connection(s3_interface['access_key'], s3_interface['secret_access_key'])
bucketname = str(settings.AWS_STORAGE_BUCKET_NAME) bucketname = str(s3_interface['storage_bucket_name'])
bucket = conn.create_bucket(bucketname.lower()) bucket = conn.create_bucket(bucketname.lower())
k = Key(bucket) k = Key(bucket)
......
...@@ -5,28 +5,16 @@ hints, answers, and assessment judgment (currently only correct/incorrect). ...@@ -5,28 +5,16 @@ hints, answers, and assessment judgment (currently only correct/incorrect).
Parses xml definition file--see below for exact format. Parses xml definition file--see below for exact format.
""" """
import copy
from fs.errors import ResourceNotFoundError
import itertools
import json import json
import logging import logging
from lxml import etree from lxml import etree
from lxml.html import rewrite_links
from path import path
import os
import sys
import hashlib
import capa.xqueue_interface as xqueue_interface import capa.xqueue_interface as xqueue_interface
from pkg_resources import resource_string from xmodule.capa_module import ComplexEncoder
from xmodule.editing_module import EditingDescriptor
from .capa_module import only_one, ComplexEncoder from xmodule.progress import Progress
from .editing_module import EditingDescriptor from xmodule.stringify import stringify_children
from .html_checker import check_html from xmodule.xml_module import XmlDescriptor
from progress import Progress
from .stringify import stringify_children
from .xml_module import XmlDescriptor
from xmodule.modulestore import Location
from capa.util import * from capa.util import *
import openendedchild import openendedchild
...@@ -689,9 +677,6 @@ class OpenEndedDescriptor(XmlDescriptor, EditingDescriptor): ...@@ -689,9 +677,6 @@ class OpenEndedDescriptor(XmlDescriptor, EditingDescriptor):
has_score = True has_score = True
template_dir_name = "openended" template_dir_name = "openended"
js = {'coffee': [resource_string(__name__, 'js/src/html/edit.coffee')]}
js_module_name = "HTMLEditingDescriptor"
@classmethod @classmethod
def definition_from_xml(cls, xml_object, system): def definition_from_xml(cls, xml_object, system):
""" """
......
...@@ -13,17 +13,15 @@ import hashlib ...@@ -13,17 +13,15 @@ import hashlib
import capa.xqueue_interface as xqueue_interface import capa.xqueue_interface as xqueue_interface
import re import re
from pkg_resources import resource_string from xmodule.capa_module import only_one, ComplexEncoder
import open_ended_image_submission
from .capa_module import only_one, ComplexEncoder from xmodule.editing_module import EditingDescriptor
from .editing_module import EditingDescriptor from xmodule.html_checker import check_html
from .html_checker import check_html from xmodule.progress import Progress
from progress import Progress from xmodule.stringify import stringify_children
from .stringify import stringify_children from xmodule.xml_module import XmlDescriptor
from .xml_module import XmlDescriptor
from xmodule.modulestore import Location from xmodule.modulestore import Location
from capa.util import * from capa.util import *
import open_ended_image_submission
from datetime import datetime from datetime import datetime
...@@ -100,6 +98,7 @@ class OpenEndedChild(object): ...@@ -100,6 +98,7 @@ class OpenEndedChild(object):
self.display_name = static_data['display_name'] self.display_name = static_data['display_name']
self.accept_file_upload = static_data['accept_file_upload'] self.accept_file_upload = static_data['accept_file_upload']
self.close_date = static_data['close_date'] self.close_date = static_data['close_date']
self.s3_interface = static_data['s3_interface']
# Used for progress / grading. Currently get credit just for # Used for progress / grading. Currently get credit just for
# completion (doesn't matter if you self-assessed correct/incorrect). # completion (doesn't matter if you self-assessed correct/incorrect).
...@@ -319,7 +318,7 @@ class OpenEndedChild(object): ...@@ -319,7 +318,7 @@ class OpenEndedChild(object):
try: try:
image_data.seek(0) image_data.seek(0)
success, s3_public_url = open_ended_image_submission.upload_to_s3(image_data, image_key) success, s3_public_url = open_ended_image_submission.upload_to_s3(image_data, image_key, self.s3_interface)
except: except:
log.exception("Could not upload image to S3.") log.exception("Could not upload image to S3.")
......
import json import json
import logging import logging
import requests
from requests.exceptions import RequestException, ConnectionError, HTTPError
import sys
#TODO: Settings import is needed now in order to specify the URL where to find the peer grading service. from grading_service_module import GradingService
#Eventually, the goal is to replace the global django settings import with settings specifically
#for this xmodule. There is no easy way to do this now, so piggybacking on the django settings
#makes sense.
from django.conf import settings
from combined_open_ended_rubric import CombinedOpenEndedRubric, RubricParsingError
from lxml import etree
from grading_service_module import GradingService, GradingServiceError
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -28,6 +17,8 @@ class PeerGradingService(GradingService): ...@@ -28,6 +17,8 @@ class PeerGradingService(GradingService):
def __init__(self, config, system): def __init__(self, config, system):
config['system'] = system config['system'] = system
super(PeerGradingService, self).__init__(config) super(PeerGradingService, self).__init__(config)
self.url = config['url'] + config['peer_grading']
self.login_url = self.url + '/login/'
self.get_next_submission_url = self.url + '/get_next_submission/' self.get_next_submission_url = self.url + '/get_next_submission/'
self.save_grade_url = self.url + '/save_grade/' self.save_grade_url = self.url + '/save_grade/'
self.is_student_calibrated_url = self.url + '/is_student_calibrated/' self.is_student_calibrated_url = self.url + '/is_student_calibrated/'
...@@ -142,25 +133,3 @@ class MockPeerGradingService(object): ...@@ -142,25 +133,3 @@ class MockPeerGradingService(object):
json.dumps({'location': 'i4x://MITx/3.091x/problem/open_ended_demo2', json.dumps({'location': 'i4x://MITx/3.091x/problem/open_ended_demo2',
'problem_name': "Problem 2", 'num_graded': 1, 'num_pending': 5}) 'problem_name': "Problem 2", 'num_graded': 1, 'num_pending': 5})
]}) ]})
_service = None
def peer_grading_service(system):
"""
Return a peer grading service instance--if settings.MOCK_PEER_GRADING is True,
returns a mock one, otherwise a real one.
Caches the result, so changing the setting after the first call to this
function will have no effect.
"""
global _service
if _service is not None:
return _service
if settings.MOCK_PEER_GRADING:
_service = MockPeerGradingService()
else:
_service = PeerGradingService(settings.PEER_GRADING_INTERFACE, system)
return _service
import copy
from fs.errors import ResourceNotFoundError
import itertools
import json import json
import logging import logging
from lxml import etree from lxml import etree
from lxml.html import rewrite_links
from path import path from xmodule.capa_module import ComplexEncoder
import os from xmodule.editing_module import EditingDescriptor
import sys from xmodule.progress import Progress
from xmodule.stringify import stringify_children
from pkg_resources import resource_string from xmodule.xml_module import XmlDescriptor
from .capa_module import only_one, ComplexEncoder
from .editing_module import EditingDescriptor
from .html_checker import check_html
from progress import Progress
from .stringify import stringify_children
from .x_module import XModule
from .xml_module import XmlDescriptor
from xmodule.modulestore import Location
import openendedchild import openendedchild
from combined_open_ended_rubric import CombinedOpenEndedRubric from combined_open_ended_rubric import CombinedOpenEndedRubric
...@@ -285,10 +273,6 @@ class SelfAssessmentDescriptor(XmlDescriptor, EditingDescriptor): ...@@ -285,10 +273,6 @@ class SelfAssessmentDescriptor(XmlDescriptor, EditingDescriptor):
has_score = True has_score = True
template_dir_name = "selfassessment" template_dir_name = "selfassessment"
js = {'coffee': [resource_string(__name__, 'js/src/html/edit.coffee')]}
js_module_name = "HTMLEditingDescriptor"
css = {'scss': [resource_string(__name__, 'css/editor/edit.scss'), resource_string(__name__, 'css/html/edit.scss')]}
@classmethod @classmethod
def definition_from_xml(cls, xml_object, system): def definition_from_xml(cls, xml_object, system):
""" """
......
"""
This module provides an interface on the grading-service backend
for peer grading
Use peer_grading_service() to get the version specified
in settings.PEER_GRADING_INTERFACE
"""
import json import json
import logging import logging
import requests
import sys
from django.conf import settings
from combined_open_ended_rubric import CombinedOpenEndedRubric
from lxml import etree from lxml import etree
import copy
import itertools
import json
import logging
from lxml.html import rewrite_links
import os
from pkg_resources import resource_string from pkg_resources import resource_string
from .capa_module import only_one, ComplexEncoder from .capa_module import ComplexEncoder
from .editing_module import EditingDescriptor from .editing_module import EditingDescriptor
from .html_checker import check_html
from progress import Progress
from .stringify import stringify_children from .stringify import stringify_children
from .x_module import XModule from .x_module import XModule
from .xml_module import XmlDescriptor from .xml_module import XmlDescriptor
from xmodule.modulestore import Location from xmodule.modulestore import Location
from peer_grading_service import peer_grading_service, GradingServiceError from xmodule.open_ended_grading_classes.peer_grading_service import PeerGradingService, GradingServiceError
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -70,7 +48,7 @@ class PeerGradingModule(XModule): ...@@ -70,7 +48,7 @@ class PeerGradingModule(XModule):
#We need to set the location here so the child modules can use it #We need to set the location here so the child modules can use it
system.set('location', location) system.set('location', location)
self.system = system self.system = system
self.peer_gs = peer_grading_service(self.system) self.peer_gs = PeerGradingService(self.system.open_ended_grading_interface, self.system)
self.use_for_single_location = self.metadata.get('use_for_single_location', USE_FOR_SINGLE_LOCATION) self.use_for_single_location = self.metadata.get('use_for_single_location', USE_FOR_SINGLE_LOCATION)
if isinstance(self.use_for_single_location, basestring): if isinstance(self.use_for_single_location, basestring):
...@@ -142,7 +120,7 @@ class PeerGradingModule(XModule): ...@@ -142,7 +120,7 @@ class PeerGradingModule(XModule):
def query_data_for_location(self): def query_data_for_location(self):
student_id = self.system.anonymous_student_id student_id = self.system.anonymous_student_id
location = self.system.location location = self.link_to_location
success = False success = False
response = {} response = {}
...@@ -171,7 +149,7 @@ class PeerGradingModule(XModule): ...@@ -171,7 +149,7 @@ class PeerGradingModule(XModule):
success, response = self.query_data_for_location() success, response = self.query_data_for_location()
if not success: if not success:
log.exception("No instance data found and could not get data from controller for loc {0} student {1}".format( log.exception("No instance data found and could not get data from controller for loc {0} student {1}".format(
self.system.location, self.system.anonymous_student_id self.system.location.url(), self.system.anonymous_student_id
)) ))
return None return None
count_graded = response['count_graded'] count_graded = response['count_graded']
......
...@@ -2,9 +2,9 @@ import json ...@@ -2,9 +2,9 @@ import json
from mock import Mock, MagicMock, ANY from mock import Mock, MagicMock, ANY
import unittest import unittest
from xmodule.openendedchild import OpenEndedChild from xmodule.open_ended_grading_classes.openendedchild import OpenEndedChild
from xmodule.open_ended_module import OpenEndedModule from xmodule.open_ended_grading_classes.open_ended_module import OpenEndedModule
from xmodule.combined_open_ended_modulev1 import CombinedOpenEndedV1Module from xmodule.open_ended_grading_classes.combined_open_ended_modulev1 import CombinedOpenEndedV1Module
from xmodule.modulestore import Location from xmodule.modulestore import Location
from lxml import etree from lxml import etree
...@@ -12,6 +12,8 @@ import capa.xqueue_interface as xqueue_interface ...@@ -12,6 +12,8 @@ import capa.xqueue_interface as xqueue_interface
from datetime import datetime from datetime import datetime
from . import test_system from . import test_system
import test_util_open_ended
""" """
Tests for the various pieces of the CombinedOpenEndedGrading system Tests for the various pieces of the CombinedOpenEndedGrading system
...@@ -43,7 +45,9 @@ class OpenEndedChildTest(unittest.TestCase): ...@@ -43,7 +45,9 @@ class OpenEndedChildTest(unittest.TestCase):
'max_score': max_score, 'max_score': max_score,
'display_name': 'Name', 'display_name': 'Name',
'accept_file_upload': False, 'accept_file_upload': False,
'close_date': None 'close_date': None,
's3_interface' : "",
'open_ended_grading_interface' : {},
} }
definition = Mock() definition = Mock()
descriptor = Mock() descriptor = Mock()
...@@ -161,6 +165,8 @@ class OpenEndedModuleTest(unittest.TestCase): ...@@ -161,6 +165,8 @@ class OpenEndedModuleTest(unittest.TestCase):
'accept_file_upload': False, 'accept_file_upload': False,
'rewrite_content_links' : "", 'rewrite_content_links' : "",
'close_date': None, 'close_date': None,
's3_interface' : test_util_open_ended.S3_INTERFACE,
'open_ended_grading_interface' : test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE,
} }
oeparam = etree.XML(''' oeparam = etree.XML('''
...@@ -293,6 +299,8 @@ class CombinedOpenEndedModuleTest(unittest.TestCase): ...@@ -293,6 +299,8 @@ class CombinedOpenEndedModuleTest(unittest.TestCase):
'accept_file_upload' : False, 'accept_file_upload' : False,
'rewrite_content_links' : "", 'rewrite_content_links' : "",
'close_date' : "", 'close_date' : "",
's3_interface' : test_util_open_ended.S3_INTERFACE,
'open_ended_grading_interface' : test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE,
} }
oeparam = etree.XML(''' oeparam = etree.XML('''
......
...@@ -2,13 +2,14 @@ import json ...@@ -2,13 +2,14 @@ import json
from mock import Mock from mock import Mock
import unittest import unittest
from xmodule.self_assessment_module import SelfAssessmentModule from xmodule.open_ended_grading_classes.self_assessment_module import SelfAssessmentModule
from xmodule.modulestore import Location from xmodule.modulestore import Location
from lxml import etree from lxml import etree
from nose.plugins.skip import SkipTest from nose.plugins.skip import SkipTest
from . import test_system from . import test_system
import test_util_open_ended
class SelfAssessmentTest(unittest.TestCase): class SelfAssessmentTest(unittest.TestCase):
...@@ -47,7 +48,9 @@ class SelfAssessmentTest(unittest.TestCase): ...@@ -47,7 +48,9 @@ class SelfAssessmentTest(unittest.TestCase):
'max_score': 1, 'max_score': 1,
'display_name': "Name", 'display_name': "Name",
'accept_file_upload': False, 'accept_file_upload': False,
'close_date': None 'close_date': None,
's3_interface' : test_util_open_ended.S3_INTERFACE,
'open_ended_grading_interface' : test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE,
} }
self.module = SelfAssessmentModule(test_system, self.location, self.module = SelfAssessmentModule(test_system, self.location,
......
OPEN_ENDED_GRADING_INTERFACE = {
'url' : 'http://127.0.0.1:3033/',
'username' : 'incorrect',
'password' : 'incorrect',
'staff_grading' : 'staff_grading',
'peer_grading' : 'peer_grading',
'grading_controller' : 'grading_controller'
}
S3_INTERFACE = {
'aws_access_key' : "",
'aws_secret_key' : "",
"aws_bucket_name" : "",
}
\ No newline at end of file
...@@ -879,7 +879,9 @@ class ModuleSystem(object): ...@@ -879,7 +879,9 @@ class ModuleSystem(object):
xqueue=None, xqueue=None,
node_path="", node_path="",
anonymous_student_id='', anonymous_student_id='',
course_id=None): course_id=None,
open_ended_grading_interface=None,
s3_interface=None):
''' '''
Create a closure around the system environment. Create a closure around the system environment.
...@@ -930,6 +932,8 @@ class ModuleSystem(object): ...@@ -930,6 +932,8 @@ class ModuleSystem(object):
self.anonymous_student_id = anonymous_student_id self.anonymous_student_id = anonymous_student_id
self.course_id = course_id self.course_id = course_id
self.user_is_staff = user is not None and user.is_staff self.user_is_staff = user is not None and user.is_staff
self.open_ended_grading_interface = open_ended_grading_interface
self.s3_interface = s3_interface
def get(self, attr): def get(self, attr):
''' provide uniform access to attributes (like etree).''' ''' provide uniform access to attributes (like etree).'''
......
...@@ -226,6 +226,30 @@ def _get_module(user, request, descriptor, student_module_cache, course_id, ...@@ -226,6 +226,30 @@ def _get_module(user, request, descriptor, student_module_cache, course_id,
'waittime': settings.XQUEUE_WAITTIME_BETWEEN_REQUESTS 'waittime': settings.XQUEUE_WAITTIME_BETWEEN_REQUESTS
} }
def get_or_default(key, default):
getattr(settings, key, default)
#This is a hacky way to pass settings to the combined open ended xmodule
#It needs an S3 interface to upload images to S3
#It needs the open ended grading interface in order to get peer grading to be done
#TODO: refactor these settings into module-specific settings when possible.
#this first checks to see if the descriptor is the correct one, and only sends settings if it is
is_descriptor_combined_open_ended = (descriptor.__class__.__name__ == 'CombinedOpenEndedDescriptor')
is_descriptor_peer_grading = (descriptor.__class__.__name__ == 'PeerGradingDescriptor')
open_ended_grading_interface = None
s3_interface = None
if is_descriptor_combined_open_ended or is_descriptor_peer_grading:
open_ended_grading_interface = settings.OPEN_ENDED_GRADING_INTERFACE
open_ended_grading_interface['mock_peer_grading'] = settings.MOCK_PEER_GRADING
open_ended_grading_interface['mock_staff_grading'] = settings.MOCK_STAFF_GRADING
if is_descriptor_combined_open_ended:
s3_interface = {
'access_key' : get_or_default('AWS_ACCESS_KEY_ID',''),
'secret_access_key' : get_or_default('AWS_SECRET_ACCESS_KEY',''),
'storage_bucket_name' : get_or_default('AWS_STORAGE_BUCKET_NAME','')
}
def inner_get_module(descriptor): def inner_get_module(descriptor):
""" """
Delegate to get_module. It does an access check, so may return None Delegate to get_module. It does an access check, so may return None
...@@ -255,6 +279,8 @@ def _get_module(user, request, descriptor, student_module_cache, course_id, ...@@ -255,6 +279,8 @@ def _get_module(user, request, descriptor, student_module_cache, course_id,
node_path=settings.NODE_PATH, node_path=settings.NODE_PATH,
anonymous_student_id=unique_id_for_user(user), anonymous_student_id=unique_id_for_user(user),
course_id=course_id, course_id=course_id,
open_ended_grading_interface=open_ended_grading_interface,
s3_interface=s3_interface,
) )
# pass position specified in URL to module through ModuleSystem # pass position specified in URL to module through ModuleSystem
system.set('position', position) system.set('position', position)
......
import json
import logging import logging
import requests from xmodule.open_ended_grading_classes.grading_service_module import GradingService
from requests.exceptions import RequestException, ConnectionError, HTTPError
import sys
from xmodule.grading_service_module import GradingService, GradingServiceError
from django.conf import settings
from django.http import HttpResponse, Http404
from xmodule.x_module import ModuleSystem from xmodule.x_module import ModuleSystem
from mitxmako.shortcuts import render_to_string from mitxmako.shortcuts import render_to_string
...@@ -20,6 +14,8 @@ class ControllerQueryService(GradingService): ...@@ -20,6 +14,8 @@ class ControllerQueryService(GradingService):
def __init__(self, config): def __init__(self, config):
config['system'] = ModuleSystem(None, None, None, render_to_string, None) config['system'] = ModuleSystem(None, None, None, render_to_string, None)
super(ControllerQueryService, self).__init__(config) super(ControllerQueryService, self).__init__(config)
self.url = config['url'] + config['grading_controller']
self.login_url = self.url + '/login/'
self.check_eta_url = self.url + '/get_submission_eta/' self.check_eta_url = self.url + '/get_submission_eta/'
self.is_unique_url = self.url + '/is_name_unique/' self.is_unique_url = self.url + '/is_name_unique/'
self.combined_notifications_url = self.url + '/combined_notifications/' self.combined_notifications_url = self.url + '/combined_notifications/'
......
from django.conf import settings from django.conf import settings
from xmodule.open_ended_grading_classes import peer_grading_service
from staff_grading_service import StaffGradingService from staff_grading_service import StaffGradingService
from open_ended_grading.controller_query_service import ControllerQueryService from open_ended_grading.controller_query_service import ControllerQueryService
from xmodule import peer_grading_service
import json import json
from student.models import unique_id_for_user from student.models import unique_id_for_user
import open_ended_util
from courseware.models import StudentModule from courseware.models import StudentModule
import logging import logging
from courseware.access import has_access from courseware.access import has_access
from util.cache import cache from util.cache import cache
import datetime import datetime
from xmodule import peer_grading_service
from xmodule.x_module import ModuleSystem from xmodule.x_module import ModuleSystem
from mitxmako.shortcuts import render_to_string from mitxmako.shortcuts import render_to_string
...@@ -28,7 +26,7 @@ NOTIFICATION_TYPES = ( ...@@ -28,7 +26,7 @@ NOTIFICATION_TYPES = (
def staff_grading_notifications(course, user): def staff_grading_notifications(course, user):
staff_gs = StaffGradingService(settings.STAFF_GRADING_INTERFACE) staff_gs = StaffGradingService(settings.OPEN_ENDED_GRADING_INTERFACE)
pending_grading = False pending_grading = False
img_path = "" img_path = ""
course_id = course.id course_id = course.id
...@@ -61,7 +59,7 @@ def staff_grading_notifications(course, user): ...@@ -61,7 +59,7 @@ def staff_grading_notifications(course, user):
def peer_grading_notifications(course, user): def peer_grading_notifications(course, user):
system = ModuleSystem(None, None, None, render_to_string, None) system = ModuleSystem(None, None, None, render_to_string, None)
peer_gs = peer_grading_service.PeerGradingService(settings.PEER_GRADING_INTERFACE, system) peer_gs = peer_grading_service.PeerGradingService(settings.OPEN_ENDED_GRADING_INTERFACE, system)
pending_grading = False pending_grading = False
img_path = "" img_path = ""
course_id = course.id course_id = course.id
...@@ -93,8 +91,7 @@ def peer_grading_notifications(course, user): ...@@ -93,8 +91,7 @@ def peer_grading_notifications(course, user):
def combined_notifications(course, user): def combined_notifications(course, user):
controller_url = open_ended_util.get_controller_url() controller_qs = ControllerQueryService(settings.OPEN_ENDED_GRADING_INTERFACE)
controller_qs = ControllerQueryService(controller_url)
student_id = unique_id_for_user(user) 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 course_id = course.id
......
from django.conf import settings
import logging
log = logging.getLogger(__name__)
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.copy()
controller_settings['url'] = controller_url
return controller_settings
...@@ -4,10 +4,7 @@ This module provides views that proxy to the staff grading backend service. ...@@ -4,10 +4,7 @@ This module provides views that proxy to the staff grading backend service.
import json import json
import logging import logging
import requests from xmodule.open_ended_grading_classes.grading_service_module import GradingService, GradingServiceError
from requests.exceptions import RequestException, ConnectionError, HTTPError
import sys
from xmodule.grading_service_module import GradingService, GradingServiceError
from django.conf import settings from django.conf import settings
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404
...@@ -64,6 +61,8 @@ class StaffGradingService(GradingService): ...@@ -64,6 +61,8 @@ class StaffGradingService(GradingService):
def __init__(self, config): def __init__(self, config):
config['system'] = ModuleSystem(None, None, None, render_to_string, None) config['system'] = ModuleSystem(None, None, None, render_to_string, None)
super(StaffGradingService, self).__init__(config) super(StaffGradingService, self).__init__(config)
self.url = config['url'] + config['staff_grading']
self.login_url = self.url + '/login/'
self.get_next_url = self.url + '/get_next_submission/' self.get_next_url = self.url + '/get_next_submission/'
self.save_grade_url = self.url + '/save_grade/' self.save_grade_url = self.url + '/save_grade/'
self.get_problem_list_url = self.url + '/get_problem_list/' self.get_problem_list_url = self.url + '/get_problem_list/'
...@@ -164,7 +163,7 @@ def staff_grading_service(): ...@@ -164,7 +163,7 @@ def staff_grading_service():
if settings.MOCK_STAFF_GRADING: if settings.MOCK_STAFF_GRADING:
_service = MockStaffGradingService() _service = MockStaffGradingService()
else: else:
_service = StaffGradingService(settings.STAFF_GRADING_INTERFACE) _service = StaffGradingService(settings.OPEN_ENDED_GRADING_INTERFACE)
return _service return _service
......
...@@ -6,7 +6,8 @@ django-admin.py test --settings=lms.envs.test --pythonpath=. lms/djangoapps/open ...@@ -6,7 +6,8 @@ django-admin.py test --settings=lms.envs.test --pythonpath=. lms/djangoapps/open
from django.test import TestCase from django.test import TestCase
from open_ended_grading import staff_grading_service from open_ended_grading import staff_grading_service
from xmodule import peer_grading_service, peer_grading_module from xmodule.open_ended_grading_classes import peer_grading_service
from xmodule import peer_grading_module
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
...@@ -25,6 +26,8 @@ log = logging.getLogger(__name__) ...@@ -25,6 +26,8 @@ log = logging.getLogger(__name__)
from django.test.utils import override_settings from django.test.utils import override_settings
from django.http import QueryDict from django.http import QueryDict
from xmodule.tests import test_util_open_ended
@override_settings(MODULESTORE=ct.TEST_DATA_XML_MODULESTORE) @override_settings(MODULESTORE=ct.TEST_DATA_XML_MODULESTORE)
class TestStaffGradingService(ct.PageLoader): class TestStaffGradingService(ct.PageLoader):
...@@ -144,9 +147,11 @@ class TestPeerGradingService(ct.PageLoader): ...@@ -144,9 +147,11 @@ class TestPeerGradingService(ct.PageLoader):
location = "i4x://edX/toy/peergrading/init" location = "i4x://edX/toy/peergrading/init"
self.mock_service = peer_grading_service.MockPeerGradingService() self.mock_service = peer_grading_service.MockPeerGradingService()
self.system = ModuleSystem(location, None, None, render_to_string, None) self.system = ModuleSystem(location, None, None, render_to_string, None,
s3_interface = test_util_open_ended.S3_INTERFACE,
open_ended_grading_interface=test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE
)
self.descriptor = peer_grading_module.PeerGradingDescriptor(self.system) self.descriptor = peer_grading_module.PeerGradingDescriptor(self.system)
self.peer_module = peer_grading_module.PeerGradingModule(self.system, location, "<peergrading/>", self.descriptor) self.peer_module = peer_grading_module.PeerGradingModule(self.system, location, "<peergrading/>", self.descriptor)
self.peer_module.peer_gs = self.mock_service self.peer_module.peer_gs = self.mock_service
self.logout() self.logout()
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
import logging import logging
import urllib import urllib
import re
from django.conf import settings from django.conf import settings
from django.views.decorators.cache import cache_control from django.views.decorators.cache import cache_control
...@@ -13,12 +12,10 @@ from student.models import unique_id_for_user ...@@ -13,12 +12,10 @@ from student.models import unique_id_for_user
from courseware.courses import get_course_with_access from courseware.courses import get_course_with_access
from controller_query_service import ControllerQueryService from controller_query_service import ControllerQueryService
from xmodule.grading_service_module import GradingServiceError from xmodule.open_ended_grading_classes.grading_service_module import GradingServiceError
import json import json
from .staff_grading import StaffGrading
from student.models import unique_id_for_user from student.models import unique_id_for_user
import open_ended_util
import open_ended_notifications import open_ended_notifications
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
...@@ -30,8 +27,7 @@ log = logging.getLogger(__name__) ...@@ -30,8 +27,7 @@ log = logging.getLogger(__name__)
template_imports = {'urllib': urllib} template_imports = {'urllib': urllib}
controller_url = open_ended_util.get_controller_url() controller_qs = ControllerQueryService(settings.OPEN_ENDED_GRADING_INTERFACE)
controller_qs = ControllerQueryService(controller_url)
""" """
Reverses the URL from the name and the course id, and then adds a trailing slash if Reverses the URL from the name and the course id, and then adds a trailing slash if
......
...@@ -100,10 +100,7 @@ XQUEUE_INTERFACE = AUTH_TOKENS['XQUEUE_INTERFACE'] ...@@ -100,10 +100,7 @@ XQUEUE_INTERFACE = AUTH_TOKENS['XQUEUE_INTERFACE']
MODULESTORE = AUTH_TOKENS.get('MODULESTORE', MODULESTORE) MODULESTORE = AUTH_TOKENS.get('MODULESTORE', MODULESTORE)
CONTENTSTORE = AUTH_TOKENS.get('CONTENTSTORE', CONTENTSTORE) CONTENTSTORE = AUTH_TOKENS.get('CONTENTSTORE', CONTENTSTORE)
STAFF_GRADING_INTERFACE = AUTH_TOKENS.get('STAFF_GRADING_INTERFACE', OPEN_ENDED_GRADING_INTERFACE = AUTH_TOKENS.get('OPEN_ENDED_GRADING_INTERFACE', OPEN_ENDED_GRADING_INTERFACE)
STAFF_GRADING_INTERFACE)
PEER_GRADING_INTERFACE = AUTH_TOKENS.get('PEER_GRADING_INTERFACE',
PEER_GRADING_INTERFACE)
PEARSON_TEST_USER = "pearsontest" PEARSON_TEST_USER = "pearsontest"
PEARSON_TEST_PASSWORD = AUTH_TOKENS.get("PEARSON_TEST_PASSWORD") PEARSON_TEST_PASSWORD = AUTH_TOKENS.get("PEARSON_TEST_PASSWORD")
......
...@@ -310,37 +310,30 @@ WIKI_USE_BOOTSTRAP_SELECT_WIDGET = False ...@@ -310,37 +310,30 @@ WIKI_USE_BOOTSTRAP_SELECT_WIDGET = False
WIKI_LINK_LIVE_LOOKUPS = False WIKI_LINK_LIVE_LOOKUPS = False
WIKI_LINK_DEFAULT_LEVEL = 2 WIKI_LINK_DEFAULT_LEVEL = 2
################################# Staff grading config #####################
#By setting up the default settings with an incorrect user name and password,
# will get an error when attempting to connect
STAFF_GRADING_INTERFACE = {
'url': 'http://sandbox-grader-001.m.edx.org/staff_grading',
'username': 'incorrect_user',
'password': 'incorrect_pass',
}
# Used for testing, debugging
MOCK_STAFF_GRADING = False
################################# Pearson TestCenter config ################ ################################# Pearson TestCenter config ################
PEARSONVUE_SIGNINPAGE_URL = "https://www1.pearsonvue.com/testtaker/signin/SignInPage/EDX" PEARSONVUE_SIGNINPAGE_URL = "https://www1.pearsonvue.com/testtaker/signin/SignInPage/EDX"
# TESTCENTER_ACCOMMODATION_REQUEST_EMAIL = "exam-help@edx.org" # TESTCENTER_ACCOMMODATION_REQUEST_EMAIL = "exam-help@edx.org"
################################# Peer grading config ##################### ################################# open ended grading config #####################
#By setting up the default settings with an incorrect user name and password, #By setting up the default settings with an incorrect user name and password,
# will get an error when attempting to connect # will get an error when attempting to connect
PEER_GRADING_INTERFACE = { OPEN_ENDED_GRADING_INTERFACE = {
'url': 'http://sandbox-grader-001.m.edx.org/peer_grading', 'url': 'http://sandbox-grader-001.m.edx.org/peer_grading',
'username': 'incorrect_user', 'username': 'incorrect_user',
'password': 'incorrect_pass', 'password': 'incorrect_pass',
'staff_grading' : 'staff_grading',
'peer_grading' : 'peer_grading',
'grading_controller' : 'grading_controller'
} }
# Used for testing, debugging # Used for testing, debugging peer grading
MOCK_PEER_GRADING = False MOCK_PEER_GRADING = False
# Used for testing, debugging staff grading
MOCK_STAFF_GRADING = False
################################# Jasmine ################################### ################################# Jasmine ###################################
JASMINE_TEST_DIRECTORY = PROJECT_ROOT + '/static/coffee' JASMINE_TEST_DIRECTORY = PROJECT_ROOT + '/static/coffee'
......
...@@ -131,21 +131,17 @@ if os.path.isdir(DATA_DIR): ...@@ -131,21 +131,17 @@ if os.path.isdir(DATA_DIR):
MITX_VERSION_STRING = os.popen('cd %s; git describe' % REPO_ROOT).read().strip() MITX_VERSION_STRING = os.popen('cd %s; git describe' % REPO_ROOT).read().strip()
################################# Staff grading config ##################### ################################# Open ended grading config #####################
STAFF_GRADING_INTERFACE = { OPEN_ENDED_GRADING_INTERFACE = {
'url': 'http://127.0.0.1:3033/staff_grading', 'url' : 'http://127.0.0.1:3033/',
'username': 'lms', 'username' : 'lms',
'password': 'abcd', 'password' : 'abcd',
} 'staff_grading' : 'staff_grading',
'peer_grading' : 'peer_grading',
################################# Peer grading config ##################### 'grading_controller' : 'grading_controller'
}
PEER_GRADING_INTERFACE = {
'url': 'http://127.0.0.1:3033/peer_grading',
'username': 'lms',
'password': 'abcd',
}
################################ LMS Migration ################################# ################################ LMS Migration #################################
MITX_FEATURES['ENABLE_LMS_MIGRATION'] = True MITX_FEATURES['ENABLE_LMS_MIGRATION'] = True
MITX_FEATURES['ACCESS_REQUIRE_STAFF_FOR_COURSE'] = False # require that user be in the staff_* group to be able to enroll MITX_FEATURES['ACCESS_REQUIRE_STAFF_FOR_COURSE'] = False # require that user be in the staff_* group to be able to enroll
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment