def make_review(self, attempt, data, backend=None): """ Save the review and review comments """ attempt_code = attempt['attempt_code'] if not backend: backend = get_backend_provider(attempt['proctored_exam']) # this method should convert the payload into a normalized format backend_review = backend.on_review_callback(attempt, data) # do we already have a review for this attempt?!? We may not allow updates review = ProctoredExamSoftwareSecureReview.get_review_by_attempt_code(attempt_code) if review: if not constants.ALLOW_REVIEW_UPDATES: err_msg = ( 'We already have a review submitted regarding ' 'attempt_code {attempt_code}. We do not allow for updates!'.format( attempt_code=attempt_code ) ) raise ProctoredExamReviewAlreadyExists(err_msg) # we allow updates warn_msg = ( 'We already have a review submitted from our proctoring provider regarding ' 'attempt_code {attempt_code}. We have been configured to allow for ' 'updates and will continue...'.format( attempt_code=attempt_code ) ) LOG.warning(warn_msg) else: # this is first time we've received this attempt_code, so # make a new record in the review table review = ProctoredExamSoftwareSecureReview() # first, validate that the backend review status is valid ReviewStatus.validate(backend_review['status']) # For now, we'll convert the standard review status to the old # software secure review status. # In the future, the old data should be standardized. review.review_status = SoftwareSecureReviewStatus.from_standard_status.get(backend_review['status']) review.attempt_code = attempt_code review.raw_data = json.dumps(data) review.student_id = attempt['user']['id'] review.exam_id = attempt['proctored_exam']['id'] try: review.reviewed_by = get_user_model().objects.get(email=data['reviewed_by']) except (ObjectDoesNotExist, KeyError): review.reviewed_by = None # If the reviewing user is a user in the system (user may be None for automated reviews) and does # not have permission to submit a review, log a warning. course_id = attempt['proctored_exam']['course_id'] if review.reviewed_by is not None and not is_user_course_or_global_staff(review.reviewed_by, course_id): LOG.warning( 'User %(user)s does not have the required permissions to submit ' 'a review for attempt_code %(attempt_code)s.', {'user': review.reviewed_by, 'attempt_code': attempt_code} ) review.save() # go through and populate all of the specific comments for comment in backend_review.get('comments', []): comment = ProctoredExamSoftwareSecureComment( review=review, start_time=comment.get('start', 0), stop_time=comment.get('stop', 0), duration=comment.get('duration', 0), comment=comment['comment'], status=comment['status'] ) comment.save() if review.should_notify: instructor_service = get_runtime_service('instructor') request = get_current_request() if instructor_service and request: course_id = attempt['proctored_exam']['course_id'] exam_id = attempt['proctored_exam']['id'] review_url = request.build_absolute_uri( u'{}?attempt={}'.format( reverse('edx_proctoring:instructor_dashboard_exam', args=[course_id, exam_id]), attempt['external_id'] )) instructor_service.send_support_notification( course_id=attempt['proctored_exam']['course_id'], exam_name=attempt['proctored_exam']['exam_name'], student_username=attempt['user']['username'], review_status=review.review_status, review_url=review_url, )
def make_review(self, attempt, data, backend=None): """ Save the review and review comments """ attempt_code = attempt['attempt_code'] if not backend: backend = get_backend_provider(attempt['proctored_exam']) # this method should convert the payload into a normalized format backend_review = backend.on_review_callback(attempt, data) # do we already have a review for this attempt?!? We may not allow updates review = ProctoredExamSoftwareSecureReview.get_review_by_attempt_code(attempt_code) if review: if not constants.ALLOW_REVIEW_UPDATES: err_msg = ( u'We already have a review submitted regarding ' u'attempt_code {attempt_code}. We do not allow for updates!'.format( attempt_code=attempt_code ) ) raise ProctoredExamReviewAlreadyExists(err_msg) # we allow updates warn_msg = ( u'We already have a review submitted from our proctoring provider regarding ' u'attempt_code {attempt_code}. We have been configured to allow for ' u'updates and will continue...'.format( attempt_code=attempt_code ) ) LOG.warning(warn_msg) else: # this is first time we've received this attempt_code, so # make a new record in the review table review = ProctoredExamSoftwareSecureReview() # first, validate that the backend review status is valid ReviewStatus.validate(backend_review['status']) # For now, we'll convert the standard review status to the old # software secure review status. # In the future, the old data should be standardized. review.review_status = SoftwareSecureReviewStatus.from_standard_status.get(backend_review['status']) review.attempt_code = attempt_code review.raw_data = json.dumps(data) review.student_id = attempt['user']['id'] review.exam_id = attempt['proctored_exam']['id'] try: review.reviewed_by = get_user_model().objects.get(email=data['reviewed_by']) except (ObjectDoesNotExist, KeyError): review.reviewed_by = None # If the reviewing user is a user in the system (user may be None for automated reviews) and does # not have permission to submit a review, log a warning. course_id = attempt['proctored_exam']['course_id'] if review.reviewed_by is not None and not is_user_course_or_global_staff(review.reviewed_by, course_id): LOG.warning( u'User %(user)s does not have the required permissions to submit ' u'a review for attempt_code %(attempt_code)s.', {'user': review.reviewed_by, 'attempt_code': attempt_code} ) review.save() # go through and populate all of the specific comments for comment in backend_review.get('comments', []): comment = ProctoredExamSoftwareSecureComment( review=review, start_time=comment.get('start', 0), stop_time=comment.get('stop', 0), duration=comment.get('duration', 0), comment=comment['comment'], status=comment['status'] ) comment.save() if review.should_notify: instructor_service = get_runtime_service('instructor') request = get_current_request() if instructor_service and request: course_id = attempt['proctored_exam']['course_id'] exam_id = attempt['proctored_exam']['id'] review_url = request.build_absolute_uri( u'{}?attempt={}'.format( reverse('edx_proctoring:instructor_dashboard_exam', args=[course_id, exam_id]), attempt['external_id'] )) instructor_service.send_support_notification( course_id=attempt['proctored_exam']['course_id'], exam_name=attempt['proctored_exam']['exam_name'], student_username=attempt['user']['username'], review_status=review.review_status, review_url=review_url, )
def make_review(self, attempt, data, backend=None): """ Save the review and review comments """ attempt_code = attempt['attempt_code'] if not backend: backend = get_backend_provider(attempt['proctored_exam']) # this method should convert the payload into a normalized format backend_review = backend.on_review_callback(attempt, data) # do we already have a review for this attempt?!? We may not allow updates review = ProctoredExamSoftwareSecureReview.get_review_by_attempt_code(attempt_code) if review: if not constants.ALLOW_REVIEW_UPDATES: err_msg = ( 'We already have a review submitted regarding ' 'attempt_code {attempt_code}. We do not allow for updates!'.format( attempt_code=attempt_code ) ) raise ProctoredExamReviewAlreadyExists(err_msg) # we allow updates warn_msg = ( 'We already have a review submitted from our proctoring provider regarding ' 'attempt_code {attempt_code}. We have been configured to allow for ' 'updates and will continue...'.format( attempt_code=attempt_code ) ) LOG.warning(warn_msg) else: # this is first time we've received this attempt_code, so # make a new record in the review table review = ProctoredExamSoftwareSecureReview() # first, validate that the backend review status is valid ReviewStatus.validate(backend_review['status']) # For now, we'll convert the standard review status to the old # software secure review status. # In the future, the old data should be standardized. review.review_status = SoftwareSecureReviewStatus.from_standard_status.get(backend_review['status']) review.attempt_code = attempt_code review.raw_data = json.dumps(backend_review) review.student_id = attempt['user']['id'] review.exam_id = attempt['proctored_exam']['id'] # set reviewed_by to None because it was reviewed by our 3rd party # service provider, not a user in our database review.reviewed_by = None review.save() # go through and populate all of the specific comments for comment in backend_review.get('comments', []): comment = ProctoredExamSoftwareSecureComment( review=review, start_time=comment.get('start', 0), stop_time=comment.get('stop', 0), duration=comment.get('duration', 0), comment=comment['comment'], status=comment['status'] ) comment.save()