def reset_score(student_id, course_id, item_id, clear_state=False, emit_signal=True): """ Reset scores for a specific student on a specific problem. Note: this does *not* delete `Score` models from the database, since these are immutable. It simply creates a new score with the "reset" flag set to True. Args: student_id (unicode): The ID of the student for whom to reset scores. course_id (unicode): The ID of the course containing the item to reset. item_id (unicode): The ID of the item for which to reset scores. clear_state (bool): If True, will appear to delete any submissions associated with the specified StudentItem Returns: None Raises: SubmissionInternalError: An unexpected error occurred while resetting scores. """ # Retrieve the student item try: student_item = StudentItem.objects.get(student_id=student_id, course_id=course_id, item_id=item_id) except StudentItem.DoesNotExist: # If there is no student item, then there is no score to reset, # so we can return immediately. return # Create a "reset" score try: score = Score.create_reset_score(student_item) if emit_signal: # Send a signal out to any listeners who are waiting for scoring events. score_reset.send( sender=None, anonymous_user_id=student_id, course_id=course_id, item_id=item_id, created_at=score.created_at, ) if clear_state: for sub in student_item.submission_set.all(): # soft-delete the Submission sub.status = DELETED sub.save(update_fields=["status"]) # Also clear out cached values cache_key = Submission.get_cache_key(sub.uuid) cache.delete(cache_key) except DatabaseError as error: msg = ("Error occurred while reseting scores for" " item {item_id} in course {course_id} for student {student_id}" ).format(item_id=item_id, course_id=course_id, student_id=student_id) logger.exception(msg) raise SubmissionInternalError(msg) from error else: msg = "Score reset for item {item_id} in course {course_id} for student {student_id}".format( item_id=item_id, course_id=course_id, student_id=student_id) logger.info(msg)
def reset_score(student_id, course_id, item_id, clear_state=False, emit_signal=True): """ Reset scores for a specific student on a specific problem. Note: this does *not* delete `Score` models from the database, since these are immutable. It simply creates a new score with the "reset" flag set to True. Args: student_id (unicode): The ID of the student for whom to reset scores. course_id (unicode): The ID of the course containing the item to reset. item_id (unicode): The ID of the item for which to reset scores. clear_state (bool): If True, will appear to delete any submissions associated with the specified StudentItem Returns: None Raises: SubmissionInternalError: An unexpected error occurred while resetting scores. """ # Retrieve the student item try: student_item = StudentItem.objects.get( student_id=student_id, course_id=course_id, item_id=item_id ) except StudentItem.DoesNotExist: # If there is no student item, then there is no score to reset, # so we can return immediately. return # Create a "reset" score try: score = Score.create_reset_score(student_item) if emit_signal: # Send a signal out to any listeners who are waiting for scoring events. score_reset.send( sender=None, anonymous_user_id=student_id, course_id=course_id, item_id=item_id, created_at=score.created_at, ) if clear_state: for sub in student_item.submission_set.all(): # soft-delete the Submission sub.status = Submission.DELETED sub.save(update_fields=["status"]) # Also clear out cached values cache_key = Submission.get_cache_key(sub.uuid) cache.delete(cache_key) except DatabaseError: msg = ( u"Error occurred while reseting scores for" u" item {item_id} in course {course_id} for student {student_id}" ).format(item_id=item_id, course_id=course_id, student_id=student_id) logger.exception(msg) raise SubmissionInternalError(msg) else: msg = u"Score reset for item {item_id} in course {course_id} for student {student_id}".format( item_id=item_id, course_id=course_id, student_id=student_id ) logger.info(msg)
def get_submission(submission_uuid, read_replica=False): """Retrieves a single submission by uuid. Args: submission_uuid (str): Identifier for the submission. Kwargs: read_replica (bool): If true, attempt to use the read replica database. If no read replica is available, use the default database. Raises: SubmissionNotFoundError: Raised if the submission does not exist. SubmissionRequestError: Raised if the search parameter is not a string. SubmissionInternalError: Raised for unknown errors. Examples: >>> get_submission("20b78e0f32df805d21064fc912f40e9ae5ab260d") { 'student_item': 2, 'attempt_number': 1, 'submitted_at': datetime.datetime(2014, 1, 29, 23, 14, 52, 649284, tzinfo=<UTC>), 'created_at': datetime.datetime(2014, 1, 29, 17, 14, 52, 668850, tzinfo=<UTC>), 'answer': u'The answer is 42.' } """ if not isinstance(submission_uuid, str): if isinstance(submission_uuid, UUID): submission_uuid = str(submission_uuid) else: raise SubmissionRequestError( msg= f"submission_uuid ({submission_uuid!r}) must be serializable") cache_key = Submission.get_cache_key(submission_uuid) try: cached_submission_data = cache.get(cache_key) except Exception: # pylint: disable=broad-except # The cache backend could raise an exception # (for example, memcache keys that contain spaces) logger.exception( "Error occurred while retrieving submission from the cache") cached_submission_data = None if cached_submission_data: logger.info("Get submission %s (cached)", submission_uuid) return cached_submission_data try: submission = _get_submission_model(submission_uuid, read_replica) submission_data = SubmissionSerializer(submission).data cache.set(cache_key, submission_data) except Submission.DoesNotExist as error: logger.error("Submission %s not found.", submission_uuid) raise SubmissionNotFoundError( f"No submission matching uuid {submission_uuid}") from error except Exception as exc: # Something very unexpected has just happened (like DB misconfig) err_msg = f"Could not get submission due to error: {exc}" logger.exception(err_msg) raise SubmissionInternalError(err_msg) from exc logger.info("Get submission %s", submission_uuid) return submission_data
def get_submission(submission_uuid, read_replica=False): """Retrieves a single submission by uuid. Args: submission_uuid (str): Identifier for the submission. Kwargs: read_replica (bool): If true, attempt to use the read replica database. If no read replica is available, use the default database. Raises: SubmissionNotFoundError: Raised if the submission does not exist. SubmissionRequestError: Raised if the search parameter is not a string. SubmissionInternalError: Raised for unknown errors. Examples: >>> get_submission("20b78e0f32df805d21064fc912f40e9ae5ab260d") { 'student_item': 2, 'attempt_number': 1, 'submitted_at': datetime.datetime(2014, 1, 29, 23, 14, 52, 649284, tzinfo=<UTC>), 'created_at': datetime.datetime(2014, 1, 29, 17, 14, 52, 668850, tzinfo=<UTC>), 'answer': u'The answer is 42.' } """ if not isinstance(submission_uuid, six.string_types): if isinstance(submission_uuid, UUID): submission_uuid = six.text_type(submission_uuid) else: raise SubmissionRequestError( msg="submission_uuid ({!r}) must be serializable".format(submission_uuid) ) cache_key = Submission.get_cache_key(submission_uuid) try: cached_submission_data = cache.get(cache_key) except Exception: # The cache backend could raise an exception # (for example, memcache keys that contain spaces) logger.exception("Error occurred while retrieving submission from the cache") cached_submission_data = None if cached_submission_data: logger.info("Get submission {} (cached)".format(submission_uuid)) return cached_submission_data try: submission = _get_submission_model(submission_uuid, read_replica) submission_data = SubmissionSerializer(submission).data cache.set(cache_key, submission_data) except Submission.DoesNotExist: logger.error("Submission {} not found.".format(submission_uuid)) raise SubmissionNotFoundError( u"No submission matching uuid {}".format(submission_uuid) ) except Exception as exc: # Something very unexpected has just happened (like DB misconfig) err_msg = "Could not get submission due to error: {}".format(exc) logger.exception(err_msg) raise SubmissionInternalError(err_msg) logger.info("Get submission {}".format(submission_uuid)) return submission_data