def to_html(self): # not good to have imports here... from queries import get_question, get_last_question_response, get_peer_tasks_for_grader, get_self_tasks_for_student from auth import validate_user self.set_metadata() user = validate_user() if user.type == "guest": return "Sorry, but only students can view peer assessment questions." vars = {"question": get_question(self.question_id)} # if peer assessment was assigned if len(self.peer_pts): peer_tasks = get_peer_tasks_for_grader(self.question_id, user.stuid) vars['peer_responses'] = [get_last_question_response(self.question_id, task.student) for task in peer_tasks] # if self assessment was assigned if self.self_pts is not None: # add the task if it hasn't been already response = get_last_question_response(self.question_id, user.stuid) if response and not get_self_tasks_for_student(self.question_id, user.stuid): session.add(GradingTask(grader=user.stuid, student=user.stuid, question_id=self.question_id)) session.commit() vars['self_response'] = response # jinja2 to get template for peer review questions from jinja2 import Environment, PackageLoader env = Environment(autoescape=True, loader=PackageLoader("ohms", "templates")) template = env.get_template("peer_review_question.html") return template.render(**vars)
def load_response(self, user): from queries import get_last_question_response last_submission = get_last_question_response(self.id, user.stuid) out = { 'submission': self.delay_feedback(last_submission), 'locked': self.check_if_locked(last_submission), } if user.type == "admin" or (user.type == "student" and pdt_now() > self.homework.due_date): out['solution'] = [item.solution for item in self.items] return out
def submit_response(self, stuid, responses): from queries import get_last_question_response last_submission = get_last_question_response(self.id, stuid) if not self.check_if_locked(last_submission): item_responses = [ItemResponse(item_id=item.id, response=response) \ for item, response in zip(self.items, responses)] score, comments = self.check(responses) question_response = QuestionResponse( stuid=stuid, time=pdt_now(), question_id=self.id, item_responses=item_responses, score=score, comments=comments ) session.add(question_response) session.commit() return { 'submission': self.delay_feedback(question_response), 'locked': self.check_if_locked(question_response), } else: raise Exception("The deadline for submitting this homework has passed.")
def assign_tasks(hw_id, due_date, send_emails=False): homework = session.query(Homework).get(hw_id) users = session.query(User).filter(User.type == "student").order_by(User.stuid).all() for q in homework.questions: # only if this is a peer graded question if not isinstance(q.items[0], LongAnswerItem): continue random.seed(q.id) # setting a seed will be useful for debugging responsible_kids = list() # did the homework! irresponsible_kids = list() # didn't do the homework! # Figure out who did the homework for user in users: if get_last_question_response(q.id, user.stuid): responsible_kids.append(user.stuid) else: irresponsible_kids.append(user.stuid) # Make the assignments for the responsible kids n = len(responsible_kids) random.shuffle(responsible_kids) for i, stuid in enumerate(responsible_kids): # Make the assignments for this responsible student for offset in [1, 3, 6]: j = (i + offset) % n gt = GradingTask(grader=stuid, student=responsible_kids[j], question_id=q.id) session.add(gt) # Make the assignments for the irresponsible kids: # Do so in round robin order, shuffling the responsible students again # to minimize the number of pairs of students grading together. random.shuffle(responsible_kids) for i, stuid in enumerate(irresponsible_kids): # Make the assignments for this irresponsible student for offset in range(3): j = (i * 3 + offset) % n gt = GradingTask(grader=stuid, student=responsible_kids[j], question_id=q.id) session.add(gt) # Make all self-assignments for stuid in (responsible_kids + irresponsible_kids): gt = GradingTask(grader=stuid, student=stuid, question_id=q.id) session.add(gt) session.commit() if not send_emails: return "Successfully assigned %d students" # Send email notifications to all the students send_all(users, "Peer Assessment for %s is Ready" % homework.name[:-1], r"""Dear %s, We've made the peer-grading assignments for this week. The assessments are due {due_date}, and you can start after lecture today at 11:00AM. You will be able to view your peer's comments on your answers as they are submitted, but your score will not be available until {due_date}. At that time, please log in to view and respond to the comments you received from your peers. Best, STATS 60 Staff""".format(due_date=due_date.strftime("%A, %b %d at %I:%M %p"))) # Send email to the course staff admins = session.query(User).filter_by(type="admin").all() send_all(admins, "Peer Assessment for %s is Ready" % homework.name[:-1], r"""Dear %s (and other members of the STATS 60 Staff), Just letting you know that the peer assessment for this week was just released. It is due at {due_date}. Sincerely, OHMS P.S. This is an automatically generated message ;-) """.format(due_date=due_date.strftime("%A, %b %d at %I:%M %p"))) return r'''Successfully assigned %d students. You should have received an e-mail confirmation.''' % len(users)
def update_hw_grades(user, homeworks): """ helper function that computes user's grades on homeworks, returns a list of uncompleted peer reviews """ # keep track of to-do list for peer reviews to_do = defaultdict(int) # keep track of the peer review corresponding to each question prq_map = {} for prq in get_peer_review_questions(): prq.set_metadata() prq_map[prq.question_id] = prq for hw in homeworks: # skip if homework not due yet if hw.due_date > pdt_now(): continue # iterate over questions for q in hw.questions: # check if q is a question that is peer-reviewed if q.id in prq_map: # if grading tasks haven't been assigned if not get_all_peer_tasks(q.id): # get corresponding Peer Review object, instantiate with data from XML prq = prq_map[q.id] # get list of all students who responded, then shuffle responders = [ r.stuid for r in get_all_responses_to_question(q.id) ] import random random.seed(q.id) random.shuffle(responders) # import engine from base import engine # assign peer grading tasks, if applicable # (self grading tasks are assigned individually, on the fly) tasks = [] m, n = len(prq.peer_pts), len(responders) for i, stuid in enumerate(responders): for offset in [ k * (k + 1) / 2 for k in range(1, m + 1) ]: j = (i + offset) % n tasks.append({ "grader": stuid, "student": responders[j], "question_id": q.id }) engine.execute(GradingTask.__table__.insert(), tasks) # if question itself is a peer review question elif isinstance(q, PeerReview): # compute updated score for student response = get_last_question_response(q.question_id, user.stuid) if response: tasks = get_peer_tasks_for_student(q.question_id, user.stuid) scores = [t.score for t in tasks if t.score is not None] new_score = sorted(scores)[len(scores) // 2] if scores else None if response.score is None: response.score = new_score response.comments = "Click <a href='rate?id=%d' target='_blank'>here</a> to view comments." % q.question_id # check that student has rated all the peer reviews for task in tasks: if task.score is not None and task.rating is None: to_do[response.question.homework] += 1 # update student's grade on the homework calculate_grade(user, hw) return to_do
def update_hw_grades(user, homeworks): """ helper function that computes user's grades on homeworks, returns a list of uncompleted peer reviews """ # keep track of to-do list for peer reviews to_do = defaultdict(int) # keep track of the peer review corresponding to each question prq_map = {} for prq in get_peer_review_questions(): prq.set_metadata() prq_map[prq.question_id] = prq for hw in homeworks: # skip if homework not due yet if hw.due_date > pdt_now(): continue # iterate over questions for q in hw.questions: # check if q is a question that is peer-reviewed if q.id in prq_map: # if grading tasks haven't been assigned if not get_all_peer_tasks(q.id): # get corresponding Peer Review object, instantiate with data from XML prq = prq_map[q.id] # get list of all students who responded, then shuffle responders = [r.stuid for r in get_all_responses_to_question(q.id)] import random random.seed(q.id) random.shuffle(responders) # import engine from base import engine # assign peer grading tasks, if applicable # (self grading tasks are assigned individually, on the fly) tasks = [] m, n = len(prq.peer_pts), len(responders) for i, stuid in enumerate(responders): for offset in [k*(k+1)/2 for k in range(1, m+1)]: j = (i + offset) % n tasks.append({"grader": stuid, "student": responders[j], "question_id": q.id}) engine.execute(GradingTask.__table__.insert(), tasks) # if question itself is a peer review question elif isinstance(q, PeerReview): # compute updated score for student response = get_last_question_response(q.question_id, user.stuid) if response: tasks = get_peer_tasks_for_student(q.question_id, user.stuid) scores = [t.score for t in tasks if t.score is not None] new_score = sorted(scores)[len(scores) // 2] if scores else None if response.score is None: response.score = new_score response.comments = "Click <a href='rate?id=%d' target='_blank'>here</a> to view comments." % q.question_id # check that student has rated all the peer reviews for task in tasks: if task.score is not None and task.rating is None: to_do[response.question.homework] += 1 # update student's grade on the homework calculate_grade(user, hw) return to_do