|
43 | 43 | ProctoredBaseException, |
44 | 44 | ProctoredExamNotFoundException, |
45 | 45 | ) |
| 46 | +from edx_proctoring.models import ProctoredExamStudentAllowance |
46 | 47 | from edx_rest_framework_extensions.paginators import DefaultPagination |
47 | 48 | from edx_when import api as edx_when_api |
48 | 49 | from opaque_keys import InvalidKeyError |
@@ -4233,6 +4234,23 @@ def patch(self, request, course_id): |
4233 | 4234 | return Response(serializer.data, status=status.HTTP_200_OK) |
4234 | 4235 |
|
4235 | 4236 |
|
| 4237 | +def add_or_replace_allowance_for_user(exam_id, username_or_email, key, value): |
| 4238 | + """ |
| 4239 | + Add an allowance for a user on an exam, removing any existing allowance with a different key. |
| 4240 | +
|
| 4241 | + Enforces one allowance per user per exam regardless of allowance type. If the user already |
| 4242 | + has an allowance for this exam with a different key, it is removed before the new one is created. |
| 4243 | + """ |
| 4244 | + user_id = get_user_by_username_or_email(username_or_email).id |
| 4245 | + |
| 4246 | + with transaction.atomic(): |
| 4247 | + for allowance in ProctoredExamStudentAllowance.get_allowances_for_user(exam_id, user_id): |
| 4248 | + if allowance.key != key: |
| 4249 | + remove_allowance_for_user(exam_id, user_id, allowance.key) |
| 4250 | + |
| 4251 | + add_allowance_for_user(exam_id, username_or_email, key, value) |
| 4252 | + |
| 4253 | + |
4236 | 4254 | class ExamAllowanceView(DeveloperErrorViewMixin, APIView): |
4237 | 4255 | """ |
4238 | 4256 | Grant, update, or remove an allowance for a student on a proctored exam. |
@@ -4289,17 +4307,17 @@ def post(self, request, course_id, exam_id): |
4289 | 4307 |
|
4290 | 4308 | validated = serializer.validated_data |
4291 | 4309 | results = [] |
4292 | | - for user_info in validated['user_ids']: |
| 4310 | + for username_or_email in validated['user_ids']: |
4293 | 4311 | try: |
4294 | | - add_allowance_for_user( |
| 4312 | + add_or_replace_allowance_for_user( |
4295 | 4313 | int(exam_id), |
4296 | | - user_info, |
| 4314 | + username_or_email, |
4297 | 4315 | validated['allowance_type'], |
4298 | 4316 | validated['value'], |
4299 | 4317 | ) |
4300 | | - results.append({'identifier': user_info, 'success': True}) |
4301 | | - except ProctoredBaseException as err: |
4302 | | - results.append({'identifier': user_info, 'success': False, 'error': str(err)}) |
| 4318 | + results.append({'identifier': username_or_email, 'success': True}) |
| 4319 | + except (ProctoredBaseException, User.DoesNotExist, User.MultipleObjectsReturned) as err: |
| 4320 | + results.append({'identifier': username_or_email, 'success': False, 'error': str(err)}) |
4303 | 4321 |
|
4304 | 4322 | return Response( |
4305 | 4323 | {'allowance_type': validated['allowance_type'], 'results': results}, |
@@ -4471,17 +4489,24 @@ def post(self, request, course_id): |
4471 | 4489 | validated = serializer.validated_data |
4472 | 4490 | results = [] |
4473 | 4491 | for exam_id in validated['exam_ids']: |
4474 | | - for user_info in validated['user_ids']: |
| 4492 | + for username_or_email in validated['user_ids']: |
4475 | 4493 | try: |
4476 | | - add_allowance_for_user( |
| 4494 | + add_or_replace_allowance_for_user( |
4477 | 4495 | exam_id, |
4478 | | - user_info, |
| 4496 | + username_or_email, |
4479 | 4497 | validated['allowance_type'], |
4480 | 4498 | validated['value'], |
4481 | 4499 | ) |
4482 | | - results.append({'identifier': user_info, 'exam_id': exam_id, 'success': True}) |
4483 | | - except ProctoredBaseException as err: |
4484 | | - results.append({'identifier': user_info, 'exam_id': exam_id, 'success': False, 'error': str(err)}) |
| 4500 | + results.append({'identifier': username_or_email, 'exam_id': exam_id, 'success': True}) |
| 4501 | + except (ProctoredBaseException, User.DoesNotExist, User.MultipleObjectsReturned) as err: |
| 4502 | + results.append( |
| 4503 | + { |
| 4504 | + 'identifier': username_or_email, |
| 4505 | + 'exam_id': exam_id, |
| 4506 | + 'success': False, |
| 4507 | + 'error': str(err) |
| 4508 | + } |
| 4509 | + ) |
4485 | 4510 |
|
4486 | 4511 | return Response({ |
4487 | 4512 | 'allowance_type': validated['allowance_type'], |
|
0 commit comments