Exemplo n.º 1
0
 def get_lesson_json(self, lesson_code):
     from model import Lesson
     import json
     import datetime
         
     def handler(o):
         if isinstance(o, datetime.datetime):
             return "(new Date(%d, %d, %d, %d, %d, %d))"%(
                     o.year,
                     o.month,  
                     o.day,
                     o.hour,
                     o.minute,
                     o.second)
         else:
             raise TypeError(repr(o))
 
     lesson = Lesson.get_by_key_name(lesson_code)
     lesson_info = []
     if not lesson.is_deleted:
         lesson_info.append({
             "lesson_code" : lesson.lesson_code,
             "title" : lesson.title,
             "description" : lesson.description,
             "class_name" : lesson.class_name,
             "start_time" : lesson.start_time,
             "stop_time" : lesson.stop_time,
             "tasks" : lesson.tasks,
             "is_active" : lesson.is_active
         })
     lesson_json = json.dumps(lesson_info, default=handler)
     return lesson_json
Exemplo n.º 2
0
 def make_lesson_code(self):
     import random
     from model import Lesson
     digits = 5
     
     # This is essentially a do loop, but I'm using a generous upper bound to prevent the
     # possibility of an endless (and potentially costly) spin, in case of a bug, for example.
     for i in range(1000):
         assert i < 1000 - 1, "Looks like infinite loop."
         n = random.randint(0,10**digits - 1)
         lesson_code = "%05d"%n
         lesson = Lesson.get_by_key_name(lesson_code)
         if lesson is None:
             break
     return lesson_code
Exemplo n.º 3
0
    def get(self):
        self.load_search_party_context(user_type="teacher")

        try:
            if not self.is_teacher:
                raise NotAnAuthenticatedTeacherError()
            
            else:
                lesson = None
                form_item = lambda key:self.request.get(key, "").strip()
                if form_item is not None:
                    lesson_code = form_item("lesson_code")
                    if lesson_code != "":
                        from model import Lesson
                        lesson = Lesson.get_by_key_name(lesson_code)       
                    action = form_item("action")
                if action=="create":
                    self.create_edit_lesson(form_item)
                elif action=="clone":
                    self.clone_lesson(lesson)
                elif action=="edit":
                    self.create_edit_lesson(form_item)
                elif action=="start":
                    self.start_lesson(lesson)  
                elif action=="stop":
                    self.stop_lesson(lesson)
                elif action=="stopall":
                    self.stop_all_lessons()
                elif action=="clear":
                    self.clear_lesson(lesson)
                elif action=="delete":
                    self.delete_lesson(lesson)
                elif action=="deleteall":
                    self.delete_all_lessons()
                elif action=="logoutstudent":
                    from model import Student
                    student_nickname = form_item("student_nickname")
                    student_key = "::".join((student_nickname, lesson_code))
                    student = Student.get_by_key_name(student_key)
                    self.log_out_student(student)
                elif action=="logoutallstudents":
                    self.log_out_all_students(lesson)
                else:
                    self.show_dashboard()

        except NotAnAuthenticatedTeacherError:
            self.redirect_to_teacher_login()
 def post(self):
     from helpers import log
     self.load_user()
     self.person.add_client_id(self.client_id)
     if self.person_type=="student" and len(self.person.client_ids)==1:
         self.person.latest_logout_timestamp = None
     self.person.put()
     
     log("=> CHANNEL CONNECTED: {0} ({1})".format(str(self.client_id),len(self.person.client_ids)))
             
     if self.person_type=="student" and len(self.person.client_ids)==1:
         from client_id_utils import lesson_code_for_client_id
         from model import Lesson
         from updates import send_update_log_in
         lesson_code = lesson_code_for_client_id(self.client_id)
         lesson = Lesson.get_by_key_name(lesson_code)
         send_update_log_in(student=self.person, teacher=lesson.teacher)
