Skip to content

Commit

Permalink
Enables the use of the OpenEdx Pluggable Django App framework
Browse files Browse the repository at this point in the history
  • Loading branch information
Dave St.Germain committed Dec 11, 2018
1 parent 155dc6d commit 2e0be36
Show file tree
Hide file tree
Showing 20 changed files with 273 additions and 157 deletions.
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ parallel = True
source = edx_proctoring
omit =
*/migrations/*
edx_proctoring/settings/*
edx_proctoring/admin.py
10 changes: 4 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,10 @@ help: ## display this help message
@perl -nle'print $& if m{^[a-zA-Z_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m %-25s\033[0m %s\n", $$1, $$2}'

clean: ## remove generated byte code, coverage reports, and build artifacts
find . -name '*.pyc' -exec rm -f {} +
find . -name '*.pyo' -exec rm -f {} +
find . -name '*~' -exec rm -f {} +
rm -fr build/
rm -fr dist/
rm -fr *.egg-info
find . -name '*.pyc' -delete
find . -name '*.pyo' -delete
find . -name '*~' -delete
rm -fr build/ dist/ *.egg-info

upgrade: ## update the requirements/*.txt files with the latest packages satisfying requirements/*.in
pip install -q pip-tools
Expand Down
12 changes: 6 additions & 6 deletions edx_proctoring/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1684,9 +1684,9 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
'progress_page_url': progress_page_url,
'does_time_remain': _does_time_remain(attempt),
'has_time_expired': has_time_expired,
'enter_exam_endpoint': reverse('edx_proctoring.proctored_exam.attempt.collection'),
'enter_exam_endpoint': reverse('edx_proctoring:proctored_exam.attempt.collection'),
'change_state_url': reverse(
'edx_proctoring.proctored_exam.attempt',
'edx_proctoring:proctored_exam.attempt',
args=[attempt['id']]
) if attempt else '',
})
Expand Down Expand Up @@ -1741,17 +1741,17 @@ def _get_proctored_exam_context(exam, attempt, user_id, course_id, is_practice_e
'has_due_date': has_due_date,
'has_due_date_passed': has_due_date_passed(exam['due_date']),
'does_time_remain': _does_time_remain(attempt),
'enter_exam_endpoint': reverse('edx_proctoring.proctored_exam.attempt.collection'),
'enter_exam_endpoint': reverse('edx_proctoring:proctored_exam.attempt.collection'),
'exam_started_poll_url': reverse(
'edx_proctoring.proctored_exam.attempt',
'edx_proctoring:proctored_exam.attempt',
args=[attempt['id']]
) if attempt else '',
'change_state_url': reverse(
'edx_proctoring.proctored_exam.attempt',
'edx_proctoring:proctored_exam.attempt',
args=[attempt['id']]
) if attempt else '',
'update_is_status_acknowledge_url': reverse(
'edx_proctoring.proctored_exam.attempt.review_status',
'edx_proctoring:proctored_exam.attempt.review_status',
args=[attempt['id']]
) if attempt else '',
'link_urls': settings.PROCTORING_SETTINGS.get('LINK_URLS', {}),
Expand Down
22 changes: 21 additions & 1 deletion edx_proctoring/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,27 @@ class EdxProctoringConfig(AppConfig):
Configuration for the edx_proctoring Django application.
"""

name = 'edx_proctoring'
name = u'edx_proctoring'
plugin_app = {
u'url_config': {
u'lms.djangoapp': {
u'namespace': u'edx_proctoring',
u'regex': u'^api/',
u'relative_path': u'urls',
}
},
u'settings_config': {
u'lms.djangoapp': {
u'common': {'relative_path': u'settings.common'},
u'aws': {'relative_path': u'settings.aws'},
},
u'cms.djangoapp': {
u'common': {'relative_path': u'settings.common'},
u'aws': {'relative_path': u'settings.aws'},
}

},
}

def get_backend_choices(self):
"""
Expand Down
4 changes: 4 additions & 0 deletions edx_proctoring/backends/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from webpack_loader.exceptions import BaseWebpackLoaderException, WebpackBundleLookupError

from edx_proctoring.backends.backend import ProctoringBackendProvider
from edx_proctoring.exceptions import BackendProvideCannotRegisterAttempt
from edx_proctoring.statuses import ProctoredExamStudentAttemptStatus
from edx_rest_api_client.client import OAuthAPIClient

Expand Down Expand Up @@ -161,7 +162,10 @@ def register_exam_attempt(self, exam, context):
payload.pop('attempt_code', False)
log.debug('Creating exam attempt for %r at %r', exam['external_id'], url)
response = self.session.post(url, json=payload)
if response.status_code != 200:
raise BackendProvideCannotRegisterAttempt(response.content)
response = response.json()
log.debug(response)
return response['id']

def start_exam_attempt(self, exam, attempt):
Expand Down
2 changes: 1 addition & 1 deletion edx_proctoring/backends/software_secure.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ def _get_payload(self, exam, context):
scheme=scheme,
hostname=settings.SITE_NAME,
path=reverse(
'edx_proctoring.anonymous.proctoring_launch_callback.start_exam',
'edx_proctoring:anonymous.proctoring_launch_callback.start_exam',
args=[attempt_code]
)
)
Expand Down
18 changes: 18 additions & 0 deletions edx_proctoring/backends/tests/test_rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from django.utils import translation

from edx_proctoring.backends.rest import BaseRestProctoringProvider
from edx_proctoring.exceptions import BackendProvideCannotRegisterAttempt


class RESTBackendTests(TestCase):
Expand Down Expand Up @@ -178,6 +179,23 @@ def test_register_exam_attempt(self):
self.assertIn('lms_host', request)
self.assertIn('full_name', request)

@responses.activate
def test_register_exam_attempt_failure(self):
context = {
'attempt_code': '2',
'obs_user_id': 'abcdefghij',
'full_name': 'user name',
'lms_host': 'http://lms.com'
}
responses.add(
responses.POST,
url=self.provider.create_exam_attempt_url.format(exam_id=self.backend_exam['external_id']),
json={'error': 'something'},
status=400
)
with self.assertRaises(BackendProvideCannotRegisterAttempt):
self.provider.register_exam_attempt(self.backend_exam, context)

@responses.activate
def test_start_exam_attempt(self):
attempt_id = 2
Expand Down
4 changes: 2 additions & 2 deletions edx_proctoring/backends/tests/test_software_secure.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def test_allow_simulated_callbacks(self):
external_id='bogus'
)
response = self.client.post(
reverse('edx_proctoring.anonymous.proctoring_review_callback'),
reverse('edx_proctoring:anonymous.proctoring_review_callback'),
data=test_payload,
content_type='application/json'
)
Expand Down Expand Up @@ -212,7 +212,7 @@ def test_missing_attempt_code(self):
external_id='bogus'
)
response = self.client.post(
reverse('edx_proctoring.anonymous.proctoring_review_callback'),
reverse('edx_proctoring:anonymous.proctoring_review_callback'),
data=test_payload,
content_type='application/json'
)
Expand Down
Empty file.
13 changes: 13 additions & 0 deletions edx_proctoring/settings/aws.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"Pluggable Django App settings for production"


def plugin_settings(settings):
"Injects local settings into django settings"
auth_tokens = getattr(settings, 'AUTH_TOKENS', {})
env_tokens = getattr(settings, 'ENV_TOKENS', {})
if env_tokens.get('PROCTORING_SETTINGS'):
settings.PROCTORING_SETTINGS = env_tokens['PROCTORING_SETTINGS']
if auth_tokens.get('PROCTORING_BACKENDS'):
settings.PROCTORING_BACKENDS = auth_tokens['PROCTORING_BACKENDS']
elif env_tokens.get('PROCTORING_BACKENDS'):
settings.PROCTORING_BACKENDS = env_tokens['PROCTORING_BACKENDS']
38 changes: 38 additions & 0 deletions edx_proctoring/settings/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"Common Pluggable Django App settings"


def plugin_settings(settings):
"Injects local settings into django settings"
settings.PROCTORING_SETTINGS = {}
settings.PROCTORING_BACKENDS = {
'DEFAULT': 'null',
'null': {},
}
proctoring_js = (
[
'proctoring/js/models/proctored_exam_allowance_model.js',
'proctoring/js/models/proctored_exam_attempt_model.js',
'proctoring/js/models/proctored_exam_model.js'
] +
[
'proctoring/js/collections/proctored_exam_allowance_collection.js',
'proctoring/js/collections/proctored_exam_attempt_collection.js',
'proctoring/js/collections/proctored_exam_collection.js'
] +
[
'proctoring/js/views/Backbone.ModalDialog.js',
'proctoring/js/views/proctored_exam_add_allowance_view.js',
'proctoring/js/views/proctored_exam_allowance_view.js',
'proctoring/js/views/proctored_exam_attempt_view.js',
'proctoring/js/views/proctored_exam_view.js',
'proctoring/js/views/proctored_exam_instructor_launch.js',
] +
[
'proctoring/js/proctored_app.js',
'proctoring/js/exam_action_handler.js'
]
)
settings.PIPELINE_JS['proctoring'] = {
'source_filenames': proctoring_js,
'output_filename': 'js/lms-proctoring.js',
}
11 changes: 11 additions & 0 deletions edx_proctoring/settings/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"Pluggable Django App settings for test"


def plugin_settings(settings):
"Injects local settings into django settings"
settings.PROCTORING_SETTINGS = {}
settings.PROCTORING_BACKENDS = {
'DEFAULT': 'mock',
'mock': {},
'mock_proctoring_without_rules': {}
}
2 changes: 1 addition & 1 deletion edx_proctoring/tests/test_reviews.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ def test_post_review(self, external_id, status):
if not external_id:
external_id = self.attempt['external_id']
response = self.client.post(
reverse('edx_proctoring.proctored_exam.attempt.callback',
reverse('edx_proctoring:proctored_exam.attempt.callback',
kwargs={'external_id': external_id}),
json.dumps(review),
content_type='application/json'
Expand Down
Loading

0 comments on commit 2e0be36

Please sign in to comment.