def clear_lesson(self, lesson, write_response=True): from model import Student, StudentActivity from google.appengine.ext import db db.delete(StudentActivity.fetch_all("lesson =", lesson)) db.delete(Student.fetch_all("lesson =", lesson)) self.log_out_all_students(lesson, False); if write_response: self.write_response_plain_text("OK")
def make_student_structure(self, lesson, student=None): # If student is None, then this will return info for all students who # worked on this lesson. from model import Student, StudentActivity if student is not None: students = (student,) filter_key = "student =" filter_value = student else: students = tuple( Student.all().filter("lesson =", lesson) ) # PERFORMANCE: Generator might be inefficient filter_key = "lesson =" filter_value = lesson student_structure = {} if len(students) > 0: num_tasks = len(lesson.tasks) for student in students: tasks_info = [{"searches":[], "answer":{"text":"", "explanation":""}, "history":[]} for _ in range(num_tasks)] student_structure[student.nickname] = { "task_idx" : student.task_idx, "logged_in" : student.is_logged_in, "tasks" : tasks_info } # Policy: Don't report same (query,student,task_idx) more than once. # This dictionary enforces that. searches_dict = {} # (student_nickname,task_idx,link_url) -> ([link_info,...], is_helpful) link_infos_and_ratings = {} activities = StudentActivity.fetch_all(filter_key, filter_value) for activity in activities: student_nickname = activity.student.nickname task_idx = activity.task_idx activity_type = activity.activity_type if activity_type in (StudentActivity.ACTIVITY_TYPE_LINK, StudentActivity.ACTIVITY_TYPE_LINK_RATING, StudentActivity.ACTIVITY_TYPE_SEARCH): link_url = activity.link key = (student_nickname,task_idx,link_url) link_infos_and_rating = link_infos_and_ratings.setdefault(key, [[],None]) if activity_type in (StudentActivity.ACTIVITY_TYPE_LINK, StudentActivity.ACTIVITY_TYPE_SEARCH): query = activity.search search_key = (student_nickname, task_idx, query) try: search_info = searches_dict[search_key] except KeyError: search_info = {"query":query, "links_followed":[]} student_structure[student_nickname]["tasks"][task_idx]["searches"].append(search_info) searches_dict[search_key] = search_info if activity_type==StudentActivity.ACTIVITY_TYPE_LINK: link_title = activity.link_title link_info = {"url":link_url, "title":link_title, "is_helpful":None} search_info["links_followed"].append(link_info) link_infos_and_rating[0].append(link_info) elif activity_type==StudentActivity.ACTIVITY_TYPE_LINK_RATING: link_infos_and_rating[1] = activity.is_helpful elif activity_type==StudentActivity.ACTIVITY_TYPE_ANSWER: # This will end up with the most recent answer because it is in ascending time order, so # later answers will overwrite the older ones. answer_info = student_structure[student_nickname]["tasks"][task_idx]["answer"] answer_info["text"] = activity.answer_text answer_info["explanation"] = activity.answer_explanation student_structure[student_nickname]["tasks"][task_idx]["history"].append(activity) for k,v in link_infos_and_ratings.items(): (student_nickname,task_idx,link_url) = k link_infos, is_helpful = v for link_info in link_infos: link_info["is_helpful"] = is_helpful return student_structure
def _send_tab_delimited_report(self, lesson_code, utc_offset): import StringIO from model import Student, StudentActivity, Lesson import helpers encoding = "UTF-8" lesson = Lesson.get_by_key_name(lesson_code) assert lesson is not None if lesson is None or lesson.teacher_key != self.teacher_key: self.write_response_plain_text("ERROR: Lesson code appears to be incorrect.") else: students = Student.fetch_all("lesson =", lesson) task_titles = tuple(task_info[0] for task_info in lesson.tasks) student_key_to_nickname = dict((s.key().name(), s.nickname) for s in students) activities = StudentActivity.fetch_all("lesson =", lesson) report_buffer = StringIO.StringIO() excel_writer = UnicodeWriter(report_buffer, "excel-tab", "utf8") headers = ( # "Lesson_Code", "Timestamp", "Student", "Task_Number", "Task_Name", "Activity_Type", "Query", "Link_URL", "Link_Title", "Is_Helpful", "Answer_Text", "Answer_Explanation" ) excel_writer.writerow(headers) for activity in activities: student_key = activity.student_key.name() student_nickname = student_key_to_nickname[student_key] timestamp = (activity.timestamp - utc_offset).strftime("%m/%d/%Y %H:%M:%S") task_idx = activity.task_idx task_title = task_titles[task_idx] task_num = task_idx + 1 line_parts = ( # lesson_code, timestamp, student_nickname, task_num, task_title, activity.activity_type, activity.search, activity.link, activity.link_title, activity.is_helpful, activity.answer_text, activity.answer_explanation ) # line_parts = tuple(unicode(p).encode("utf8") for p in line_parts) excel_writer.writerow(line_parts) report_text = report_buffer.getvalue() report_buffer.close() content_type = "text/tab-separated-values" filename = "search_party_lesson_%s_activity_as_of_%s.txt"%(lesson_code, helpers.timestamp()) self.write_response_as_file(encoded_content=report_text, content_type=content_type, filename=filename, encoding=encoding)