Exemplo n.º 5
0
    def get(self, lesson_code):

        self.load_search_party_context(user_type="teacher")

        try:
            from model import Lesson
            import json
            import settings
            
            if not self.is_teacher:
                raise NotAnAuthenticatedTeacherError()

            lesson = Lesson.get_by_key_name(lesson_code)
            if lesson is None:
                raise LessonNotFoundError()
            if lesson.teacher_key != self.teacher_key:
                raise WrongTeacherError()

            teacher = self.person
            person_key = teacher.user.user_id();
            token = self.create_channel(person_key=person_key, lesson_code=lesson_code)
            default_start_pane = "students"

            template_values = {
                'header'             : self.gen_header("teacher"),
                'token'              : token,
                'lesson'             : lesson,
                'lesson_json'        : self.get_lesson_json(lesson_code),
                'students_js'        : self.make_student_structure_js2(lesson=lesson, indent="  "),
                'default_start_pane' : default_start_pane,
                'debug_mode'         : json.dumps(settings.DEBUG)
            }

            if self.session.has_key('msg'):
                template_values['msg'] = self.session.pop('msg')  # only show the message once

            self.write_response_with_template("teacher.html", template_values)

        except NotAnAuthenticatedTeacherError:
            self.redirect_to_teacher_login()

        except LessonNotFoundError:
            self.redirect_with_msg("There was an internal error.  Please choose your lesson to continue.", "/teacher_dashboard")

        except WrongTeacherError:
            self.redirect_to_teacher_login()
Exemplo n.º 6
0
    def create_edit_lesson(self, form_item):
        lesson_code = form_item("lesson_code")
        is_new = lesson_code == ""
        if is_new:
            lesson_code = self.make_lesson_code()
        lesson_title = form_item("lesson_title")
        lesson_description = form_item("lesson_description")
        class_name = form_item("class_name")
        task_infos = []
    
        for task_num in range(1, int(self.request.get("max_num_tasks", "10"))+1):
            task_title = form_item("task_title_%d"%task_num)
            task_description = form_item("task_description_%d"%task_num)
            if task_title != "":
                task_infos.append((task_title, task_description))

        import json
        tasks_json = json.dumps(task_infos)

        if (len(lesson_title) > 0) and (len(lesson_code) > 0) and (len(task_infos) > 0):
            from model import Lesson
            from datetime import datetime
            now = datetime.now()

            lesson = Lesson(key_name=lesson_code,
                teacher=self.person, title=lesson_title, lesson_code=lesson_code,
                description=lesson_description, class_name=class_name, 
                tasks_json=tasks_json, start_time=now, stop_time=None)
            
            if not is_new:
                old_lesson = Lesson.get_by_key_name(lesson_code)       
                lesson.start_time = old_lesson.start_time
                lesson.stop_time = old_lesson.stop_time
            
            lesson.put()
            self.response.out.write(self.get_lessons_json())
        
        else:
            data = { 'error': 1, 'msg': 'Required fields are missing.' }
            self.response.out.write(json.dumps(data))
    def post(self):
        import json
        from model import Student, Lesson
        from all_exceptions import StudentLoginException
        from datetime import datetime
        from helpers import log

        try:
            self.load_search_party_context(user_type="student")

            # Get CGI form fields.
            lesson_code = self.request.get('lesson_code')
            student_nickname = self.request.get('student_nickname')
            ext = int(self.request.get('ext', 0))

            # Normalize whitespace in student name.
            # Replace any string of >=1 whitespace with a single space (equivalent to s/\s+/ /g).
            student_nickname = " ".join(student_nickname.split())

            if not lesson_code:
            # No lesson code
                raise StudentLoginException("Please enter a lesson code.",
                        "lesson_code==%r"%lesson_code)
                
            # If no student nickname, generate an anonymous one
            anonymous = False
            if not student_nickname:
                import random, string
                alphabet = string.letters + string.digits

                anonymous_student = None
                for i in range(8):
                    random_nickname = "".join(random.choice(alphabet) for i in range(10))
                    key_name = Student.make_key_name(student_nickname=random_nickname, lesson_code=lesson_code)
                    anonymous_student = Student.get_by_key_name(key_name)
                    if anonymous_student is None:
                        student_nickname = random_nickname
                        anonymous = True
                        break
    
            if anonymous and not student_nickname:
            # No student name
                raise StudentLoginException("Could not login as anonymous student.",
                        "student_nickname==%r"%student_nickname)

