def get(self, course_uuid, assignment_uuid): """ Get answers submitted to the assignment submitted by current user :param course_uuid: :param assignment_uuid: :return: answers """ course = Course.get_active_by_uuid_or_404(course_uuid) assignment = Assignment.get_active_by_uuid_or_404(assignment_uuid) require( READ, Answer(user_id=current_user.id), title="Answers Unavailable", message= "Sorry, your role in this course does not allow you to view answers for this assignment." ) restrict_user = not allow(MANAGE, assignment) params = user_answer_list_parser.parse_args() query = Answer.query \ .options(joinedload('comments')) \ .options(joinedload('file')) \ .options(joinedload('user')) \ .options(joinedload('group')) \ .options(joinedload('score')) \ .filter_by( active=True, assignment_id=assignment.id, course_id=course.id, draft=params.get('draft') ) # get group and individual answers for user if applicable group = current_user.get_course_group(course.id) if group: query = query.filter( or_(Answer.user_id == current_user.id, Answer.group_id == group.id)) # get just individual answers for user else: query = query.filter(Answer.user_id == current_user.id) answers = query.all() on_user_answer_get.send(self, event_name=on_user_answer_get.name, user=current_user, course_id=course.id, data={'assignment_id': assignment.id}) return { "objects": marshal(answers, dataformat.get_answer(restrict_user)) }
def get(self, course_uuid, assignment_uuid): """ Get answers submitted to the assignment submitted by current user :param course_uuid: :param assignment_uuid: :return: answers """ course = Course.get_active_by_uuid_or_404(course_uuid) assignment = Assignment.get_active_by_uuid_or_404(assignment_uuid) require(READ, Answer(user_id=current_user.id), title="Answers Unavailable", message="Sorry, your role in this course does not allow you to view answers for this assignment.") restrict_user = not allow(MANAGE, assignment) params = user_answer_list_parser.parse_args() query = Answer.query \ .options(joinedload('comments')) \ .options(joinedload('file')) \ .options(joinedload('user')) \ .options(joinedload('group')) \ .options(joinedload('score')) \ .filter_by( active=True, assignment_id=assignment.id, course_id=course.id, draft=params.get('draft') ) # get group and individual answers for user if applicable group = current_user.get_course_group(course.id) if group: query = query.filter(or_( Answer.user_id == current_user.id, Answer.group_id == group.id )) # get just individual answers for user else: query = query.filter(Answer.user_id == current_user.id) answers = query.all() on_user_answer_get.send( self, event_name=on_user_answer_get.name, user=current_user, course_id=course.id, data={'assignment_id': assignment.id}) return {"objects": marshal(answers, dataformat.get_answer(restrict_user))}
def post(self, course_uuid, assignment_uuid): course = Course.get_active_by_uuid_or_404(course_uuid) assignment = Assignment.get_active_by_uuid_or_404(assignment_uuid) if not assignment.answer_grace and not allow(MANAGE, assignment): abort( 403, title="Answer Not Submitted", message= "Sorry, the answer deadline has passed. No answers can be submitted after the deadline unless the instructor submits the answer for you." ) require( CREATE, Answer(course_id=course.id), title="Answer Not Submitted", message= "Answers can be submitted only by those enrolled in the course. Please double-check your enrollment in this course." ) restrict_user = not allow(MANAGE, assignment) answer = Answer(assignment_id=assignment.id) params = new_answer_parser.parse_args() answer.content = params.get("content") answer.draft = params.get("draft") file_uuid = params.get('file_id') attachment = None if file_uuid: attachment = File.get_by_uuid_or_404(file_uuid) answer.file_id = attachment.id else: answer.file_id = None # non-drafts must have content if not answer.draft and not answer.content and not file_uuid: abort( 400, title="Answer Not Submitted", message= "Please provide content in the text editor or upload a file and try submitting again." ) user_uuid = params.get("user_id") group_uuid = params.get("group_id") # we allow instructor and TA to submit multiple answers for other users in the class if user_uuid and not allow(MANAGE, Answer(course_id=course.id)): abort( 400, title="Answer Not Submitted", message= "Only instructors and teaching assistants can submit an answer on behalf of another." ) if group_uuid and not assignment.enable_group_answers: abort(400, title="Answer Not Submitted", message="Group answers are not allowed for this assignment.") if group_uuid and not allow(MANAGE, Answer(course_id=course.id)): abort( 400, title="Answer Not Submitted", message= "Only instructors and teaching assistants can submit an answer on behalf of a group." ) if group_uuid and user_uuid: abort( 400, title="Answer Not Submitted", message= "You cannot submit an answer for a user and a group at the same time." ) user = User.get_by_uuid_or_404( user_uuid) if user_uuid else current_user group = Group.get_active_by_uuid_or_404( group_uuid) if group_uuid else None if restrict_user and assignment.enable_group_answers and not group: group = current_user.get_course_group(course.id) if group == None: abort( 400, title="Answer Not Submitted", message= "You are currently not in any group for this course. Please contact your instructor to be added to a group." ) check_for_existing_answers = False if group and assignment.enable_group_answers: if group.course_id != course.id: abort( 400, title="Answer Not Submitted", message= "Group answers can be submitted to courses they belong in." ) answer.user_id = None answer.group_id = group.id answer.comparable = True check_for_existing_answers = True else: answer.user_id = user.id answer.group_id = None course_role = User.get_user_course_role(answer.user_id, course.id) # only system admin can add answers for themselves to a class without being enrolled in it # required for managing comparison examples as system admin if (not course_role or course_role == CourseRole.dropped ) and current_user.system_role != SystemRole.sys_admin: abort( 400, title="Answer Not Submitted", message= "Answers can be submitted only by those enrolled in the course. Please double-check your enrollment in this course." ) if course_role == CourseRole.student and assignment.enable_group_answers: abort( 400, title="Answer Not Submitted", message= "Students can only submit group answers for this assignment." ) # we allow instructor and TA to submit multiple answers for their own, # but not for student. Each student can only have one answer. if course_role and course_role == CourseRole.student: check_for_existing_answers = True answer.comparable = True else: # instructor / TA / Sys Admin can mark the answer as non-comparable, unless the answer is for a student answer.comparable = params.get("comparable") if check_for_existing_answers: # check for answers with user_id or group_id prev_answers = Answer.query \ .filter_by( assignment_id=assignment.id, user_id=answer.user_id, group_id=answer.group_id, active=True ) \ .all() # check if there is a previous answer submitted for the student non_draft_answers = [ prev_answer for prev_answer in prev_answers if not prev_answer.draft ] if len(non_draft_answers) > 0: abort( 400, title="Answer Not Submitted", message= "An answer has already been submitted for this assignment by you or on your behalf." ) # check if there is a previous draft answer submitted for the student (soft-delete if present) draft_answers = [ prev_answer for prev_answer in prev_answers if prev_answer.draft ] for draft_answer in draft_answers: draft_answer.active = False # set submission date if answer is being submitted for the first time if not answer.draft and not answer.submission_date: answer.submission_date = datetime.datetime.utcnow() answer.update_attempt(params.get('attempt_uuid'), params.get('attempt_started', None), params.get('attempt_ended', None)) db.session.add(answer) db.session.commit() on_answer_create.send(self, event_name=on_answer_create.name, user=current_user, course_id=course.id, answer=answer, data=marshal( answer, dataformat.get_answer(restrict_user))) if attachment: on_attach_file.send(self, event_name=on_attach_file.name, user=current_user, course_id=course.id, file=attachment, data={ 'answer_id': answer.id, 'file_id': attachment.id }) # update course & assignment grade for user if answer is fully submitted if not answer.draft: if answer.user: assignment.calculate_grade(answer.user) course.calculate_grade(answer.user) elif answer.group: assignment.calculate_group_grade(answer.group) course.calculate_group_grade(answer.group) return marshal(answer, dataformat.get_answer(restrict_user))
def get(self, course_uuid, assignment_uuid, **kwargs): """ :query string ids: a comma separated comment uuids to query :query string answer_ids: a comma separated answer uuids for answer filter :query string assignment_id: filter the answer comments with a assignment uuid :query string user_ids: a comma separated user uuids that own the comments :query string self_evaluation: indicate whether the result should include self-evaluation comments or self-evaluation only. Possible values: true, false or only. Default true. :query string evaluation: indicate whether the result should include evaluation comments or evaluation only. Possible values: true, false or only. Default true. :query string draft: indicate whether the result should include drafts for current user or not. Possible values: true, false or only. Default false. :reqheader Accept: the response content type depends on :mailheader:`Accept` header :resheader Content-Type: this depends on :mailheader:`Accept` header of request :statuscode 200: no error :statuscode 404: answers don't exist """ course = Course.get_active_by_uuid_or_404(course_uuid) assignment = Assignment.get_active_by_uuid_or_404(assignment_uuid) restrict_user = not allow(MANAGE, assignment) params = answer_comment_list_parser.parse_args() answer_uuids = [] if 'answer_uuid' in kwargs: answer_uuids.append(kwargs['answer_uuid']) elif 'answer_ids' in params and params['answer_ids']: answer_uuids.extend(params['answer_ids'].split(',')) if not answer_uuids and not params['ids'] and not params['assignment_id'] and not params['user_ids']: abort(404, title="Feedback Unavailable", message="There was a problem getting the feedback for this answer. Please try again.") conditions = [] answers = Answer.query \ .filter( Answer.assignment_id == assignment.id, Answer.active == True, Answer.draft == False, Answer.uuid.in_(answer_uuids) ) \ .all() if answer_uuids else [] if answer_uuids and not answers: # non-existing answer ids. abort(404, title="Feedback Unavailable", message="There was a problem getting the feedback for this answer. Please try again.") group = current_user.get_course_group(course.id) course_role = current_user.get_course_role(course.id) # build query condition for each answer for answer in answers: clauses = [AnswerComment.answer_id == answer.id] # student can only see the comments for themselves or public ones. # since the owner of the answer can access all comments. We only filter # on non-owners answer_owner = answer.user_id == current_user.id or (group and group.id == answer.group_id) if course_role == CourseRole.student and not answer_owner: # public comments or comments owned by current user clauses.append(or_( AnswerComment.comment_type == AnswerCommentType.public, AnswerComment.user_id == current_user.id )) conditions.append(and_(*clauses)) query = AnswerComment.query \ .filter( AnswerComment.assignment_id == assignment.id, AnswerComment.active==True, or_(*conditions) ) if params['ids']: query = query.filter(AnswerComment.uuid.in_(params['ids'].split(','))) if params['self_evaluation'] == 'false': # do not include self-evaluation query = query.filter(AnswerComment.comment_type != AnswerCommentType.self_evaluation) elif params['self_evaluation'] == 'only': # only self_evaluation query = query.filter(AnswerComment.comment_type == AnswerCommentType.self_evaluation) if params['evaluation'] == 'false': # do not include evalulation comments query = query.filter(AnswerComment.comment_type != AnswerCommentType.evaluation) elif params['evaluation'] == 'only': # only evaluation query = query.filter(AnswerComment.comment_type == AnswerCommentType.evaluation) if params['draft'] == 'true': # with draft (current_user) query = query.filter(or_( AnswerComment.draft == False, and_( AnswerComment.draft == True, AnswerComment.user_id == current_user.id ) )) elif params['draft'] == 'only': # only draft (current_user) query = query.filter(and_( AnswerComment.draft == True, AnswerComment.user_id == current_user.id )) else: # do not include draft. Default query = query.filter(AnswerComment.draft == False) if params['user_ids']: user_ids = params['user_ids'].split(',') query = query \ .join(User, AnswerComment.user_id == User.id) \ .filter(User.uuid.in_(user_ids)) answer_comments = query.order_by(AnswerComment.created.desc()).all() # checking the permission for answer_comment in answer_comments: require(READ, answer_comment.answer, title="Feedback Unavailable", message="Sorry, your role in this course does not allow you to view feedback for this answer.") on_answer_comment_list_get.send( self, event_name=on_answer_comment_list_get.name, user=current_user, data={'answer_ids': ','.join([str(answer.id) for answer in answers])}) return marshal(answer_comments, dataformat.get_answer_comment(restrict_user))
def get(self, course_uuid): course = Course.get_active_by_uuid_or_404(course_uuid) require(READ, course, title="Assignment Status Unavailable", message="Assignment status can be seen only by those enrolled in the course. Please double-check your enrollment in this course.") group = current_user.get_course_group(course.id) group_id = group.id if group else None assignments = course.assignments \ .filter_by(active=True) \ .all() assignment_ids = [assignment.id for assignment in assignments] answer_counts = Answer.query \ .with_entities( Answer.assignment_id, func.count(Answer.assignment_id).label('answer_count') ) \ .filter_by( comparable=True, active=True, practice=False, draft=False ) \ .filter(or_( Answer.user_id == current_user.id, and_(Answer.group_id == group_id, Answer.group_answer == True) )) \ .filter(Answer.assignment_id.in_(assignment_ids)) \ .group_by(Answer.assignment_id) \ .all() feedback_counts = AnswerComment.query \ .join("answer") \ .with_entities( Answer.assignment_id, func.count(Answer.assignment_id).label('feedback_count') ) \ .filter(and_( AnswerComment.active == True, AnswerComment.draft == False, Answer.active == True, Answer.practice == False, Answer.draft == False, Answer.assignment_id.in_(assignment_ids) )) \ .filter(or_( Answer.user_id == current_user.id, and_(Answer.group_id == group_id, Answer.group_id != None) )) \ .group_by(Answer.assignment_id) \ .all() # get self evaluation status for assignments with self evaluations enabled self_evaluations = AnswerComment.query \ .join("answer") \ .with_entities( Answer.assignment_id, func.count(Answer.assignment_id).label('self_evaluation_count') ) \ .filter(and_( AnswerComment.user_id == current_user.id, AnswerComment.active == True, AnswerComment.comment_type == AnswerCommentType.self_evaluation, AnswerComment.draft == False, Answer.active == True, Answer.practice == False, Answer.draft == False, Answer.assignment_id.in_(assignment_ids) )) \ .group_by(Answer.assignment_id) \ .all() self_evaluation_drafts = AnswerComment.query \ .join("answer") \ .with_entities( Answer.assignment_id, func.count(Answer.assignment_id).label('self_evaluation_count') ) \ .filter(and_( AnswerComment.user_id == current_user.id, AnswerComment.active == True, AnswerComment.comment_type == AnswerCommentType.self_evaluation, AnswerComment.draft == True, Answer.active == True, Answer.practice == False, Answer.draft == False, Answer.assignment_id.in_(assignment_ids) )) \ .group_by(Answer.assignment_id) \ .all() query = Answer.query \ .options(load_only('id', 'assignment_id', 'uuid')) \ .filter_by( active=True, practice=False, draft=True ) \ .filter(or_( and_(Answer.group_id == group_id, Answer.group_id != None), Answer.user_id == current_user.id )) \ .filter(Answer.assignment_id.in_(assignment_ids)) drafts = query.all() statuses = {} for assignment in assignments: answer_count = next( (result.answer_count for result in answer_counts if result.assignment_id == assignment.id), 0 ) feedback_count = next( (result.feedback_count for result in feedback_counts if result.assignment_id == assignment.id), 0 ) assignment_drafts = [draft for draft in drafts if draft.assignment_id == assignment.id] comparison_count = assignment.completed_comparison_count_for_user(current_user.id) comparison_draft_count = assignment.draft_comparison_count_for_user(current_user.id) other_comparable_answers = assignment.comparable_answer_count - answer_count # students can only begin comparing when there there are enough answers submitted that they can do # comparisons without seeing the same answer more than once comparison_available = other_comparable_answers >= assignment.number_of_comparisons * 2 # instructors and tas can compare as long as there are new possible comparisons if allow(EDIT, assignment): comparison_available = comparison_count < other_comparable_answers * (other_comparable_answers - 1) / 2 statuses[assignment.uuid] = { 'answers': { 'answered': answer_count > 0, 'feedback': feedback_count, 'count': answer_count, 'has_draft': len(assignment_drafts) > 0, 'draft_ids': [draft.uuid for draft in assignment_drafts] }, 'comparisons': { 'available': comparison_available, 'count': comparison_count, 'left': max(0, assignment.total_comparisons_required - comparison_count), 'has_draft': comparison_draft_count > 0 } } if assignment.enable_self_evaluation: self_evaluation_count = next( (result.self_evaluation_count for result in self_evaluations if result.assignment_id == assignment.id), 0 ) self_evaluation_draft_count = next( (result.self_evaluation_count for result in self_evaluation_drafts if result.assignment_id == assignment.id), 0 ) statuses[assignment.uuid]['comparisons']['self_evaluation_completed'] = self_evaluation_count > 0 statuses[assignment.uuid]['comparisons']['self_evaluation_draft'] = self_evaluation_draft_count > 0 on_assignment_list_get_status.send( self, event_name=on_assignment_list_get_status.name, user=current_user, course_id=course.id, data=statuses) return {"statuses": statuses}
def get(self, course_uuid): course = Course.get_active_by_uuid_or_404(course_uuid) require(READ, course, title="Assignment Status Unavailable", message="Assignment status can be seen only by those enrolled in the course. Please double-check your enrollment in this course.") group = current_user.get_course_group(course.id) group_id = group.id if group else None assignments = course.assignments \ .filter_by(active=True) \ .all() assignment_ids = [assignment.id for assignment in assignments] answer_counts = Answer.query \ .with_entities( Answer.assignment_id, func.count(Answer.assignment_id).label('answer_count') ) \ .filter_by( comparable=True, active=True, practice=False, draft=False ) \ .filter(or_( Answer.user_id == current_user.id, and_(Answer.group_id == group_id, Answer.group_answer == True) )) \ .filter(Answer.assignment_id.in_(assignment_ids)) \ .group_by(Answer.assignment_id) \ .all() feedback_counts = AnswerComment.query \ .join(Answer) \ .with_entities( Answer.assignment_id, func.count(Answer.assignment_id).label('feedback_count') ) \ .filter(and_( AnswerComment.active == True, AnswerComment.draft == False, Answer.active == True, Answer.practice == False, Answer.draft == False, Answer.assignment_id.in_(assignment_ids) )) \ .filter(or_( Answer.user_id == current_user.id, and_(Answer.group_id == group_id, Answer.group_id != None) )) \ .group_by(Answer.assignment_id) \ .all() # get self evaluation status for assignments with self evaluations enabled self_evaluations = AnswerComment.query \ .join(Answer) \ .with_entities( Answer.assignment_id, func.count(Answer.assignment_id).label('self_evaluation_count') ) \ .filter(and_( AnswerComment.user_id == current_user.id, AnswerComment.active == True, AnswerComment.comment_type == AnswerCommentType.self_evaluation, AnswerComment.draft == False, Answer.active == True, Answer.practice == False, Answer.draft == False, Answer.assignment_id.in_(assignment_ids) )) \ .group_by(Answer.assignment_id) \ .all() self_evaluation_drafts = AnswerComment.query \ .join(Answer) \ .with_entities( Answer.assignment_id, func.count(Answer.assignment_id).label('self_evaluation_count') ) \ .filter(and_( AnswerComment.user_id == current_user.id, AnswerComment.active == True, AnswerComment.comment_type == AnswerCommentType.self_evaluation, AnswerComment.draft == True, Answer.active == True, Answer.practice == False, Answer.draft == False, Answer.assignment_id.in_(assignment_ids) )) \ .group_by(Answer.assignment_id) \ .all() query = Answer.query \ .options(load_only('id', 'assignment_id', 'uuid')) \ .filter_by( active=True, practice=False, draft=True ) \ .filter(or_( and_(Answer.group_id == group_id, Answer.group_id != None), Answer.user_id == current_user.id )) \ .filter(Answer.assignment_id.in_(assignment_ids)) drafts = query.all() statuses = {} for assignment in assignments: answer_count = next( (result.answer_count for result in answer_counts if result.assignment_id == assignment.id), 0 ) feedback_count = next( (result.feedback_count for result in feedback_counts if result.assignment_id == assignment.id), 0 ) assignment_drafts = [draft for draft in drafts if draft.assignment_id == assignment.id] comparison_count = assignment.completed_comparison_count_for_user(current_user.id) comparison_draft_count = assignment.draft_comparison_count_for_user(current_user.id) other_comparable_answers = assignment.comparable_answer_count - answer_count # students can only begin comparing when there there are enough answers submitted that they can do # comparisons without seeing the same answer more than once comparison_available = other_comparable_answers >= assignment.number_of_comparisons * 2 # instructors and tas can compare as long as there are new possible comparisons if can(EDIT, assignment): comparison_available = comparison_count < other_comparable_answers * (other_comparable_answers - 1) / 2 statuses[assignment.uuid] = { 'answers': { 'answered': answer_count > 0, 'feedback': feedback_count, 'count': answer_count, 'has_draft': len(assignment_drafts) > 0, 'draft_ids': [draft.uuid for draft in assignment_drafts] }, 'comparisons': { 'available': comparison_available, 'count': comparison_count, 'left': max(0, assignment.total_comparisons_required - comparison_count), 'has_draft': comparison_draft_count > 0 } } if assignment.enable_self_evaluation: self_evaluation_count = next( (result.self_evaluation_count for result in self_evaluations if result.assignment_id == assignment.id), 0 ) self_evaluation_draft_count = next( (result.self_evaluation_count for result in self_evaluation_drafts if result.assignment_id == assignment.id), 0 ) statuses[assignment.uuid]['comparisons']['self_evaluation_completed'] = self_evaluation_count > 0 statuses[assignment.uuid]['comparisons']['self_evaluation_draft'] = self_evaluation_draft_count > 0 on_assignment_list_get_status.send( self, event_name=on_assignment_list_get_status.name, user=current_user, course_id=course.id, data=statuses) return {"statuses": statuses}
def post(self, course_uuid, assignment_uuid): course = Course.get_active_by_uuid_or_404(course_uuid) assignment = Assignment.get_active_by_uuid_or_404(assignment_uuid) if not assignment.answer_grace and not allow(MANAGE, assignment): abort(403, title="Answer Not Submitted", message="Sorry, the answer deadline has passed. No answers can be submitted after the deadline unless the instructor submits the answer for you.") require(CREATE, Answer(course_id=course.id), title="Answer Not Submitted", message="Answers can be submitted only by those enrolled in the course. Please double-check your enrollment in this course.") restrict_user = not allow(MANAGE, assignment) answer = Answer(assignment_id=assignment.id) params = new_answer_parser.parse_args() answer.content = params.get("content") answer.draft = params.get("draft") file_uuid = params.get('file_id') attachment = None if file_uuid: attachment = File.get_by_uuid_or_404(file_uuid) answer.file_id = attachment.id else: answer.file_id = None # non-drafts must have content if not answer.draft and not answer.content and not file_uuid: abort(400, title="Answer Not Submitted", message="Please provide content in the text editor or upload a file and try submitting again.") user_uuid = params.get("user_id") group_uuid = params.get("group_id") # we allow instructor and TA to submit multiple answers for other users in the class if user_uuid and not allow(MANAGE, Answer(course_id=course.id)): abort(400, title="Answer Not Submitted", message="Only instructors and teaching assistants can submit an answer on behalf of another.") if group_uuid and not assignment.enable_group_answers: abort(400, title="Answer Not Submitted", message="Group answers are not allowed for this assignment.") if group_uuid and not allow(MANAGE, Answer(course_id=course.id)): abort(400, title="Answer Not Submitted", message="Only instructors and teaching assistants can submit an answer on behalf of a group.") if group_uuid and user_uuid: abort(400, title="Answer Not Submitted", message="You cannot submit an answer for a user and a group at the same time.") user = User.get_by_uuid_or_404(user_uuid) if user_uuid else current_user group = Group.get_active_by_uuid_or_404(group_uuid) if group_uuid else None if restrict_user and assignment.enable_group_answers and not group: group = current_user.get_course_group(course.id) if group == None: abort(400, title="Answer Not Submitted", message="You are currently not in any group for this course. Please contact your instructor to be added to a group.") check_for_existing_answers = False if group and assignment.enable_group_answers: if group.course_id != course.id: abort(400, title="Answer Not Submitted", message="Group answers can be submitted to courses they belong in.") answer.user_id = None answer.group_id = group.id answer.comparable = True check_for_existing_answers = True else: answer.user_id = user.id answer.group_id = None course_role = User.get_user_course_role(answer.user_id, course.id) # only system admin can add answers for themselves to a class without being enrolled in it # required for managing comparison examples as system admin if (not course_role or course_role == CourseRole.dropped) and current_user.system_role != SystemRole.sys_admin: abort(400, title="Answer Not Submitted", message="Answers can be submitted only by those enrolled in the course. Please double-check your enrollment in this course.") if course_role == CourseRole.student and assignment.enable_group_answers: abort(400, title="Answer Not Submitted", message="Students can only submit group answers for this assignment.") # we allow instructor and TA to submit multiple answers for their own, # but not for student. Each student can only have one answer. if course_role and course_role == CourseRole.student: check_for_existing_answers = True answer.comparable = True else: # instructor / TA / Sys Admin can mark the answer as non-comparable, unless the answer is for a student answer.comparable = params.get("comparable") if check_for_existing_answers: # check for answers with user_id or group_id prev_answers = Answer.query \ .filter_by( assignment_id=assignment.id, user_id=answer.user_id, group_id=answer.group_id, active=True ) \ .all() # check if there is a previous answer submitted for the student non_draft_answers = [prev_answer for prev_answer in prev_answers if not prev_answer.draft] if len(non_draft_answers) > 0: abort(400, title="Answer Not Submitted", message="An answer has already been submitted for this assignment by you or on your behalf.") # check if there is a previous draft answer submitted for the student (soft-delete if present) draft_answers = [prev_answer for prev_answer in prev_answers if prev_answer.draft] for draft_answer in draft_answers: draft_answer.active = False # set submission date if answer is being submitted for the first time if not answer.draft and not answer.submission_date: answer.submission_date = datetime.datetime.utcnow() answer.update_attempt( params.get('attempt_uuid'), params.get('attempt_started', None), params.get('attempt_ended', None) ) db.session.add(answer) db.session.commit() on_answer_create.send( self, event_name=on_answer_create.name, user=current_user, course_id=course.id, answer=answer, data=marshal(answer, dataformat.get_answer(restrict_user))) if attachment: on_attach_file.send( self, event_name=on_attach_file.name, user=current_user, course_id=course.id, file=attachment, data={'answer_id': answer.id, 'file_id': attachment.id}) # update course & assignment grade for user if answer is fully submitted if not answer.draft: if answer.user: assignment.calculate_grade(answer.user) course.calculate_grade(answer.user) elif answer.group: assignment.calculate_group_grade(answer.group) course.calculate_group_grade(answer.group) return marshal(answer, dataformat.get_answer(restrict_user))