def remove_step(step): """Function to remove a manual evaluation step and perform related tasks""" evaluator_key = db.Key.from_path(course_staff.CourseStaff.kind(), step.evaluator) evaluator, summary = entities.get( [evaluator_key, step.manual_evaluation_summary_key]) if summary: summary.decrement_count(step.state) else: manage.COUNTER_DELETE_REVIEWER_SUMMARY_MISS.inc() step.removed = True if evaluator: evaluator.num_assigned -= 1 entities.put([entity for entity in [step, summary, evaluator] if entity])
def _transition_state_to_expired(cls, review_step_key): step = entities.get(review_step_key) if not step: COUNTER_EXPIRE_REVIEW_STEP_MISS.inc() raise KeyError('No review step found with key %s' % repr(review_step_key)) if step.removed: COUNTER_EXPIRE_REVIEW_CANNOT_TRANSITION.inc() raise domain.RemovedError( 'Cannot transition step %s' % repr(review_step_key), step.removed) if step.state in (domain.REVIEW_STATE_COMPLETED, domain.REVIEW_STATE_EXPIRED): COUNTER_EXPIRE_REVIEW_CANNOT_TRANSITION.inc() raise domain.TransitionError( 'Cannot transition step %s' % repr(review_step_key), step.state, domain.REVIEW_STATE_EXPIRED) summary = entities.get(step.review_summary_key) if not summary: COUNTER_EXPIRE_REVIEW_SUMMARY_MISS.inc() raise KeyError('No review summary found with key %s' % repr(step.review_summary_key)) summary.decrement_count(step.state) step.state = domain.REVIEW_STATE_EXPIRED summary.increment_count(step.state) return entities.put([step, summary])[0]
def _add_new_reviewer(cls, unit_id, submission_key, reviewee_key, reviewer_key): summary = peer.ReviewSummary(assigned_count=1, reviewee_key=reviewee_key, submission_key=submission_key, unit_id=unit_id) # Synthesize summary key to avoid a second synchronous put op. summary_key = db.Key.from_path( peer.ReviewSummary.kind(), peer.ReviewSummary.key_name(submission_key)) step = peer.ReviewStep(assigner_kind=domain.ASSIGNER_KIND_HUMAN, review_summary_key=summary_key, reviewee_key=reviewee_key, reviewer_key=reviewer_key, state=domain.REVIEW_STATE_ASSIGNED, submission_key=submission_key, unit_id=unit_id) # pylint: disable=unbalanced-tuple-unpacking,unpacking-non-sequence step_key, written_summary_key = entities.put([step, summary]) if summary_key != written_summary_key: COUNTER_ADD_REVIEWER_BAD_SUMMARY_KEY.inc() raise AssertionError('Synthesized invalid review summary key %s' % repr(summary_key)) COUNTER_ADD_REVIEWER_CREATE_REVIEW_STEP.inc() return step_key
def _transition_state_to_expired(cls, review_step_key): step = entities.get(review_step_key) if not step: COUNTER_EXPIRE_REVIEW_STEP_MISS.inc() raise KeyError( 'No review step found with key %s' % repr(review_step_key)) if step.removed: COUNTER_EXPIRE_REVIEW_CANNOT_TRANSITION.inc() raise domain.RemovedError( 'Cannot transition step %s' % repr(review_step_key), step.removed) if step.state in ( domain.REVIEW_STATE_COMPLETED, domain.REVIEW_STATE_EXPIRED): COUNTER_EXPIRE_REVIEW_CANNOT_TRANSITION.inc() raise domain.TransitionError( 'Cannot transition step %s' % repr(review_step_key), step.state, domain.REVIEW_STATE_EXPIRED) summary = entities.get(step.review_summary_key) if not summary: COUNTER_EXPIRE_REVIEW_SUMMARY_MISS.inc() raise KeyError( 'No review summary found with key %s' % repr( step.review_summary_key)) summary.decrement_count(step.state) step.state = domain.REVIEW_STATE_EXPIRED summary.increment_count(step.state) return entities.put([step, summary])[0]
def bulk_score_by_course(cls, course, csv_list, errors): """ Bulk score assessments by email. csv list should be of the following format: [ [email, assessment_id, score], . . ] """ students = [] student_ids = [entry[0].strip() for entry in csv_list] students = models.StudentProfileDAO.bulk_get_student_by_email( student_ids) modified_students = [] for i, entry in enumerate(csv_list): if len(entry) != 3: if len(entry) >= 1: errors.append('Invalid row %s' % ','.join(entry)) continue assessment_id = entry[1].strip() try: score = float(entry[2]) except ValueError: errors.append('Invalid row %s' % ','.join(entry)) continue student = students[i] if student: if not cls.score(student, course, assessment_id, score, errors): errors.append('Failed to score: %s, %s, %s' % (student.email, assessment_id, score)) else: modified_students.append(student) else: errors.append('Student not found %s' % student_ids[i]) # Bulk save the students entities.put(modified_students)
def reshare_submission_with_evaluator(step): """Function to share the step's submission contents with the course staff""" unit_id = step.unit_id namespace = namespace_manager.get_namespace() if namespace: app_context = sites.get_app_context_for_namespace(namespace) if app_context: course = courses.Course.get(app_context) if course: unit = course.find_unit_by_id(unit_id) if unit: content = ( question.SubjectiveAssignmentBaseHandler.get_content( course, unit)) if question.SubjectiveAssignmentBaseHandler.BLOB != ( content.get( question.SubjectiveAssignmentBaseHandler. OPT_QUESTION_TYPE)): # Not a drive type submission, skip. return if transforms.loads(step.drive_permission_list): # Permission list already present, skip. return evaluator = course_staff.CourseStaff.get_by_key_name( step.evaluator) submission_key = step.submission_key submission_contents = ( manage.Manager.get_submission_contents_dict( submission_key)) if submission_contents and evaluator: drive_permission_list_dump = transforms.dumps( manage.Manager.share_submission_with_evaluator( submission_contents, evaluator.email)) step.drive_permission_list = drive_permission_list_dump entities.put([step]) return logging.error('Invalid evaluator or submission for step ' + step.key().name()) return logging.error('Could not load unit for step ' + step.key())
def _add_reviewer_update_step(cls, step): should_increment_human = False should_increment_reassigned = False should_increment_unremoved = False summary = entities.get(step.review_summary_key) if not summary: COUNTER_ADD_REVIEWER_BAD_SUMMARY_KEY.inc() raise AssertionError( 'Found invalid review summary key %s' % repr( step.review_summary_key)) if not step.removed: if step.state == domain.REVIEW_STATE_EXPIRED: should_increment_reassigned = True step.state = domain.REVIEW_STATE_ASSIGNED summary.decrement_count(domain.REVIEW_STATE_EXPIRED) summary.increment_count(domain.REVIEW_STATE_ASSIGNED) elif (step.state == domain.REVIEW_STATE_ASSIGNED or step.state == domain.REVIEW_STATE_COMPLETED): COUNTER_ADD_REVIEWER_UNREMOVED_STEP_FAILED.inc() raise domain.TransitionError( 'Unable to add new reviewer to step %s' % ( repr(step.key())), step.state, domain.REVIEW_STATE_ASSIGNED) else: should_increment_unremoved = True step.removed = False if step.state != domain.REVIEW_STATE_EXPIRED: summary.increment_count(step.state) else: should_increment_reassigned = True step.state = domain.REVIEW_STATE_ASSIGNED summary.decrement_count(domain.REVIEW_STATE_EXPIRED) summary.increment_count(domain.REVIEW_STATE_ASSIGNED) if step.assigner_kind != domain.ASSIGNER_KIND_HUMAN: should_increment_human = True step.assigner_kind = domain.ASSIGNER_KIND_HUMAN step_key = entities.put([step, summary])[0] if should_increment_human: COUNTER_ADD_REVIEWER_SET_ASSIGNER_KIND_HUMAN.inc() if should_increment_reassigned: COUNTER_ADD_REVIEWER_EXPIRED_STEP_REASSIGNED.inc() if should_increment_unremoved: COUNTER_ADD_REVIEWER_REMOVED_STEP_UNREMOVED.inc() return step_key
def _attempt_review_assignment(cls, review_summary_key, reviewer_key, last_change_date): COUNTER_GET_NEW_REVIEW_ASSIGNMENT_ATTEMPTED.inc() summary = entities.get(review_summary_key) if not summary: raise KeyError('No review summary found with key %s' % repr(review_summary_key)) if summary.change_date != last_change_date: # The summary has changed since we queried it. We cannot know for # sure what the edit was, but let's skip to the next one because it # was probably a review assignment. COUNTER_GET_NEW_REVIEW_SUMMARY_CHANGED.inc() return step = peer.ReviewStep.get_by_key_name( peer.ReviewStep.key_name(summary.submission_key, reviewer_key)) if not step: step = peer.ReviewStep(assigner_kind=domain.ASSIGNER_KIND_AUTO, review_summary_key=summary.key(), reviewee_key=summary.reviewee_key, reviewer_key=reviewer_key, state=domain.REVIEW_STATE_ASSIGNED, submission_key=summary.submission_key, unit_id=summary.unit_id) else: if step.state == domain.REVIEW_STATE_COMPLETED: # Reviewer has previously done this review and the review # has been deleted. Skip to the next one. COUNTER_GET_NEW_REVIEW_CANNOT_UNREMOVE_COMPLETED.inc() return if step.removed: # We can reassign the existing review step. COUNTER_GET_NEW_REVIEW_REASSIGN_EXISTING.inc() step.removed = False step.assigner_kind = domain.ASSIGNER_KIND_AUTO step.state = domain.REVIEW_STATE_ASSIGNED else: # Reviewee has already reviewed or is already assigned to review # this submission, so we cannot reassign the step. COUNTER_GET_NEW_REVIEW_ALREADY_ASSIGNED.inc() return summary.increment_count(domain.REVIEW_STATE_ASSIGNED) return entities.put([step, summary])[0]
def _attempt_review_assignment( cls, review_summary_key, reviewer_key, last_change_date): COUNTER_GET_NEW_REVIEW_ASSIGNMENT_ATTEMPTED.inc() summary = entities.get(review_summary_key) if not summary: raise KeyError('No review summary found with key %s' % repr( review_summary_key)) if summary.change_date != last_change_date: # The summary has changed since we queried it. We cannot know for # sure what the edit was, but let's skip to the next one because it # was probably a review assignment. COUNTER_GET_NEW_REVIEW_SUMMARY_CHANGED.inc() return step = peer.ReviewStep.get_by_key_name( peer.ReviewStep.key_name(summary.submission_key, reviewer_key)) if not step: step = peer.ReviewStep( assigner_kind=domain.ASSIGNER_KIND_AUTO, review_summary_key=summary.key(), reviewee_key=summary.reviewee_key, reviewer_key=reviewer_key, state=domain.REVIEW_STATE_ASSIGNED, submission_key=summary.submission_key, unit_id=summary.unit_id) else: if step.state == domain.REVIEW_STATE_COMPLETED: # Reviewer has previously done this review and the review # has been deleted. Skip to the next one. COUNTER_GET_NEW_REVIEW_CANNOT_UNREMOVE_COMPLETED.inc() return if step.removed: # We can reassign the existing review step. COUNTER_GET_NEW_REVIEW_REASSIGN_EXISTING.inc() step.removed = False step.assigner_kind = domain.ASSIGNER_KIND_AUTO step.state = domain.REVIEW_STATE_ASSIGNED else: # Reviewee has already reviewed or is already assigned to review # this submission, so we cannot reassign the step. COUNTER_GET_NEW_REVIEW_ALREADY_ASSIGNED.inc() return summary.increment_count(domain.REVIEW_STATE_ASSIGNED) return entities.put([step, summary])[0]
def _mark_review_step_removed(cls, review_step_key): step = entities.get(review_step_key) if not step: COUNTER_DELETE_REVIEWER_STEP_MISS.inc() raise KeyError('No review step found with key %s' % repr(review_step_key)) if step.removed: COUNTER_DELETE_REVIEWER_ALREADY_REMOVED.inc() raise domain.RemovedError( 'Cannot remove step %s' % repr(review_step_key), step.removed) summary = entities.get(step.review_summary_key) if not summary: COUNTER_DELETE_REVIEWER_SUMMARY_MISS.inc() raise KeyError('No review summary found with key %s' % repr(step.review_summary_key)) step.removed = True summary.decrement_count(step.state) return entities.put([step, summary])[0]
def _mark_review_step_removed(cls, review_step_key): step = entities.get(review_step_key) if not step: COUNTER_DELETE_REVIEWER_STEP_MISS.inc() raise KeyError( 'No review step found with key %s' % repr(review_step_key)) if step.removed: COUNTER_DELETE_REVIEWER_ALREADY_REMOVED.inc() raise domain.RemovedError( 'Cannot remove step %s' % repr(review_step_key), step.removed) summary = entities.get(step.review_summary_key) if not summary: COUNTER_DELETE_REVIEWER_SUMMARY_MISS.inc() raise KeyError( 'No review summary found with key %s' % repr( step.review_summary_key)) step.removed = True summary.decrement_count(step.state) return entities.put([step, summary])[0]
def _add_new_reviewer( cls, unit_id, submission_key, reviewee_key, reviewer_key): summary = peer.ReviewSummary( assigned_count=1, reviewee_key=reviewee_key, submission_key=submission_key, unit_id=unit_id) # Synthesize summary key to avoid a second synchronous put op. summary_key = db.Key.from_path( peer.ReviewSummary.kind(), peer.ReviewSummary.key_name(submission_key)) step = peer.ReviewStep( assigner_kind=domain.ASSIGNER_KIND_HUMAN, review_summary_key=summary_key, reviewee_key=reviewee_key, reviewer_key=reviewer_key, state=domain.REVIEW_STATE_ASSIGNED, submission_key=submission_key, unit_id=unit_id) step_key, written_summary_key = entities.put([step, summary]) if summary_key != written_summary_key: COUNTER_ADD_REVIEWER_BAD_SUMMARY_KEY.inc() raise AssertionError( 'Synthesized invalid review summary key %s' % repr(summary_key)) COUNTER_ADD_REVIEWER_CREATE_REVIEW_STEP.inc() return step_key
def _update_review_contents_and_change_state(cls, review_step_key, review_payload, mark_completed): should_increment_created_new_review = False should_increment_updated_existing_review = False should_increment_assigned_to_completed = False should_increment_expired_to_completed = False step = entities.get(review_step_key) if not step: COUNTER_WRITE_REVIEW_STEP_MISS.inc() raise KeyError('No review step found with key %s' % repr(review_step_key)) elif step.removed: raise domain.RemovedError( 'Unable to process step %s' % repr(step.key()), step.removed) elif mark_completed and step.state == domain.REVIEW_STATE_COMPLETED: raise domain.TransitionError( 'Unable to transition step %s' % repr(step.key()), step.state, domain.REVIEW_STATE_COMPLETED) if step.review_key: review_to_update = entities.get(step.review_key) if review_to_update: should_increment_updated_existing_review = True else: review_to_update = student_work.Review( contents=review_payload, reviewee_key=step.reviewee_key, reviewer_key=step.reviewer_key, unit_id=step.unit_id) step.review_key = db.Key.from_path( student_work.Review.kind(), student_work.Review.key_name(step.unit_id, step.reviewee_key, step.reviewer_key)) should_increment_created_new_review = True if not review_to_update: COUNTER_WRITE_REVIEW_REVIEW_MISS.inc() raise domain.ConstraintError('No review found with key %s' % repr(step.review_key)) summary = entities.get(step.review_summary_key) if not summary: COUNTER_WRITE_REVIEW_SUMMARY_MISS.inc() raise domain.ConstraintError( 'No review summary found with key %s' % repr(step.review_summary_key)) review_to_update.contents = review_payload updated_step_key = None if not mark_completed: # pylint: disable=unbalanced-tuple-unpacking,unpacking-non-sequence _, updated_step_key = entities.put([review_to_update, step]) else: if step.state == domain.REVIEW_STATE_ASSIGNED: should_increment_assigned_to_completed = True elif step.state == domain.REVIEW_STATE_EXPIRED: should_increment_expired_to_completed = True summary.decrement_count(step.state) step.state = domain.REVIEW_STATE_COMPLETED summary.increment_count(step.state) # pylint: disable=unbalanced-tuple-unpacking,unpacking-non-sequence _, updated_step_key, _ = entities.put( [review_to_update, step, summary]) if should_increment_created_new_review: COUNTER_WRITE_REVIEW_CREATED_NEW_REVIEW.inc() elif should_increment_updated_existing_review: COUNTER_WRITE_REVIEW_UPDATED_EXISTING_REVIEW.inc() if should_increment_assigned_to_completed: COUNTER_WRITE_REVIEW_COMPLETED_ASSIGNED_STEP.inc() elif should_increment_expired_to_completed: COUNTER_WRITE_REVIEW_COMPLETED_EXPIRED_STEP.inc() return updated_step_key
def _update_review_contents_and_change_state( cls, review_step_key, review_payload, mark_completed): should_increment_created_new_review = False should_increment_updated_existing_review = False should_increment_assigned_to_completed = False should_increment_expired_to_completed = False step = entities.get(review_step_key) if not step: COUNTER_WRITE_REVIEW_STEP_MISS.inc() raise KeyError( 'No review step found with key %s' % repr(review_step_key)) elif step.removed: raise domain.RemovedError( 'Unable to process step %s' % repr(step.key()), step.removed) elif mark_completed and step.state == domain.REVIEW_STATE_COMPLETED: raise domain.TransitionError( 'Unable to transition step %s' % repr(step.key()), step.state, domain.REVIEW_STATE_COMPLETED) if step.review_key: review_to_update = entities.get(step.review_key) if review_to_update: should_increment_updated_existing_review = True else: review_to_update = student_work.Review( contents=review_payload, reviewee_key=step.reviewee_key, reviewer_key=step.reviewer_key, unit_id=step.unit_id) step.review_key = db.Key.from_path( student_work.Review.kind(), student_work.Review.key_name( step.unit_id, step.reviewee_key, step.reviewer_key)) should_increment_created_new_review = True if not review_to_update: COUNTER_WRITE_REVIEW_REVIEW_MISS.inc() raise domain.ConstraintError( 'No review found with key %s' % repr(step.review_key)) summary = entities.get(step.review_summary_key) if not summary: COUNTER_WRITE_REVIEW_SUMMARY_MISS.inc() raise domain.ConstraintError( 'No review summary found with key %s' % repr( step.review_summary_key)) review_to_update.contents = review_payload updated_step_key = None if not mark_completed: # pylint: disable=unbalanced-tuple-unpacking,unpacking-non-sequence _, updated_step_key = entities.put([review_to_update, step]) else: if step.state == domain.REVIEW_STATE_ASSIGNED: should_increment_assigned_to_completed = True elif step.state == domain.REVIEW_STATE_EXPIRED: should_increment_expired_to_completed = True summary.decrement_count(step.state) step.state = domain.REVIEW_STATE_COMPLETED summary.increment_count(step.state) # pylint: disable=unbalanced-tuple-unpacking,unpacking-non-sequence _, updated_step_key, _ = entities.put( [review_to_update, step, summary]) if should_increment_created_new_review: COUNTER_WRITE_REVIEW_CREATED_NEW_REVIEW.inc() elif should_increment_updated_existing_review: COUNTER_WRITE_REVIEW_UPDATED_EXISTING_REVIEW.inc() if should_increment_assigned_to_completed: COUNTER_WRITE_REVIEW_COMPLETED_ASSIGNED_STEP.inc() elif should_increment_expired_to_completed: COUNTER_WRITE_REVIEW_COMPLETED_EXPIRED_STEP.inc() return updated_step_key