Skip to content

Commit

Permalink
Merge pull request #487 from edx/dcs/pluggableapp
Browse files Browse the repository at this point in the history
Enables the use of the Open edX Pluggable Django App framework
  • Loading branch information
davestgermain authored Dec 12, 2018
2 parents 155dc6d + c488ce2 commit 3bad208
Show file tree
Hide file tree
Showing 23 changed files with 272 additions and 164 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
8 changes: 2 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,8 @@ 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' -o -name '*.pyo' -o -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
2 changes: 1 addition & 1 deletion edx_proctoring/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
from __future__ import absolute_import

# Be sure to update the version number in edx_proctoring/package.json
__version__ = '1.5.0rc2'
__version__ = '1.5.0rc3'

default_app_config = 'edx_proctoring.apps.EdxProctoringConfig' # pylint: disable=invalid-name
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 BackendProviderCannotRegisterAttempt
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 BackendProviderCannotRegisterAttempt(response.content)
response = response.json()
log.debug(response)
return response['id']

def start_exam_attempt(self, exam, attempt):
Expand Down
6 changes: 3 additions & 3 deletions edx_proctoring/backends/software_secure.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from edx_proctoring.backends.backend import ProctoringBackendProvider
from edx_proctoring import constants
from edx_proctoring.exceptions import (
BackendProvideCannotRegisterAttempt,
BackendProviderCannotRegisterAttempt,
ProctoredExamSuspiciousLookup,
)
from edx_proctoring.statuses import SoftwareSecureReviewStatus
Expand Down Expand Up @@ -91,7 +91,7 @@ def register_exam_attempt(self, exam, context):
)
)
log.error(err_msg)
raise BackendProvideCannotRegisterAttempt(err_msg)
raise BackendProviderCannotRegisterAttempt(err_msg)

# get the external ID that Software Secure has defined
# for this attempt
Expand Down 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 BackendProviderCannotRegisterAttempt


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(BackendProviderCannotRegisterAttempt):
self.provider.register_exam_attempt(self.backend_exam, context)

@responses.activate
def test_start_exam_attempt(self):
attempt_id = 2
Expand Down
8 changes: 4 additions & 4 deletions edx_proctoring/backends/tests/test_software_secure.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from edx_proctoring.runtime import set_runtime_service

from edx_proctoring.backends import get_backend_provider
from edx_proctoring.exceptions import BackendProvideCannotRegisterAttempt
from edx_proctoring.exceptions import BackendProviderCannotRegisterAttempt
from edx_proctoring import constants

from edx_proctoring.api import (
Expand Down 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 Expand Up @@ -501,7 +501,7 @@ def test_failing_register_attempt(self):

# now try a failing request
with HTTMock(mock_response_error):
with self.assertRaises(BackendProvideCannotRegisterAttempt):
with self.assertRaises(BackendProviderCannotRegisterAttempt):
create_exam_attempt(exam_id, self.user.id, taking_as_proctored=True)

def test_payload_construction(self):
Expand Down
2 changes: 1 addition & 1 deletion edx_proctoring/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class AllowanceValueNotAllowedException(ProctoredBaseException):
"""


class BackendProvideCannotRegisterAttempt(ProctoredBaseException):
class BackendProviderCannotRegisterAttempt(ProctoredBaseException):
"""
Raised when a back-end provider cannot register an attempt
"""
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']
32 changes: 32 additions & 0 deletions edx_proctoring/settings/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"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 3bad208

Please sign in to comment.