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 load_user(self): self.client_id = self.request.get('from', None) import client_id_utils self.person_type = client_id_utils.person_type_for_client_id(self.client_id) assert self.person_type in ("student", "teacher") self.person = None person_key = client_id_utils.person_key_for_client_id(self.client_id) if self.person_type == "teacher": from model import Teacher self.person = Teacher.get_by_key_name(person_key) else: from model import Student lesson_code = client_id_utils.lesson_code_for_client_id(self.client_id) student_key = "::".join((person_key, lesson_code)) self.person = Student.get_by_key_name(student_key) if self.person is None: from helpers import log log("***** ERROR: Person not found for client_id {0}".format(self.client_id))
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 )
def _attempt_to_identify_as_student(self): from model import Student from helpers import log # Initialize student # We still store changes to student record only, if any, but we don't want to store # the record needlessly, since that consumes billable resources. student = None student_is_dirty = False # There are two ways to identify a student: nickname + lesson code sent via CGI, # or the session ID. We will try them in that order. # Get CGI form values lesson_code = self.request.get("lesson_code", None) student_nickname = self.request.get("student_nickname", None) if lesson_code is not None and student_nickname is not None: # 1. Fetch student by nickname+lesson student_nickname = self.htmlunquote(student_nickname) key_name = Student.make_key_name(student_nickname=student_nickname, lesson_code=lesson_code) student = Student.get_by_key_name(key_name) log("=> SEARCHING BY NAME AND LESSON CODE: {0}, {1}, {2}".format(student_nickname, lesson_code, key_name)) if student is not None and self.session.sid != student.session_sid: if student.is_logged_in: # Prevent login if student already logged in to another session # GAE limits # of channels so we don't want to allow too many student windows from all_exceptions import StudentLoginException raise StudentLoginException( "Please choose another name. Someone is already logged in as %s." % (student_nickname.encode("ascii", "xmlcharrefreplace")), "Session ID doesn't match.", student.session_sid, self.session.sid, student.latest_login_timestamp, student.latest_logout_timestamp, ) # else: # # Need to update session id if student was logged into another browser previously (and then logged out) # student.session_sid = self.session.sid # student_is_dirty = True else: # 2. Fetch student by session id student = Student.all().filter("session_sid =", self.session.sid).get() log("=> SEARCHING FOR STUDENT BY SESSION ID {0}".format(self.session.sid)) if student is not None and not student.is_logged_in: # Passively log student in again. # At some point this student logged into this browser but logged out passively. from datetime import datetime student.latest_login_timestamp = datetime.now() student.latest_logout_timestamp = None student_is_dirty = True log("=> PASSIVE STUDENT LOGIN AFTER PASSIVE LOGOUT") if student_is_dirty: # Store changes to student record, if any. student.put() if student is not None and not student.is_logged_in: log("=> STUDENT IS **NOT** LOGGED IN") return student