Skip to content

Commit

Permalink
Merge pull request #878 from edx/mohtamba/add_post_bulk_allowances_en…
Browse files Browse the repository at this point in the history
…dpoint

Add Post Bulk Allowance Endpoint
  • Loading branch information
mohtamba authored Jun 15, 2021
2 parents 462cd4a + 8f24e8b commit a04db1e
Show file tree
Hide file tree
Showing 10 changed files with 886 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ Change Log
Unreleased
~~~~~~~~~~

[3.15.0] - 2021-06-15
~~~~~~~~~~~~~~~~~~~~~
* Created a POST api endpoint to add allowances for multiple students and multiple exams at the same time.

[3.14.0] - 2021-06-10
~~~~~~~~~~~~~~~~~~~~~
* When an exam attempt is finished for the first time, mark all completable children in the exam as complete
Expand Down
2 changes: 1 addition & 1 deletion edx_proctoring/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"""

# Be sure to update the version number in edx_proctoring/package.json
__version__ = '3.14.0'
__version__ = '3.15.0'

default_app_config = 'edx_proctoring.apps.EdxProctoringConfig' # pylint: disable=invalid-name
121 changes: 121 additions & 0 deletions edx_proctoring/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@
from edx_proctoring import constants
from edx_proctoring.backends import get_backend_provider
from edx_proctoring.exceptions import (
AllowanceValueNotAllowedException,
BackendProviderCannotRegisterAttempt,
BackendProviderNotConfigured,
BackendProviderOnboardingException,
BackendProviderSentNoAttemptID,
ProctoredBaseException,
ProctoredExamAlreadyExists,
ProctoredExamIllegalStatusTransition,
ProctoredExamNotActiveException,
Expand Down Expand Up @@ -494,6 +496,125 @@ def remove_allowance_for_user(exam_id, user_id, key):
emit_event(exam, 'allowance.deleted', override_data=data)


def add_bulk_allowances(exam_ids, user_ids, allowance_type, value):
"""
Adds (or updates) an allowance for multiple users and exams
"""
exam_ids = set(exam_ids)
user_ids = set(user_ids)

# Input validation logic to verify input is acceptable
log_message = (
'Adding allowances of type allowance_type={allowance_type} with value={value} '
'for exams exam_ids={exam_ids} and users user_ids={user_ids}'.format(
allowance_type=allowance_type,
value=value,
exam_ids=exam_ids,
user_ids=user_ids
)
)
log.info(log_message)

multiplier = 0
if allowance_type == constants.TIME_MULTIPLIER:
err_msg = (
u'allowance_value "{value}" should be a float value greater than 1.'
).format(value=value)
try:
multiplier = float(value) - 1
except ValueError as error:
raise AllowanceValueNotAllowedException(err_msg) from error
if multiplier < 0:
raise AllowanceValueNotAllowedException(err_msg)

if allowance_type == constants.ADDITIONAL_TIME:
err_msg = (
u'allowance_value "{value}" should be a non-negative integer value'
).format(value=value)
if not value.isdigit():
raise AllowanceValueNotAllowedException(err_msg)

# Data processing logic to add allowances to the database
successes = 0
failures = 0
data = []
for exam_id in exam_ids:
try:
target_exam = get_exam_by_id(exam_id)
except ProctoredExamNotFoundException:
log_message = (
'Attempted to get exam_id={exam_id}, but this exam does not exist.'.format(exam_id=exam_id)
)
log.error(log_message)
for user_id in user_ids:
failures += 1
data.append({

'exam_id': exam_id,
'user_id': user_id,
})
continue
if allowance_type == constants.TIME_MULTIPLIER:
exam_time = target_exam["time_limit_mins"]
added_time = round(exam_time * multiplier)
time_allowed = str(added_time)
for user_id in user_ids:
try:
add_allowance_for_user(exam_id, user_id,
ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED,
time_allowed)
successes += 1
data.append({

'exam_id': exam_id,
'user_id': user_id,
})

except ProctoredBaseException:
log_message = (
'Failed to add allowance for user_id={user_id} '
'for exam_id={exam_id}'.format(
user_id=user_id,
exam_id=exam_id
)
)
log.error(log_message)
failures += 1
data.append({

'exam_id': exam_id,
'user_id': user_id,
})
else:
for user_id in user_ids:
try:
add_allowance_for_user(exam_id, user_id,
ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED,
value)
successes += 1
data.append({

'exam_id': exam_id,
'user_id': user_id,
})
except ProctoredBaseException:
log_message = (
'Failed to add allowance for user_id={user_id} '
'for exam_id={exam_id}'.format(
user_id=user_id,
exam_id=exam_id
)
)
log.error(log_message)
failures += 1
data.append({

'exam_id': exam_id,
'user_id': user_id,
})
return data, successes, failures


def _check_for_attempt_timeout(attempt):
"""
Helper method to see if the status of an
Expand Down
4 changes: 4 additions & 0 deletions edx_proctoring/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,7 @@
ONBOARDING_PROFILE_API = 'edx_proctoring.onboarding_profile_api'

CONTENT_VIEWABLE_PAST_DUE_DATE = getattr(settings, 'PROCTORED_EXAM_VIEWABLE_PAST_DUE', False)

TIME_MULTIPLIER = 'time_multiplier'

ADDITIONAL_TIME = 'additional_time'
2 changes: 1 addition & 1 deletion edx_proctoring/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class UserNotFoundException(ProctoredBaseException):

class AllowanceValueNotAllowedException(ProctoredBaseException):
"""
Raised when the allowance value is not an non-negative integer
Raised when the allowance value is not an non-negative integer or float
"""


Expand Down
Loading

0 comments on commit a04db1e

Please sign in to comment.