import random from contextlib import contextmanager # `with` statement in db sessions # libs import bcrypt from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker, scoped_session # this project import questions from models import Student # ============================================================================ # LearnApp - application logic # ============================================================================ class LearnApp(object): def __init__(self): print('LearnApp.__init__') self.factory = questions.QuestionFactory() self.factory.load_files(['questions.yaml'], 'demo') # FIXME self.online = {} # connect to database and check registered students engine = create_engine('sqlite:///{}'.format('students.db'), echo=False) self.Session = scoped_session(sessionmaker(bind=engine)) try: with self.db_session() as s: n = s.query(Student).filter(Student.id != '0').count() except Exception as e: print('Database not usable.') raise e else: print('Database has {} students registered.'.format(n)) # ------------------------------------------------------------------------ def login_ok(self, uid, try_pw): print('LearnApp.login') with self.db_session() as s: student = s.query(Student).filter(Student.id == uid).one_or_none() if student is None or student in self.online: # student does not exist return False # hashedtry = yield executor.submit(bcrypt.hashpw, # try_pw.encode('utf-8'), student.password) hashedtry = bcrypt.hashpw(try_pw.encode('utf-8'), student.password) if hashedtry != student.password: # wrong password return False # success self.online[uid] = { 'name': student.name, 'number': student.id, 'current': None, } print(self.online) return True # ------------------------------------------------------------------------ # logout def logout(self, uid): del self.online[uid] # FIXME save current question? # ------------------------------------------------------------------------ # given the currect state, generates a new question for the student def new_question_for(self, uid): questions = list(self.factory) nextquestion = self.factory.generate(random.choice(questions)) self.online[uid]['current'] = nextquestion return nextquestion # ------------------------------------------------------------------------ def get_current_question(self, uid): return self.online[uid].get('current', None) # ------------------------------------------------------------------------ def get_student_name(self, uid): return self.online[uid].get('name', '') # ------------------------------------------------------------------------ # check answer and if correct returns new question, otherise returns None def check_answer(self, uid, answer): question = self.get_current_question(uid) print('------------------------------') print(question) print(answer) if question is not None: grade = question.correct(answer) # correct answer correct = grade > 0.99999 if correct: print('CORRECT') return self.new_question_for(uid) else: print('WRONG') return None else: print('FIRST QUESTION') return self.new_question_for(uid) # ------------------------------------------------------------------------ # helper to manage db sessions using the `with` statement, for example # with self.db_session() as s: s.query(...) @contextmanager def db_session(self): try: yield self.Session() finally: self.Session.remove()