#            if not lesson_code and not student_nickname:
#            # Blank form
#                raise StudentLoginException("Please enter a lesson code and a student name.",
#                        "lesson_code==%r, student_nickname==%r"%(lesson_code, student_nickname))
#            elif not lesson_code:
#            # No lesson code
#                raise StudentLoginException("Please enter a lesson code.",
#                        "lesson_code==%r"%lesson_code)
#            elif not student_nickname:
#            # No student name
#                raise StudentLoginException("Please enter a student name.",
#                        "student_nickname==%r"%student_nickname)

            lesson = Lesson.get_by_key_name(lesson_code)
            # Retrieve lesson from DB
            # - If lesson does not exist, this will return None.
            # - If lesson existed but is disabled, it will return the lesson, but lesson.is_active will be False.
            # - If lesson existed but was deleted (hidden), it will return the lesson, but lesson.is_deleted will be True.
            #   (Deleting lessons is done lazily.  Actually, they are merely hidden from the teacher's view.)

            if lesson is None or lesson.is_deleted:
            # Lesson does not exist or was deleted (hidden).
                raise StudentLoginException("Please check the lesson code.",
                        "lesson retrieved from datastore with lesson_code %r is None"%lesson_code)
            elif not lesson.is_active:
            # Lesson has been disabled by teacher.  Students are not allowed to work on it anymore.
                raise StudentLoginException("This lesson is finished.  You cannot work on it now.",
                        "lesson_code %r has is_active=False"%lesson_code)
            
            # Fetch student from DB.
            # - Might return None if nobody has ever logged in with this nickname+lesson combination.
            key_name = Student.make_key_name(student_nickname=student_nickname, lesson_code=lesson_code)
            student = Student.get_by_key_name(key_name)
            login_timestamp = datetime.now()

            if student is not None:
            # Found the student.
                student.session_sid=self.session.sid
                student.latest_login_timestamp = login_timestamp
                student.latest_logout_timestamp = None
                if not student.first_login_timestamp:
                    student.first_login_timestamp = login_timestamp

            else:                
                student = Student(
                    key_name=key_name,
                    nickname=student_nickname,
                    teacher=lesson.teacher_key,
                    lesson=lesson,
                    task_idx=self.INITIAL_TASK_IDX,
                    first_login_timestamp=login_timestamp,
                    latest_login_timestamp=login_timestamp,
                    latest_logout_timestamp=None,
                    session_sid=self.session.sid,
                    anonymous=anonymous,
                    client_ids=[]
                )

            assert student.session_sid is not None
            student.put()
            self.set_person(student)
            displayName = "Anonymous" if self.is_student and self.person.anonymous else self.person.nickname
            self.session['msg'] = "Student logged in:  Hello " + displayName
            self.response.headers.add_header('Content-Type', 'application/json', charset='utf-8')
            self.response.out.write(json.dumps({"status":"logged_in", "ext":ext}))
            log( "=> LOGIN SUCCESS" )

        except StudentLoginException, e:
            e.log()
            self.set_person(None)
            msg = e.args[0]
            self.session['msg'] = msg
            self.response.headers.add_header('Content-Type', 'application/json', charset='utf-8')
            self.response.out.write(json.dumps({"status":"logged_out", "error":msg}))
            log( "=> LOGIN FAILURE:  %s"%msg )
Exemplo n.º 8
0
	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)