diff --git a/aprendizations/learnapp.py b/aprendizations/learnapp.py index dbadf3f..b5fe9a9 100644 --- a/aprendizations/learnapp.py +++ b/aprendizations/learnapp.py @@ -10,13 +10,14 @@ import logging from random import random from os.path import join, exists from typing import Any, Dict, Iterable, List, Optional, Tuple, Set, DefaultDict -import yaml # third party libraries import bcrypt import networkx as nx -from sqlalchemy import create_engine, select, func +import sqlalchemy as sa +from sqlalchemy import select from sqlalchemy.orm import Session +import yaml # this project from aprendizations.models import Student, Answer, Topic, StudentTopic @@ -34,7 +35,7 @@ class LearnException(Exception): # ============================================================================ -class LearnApp(): +class Application(): ''' LearnApp - application logic @@ -157,8 +158,8 @@ class LearnApp(): # wait random time to minimize timing attacks await asyncio.sleep(random()) - query = select(Student).where(Student.id == uid) with Session(self._engine) as session: + query = select(Student).where(Student.id == uid) student = session.execute(query).scalar_one_or_none() if student is None: logger.info('User "%s" does not exist', uid) @@ -177,8 +178,8 @@ class LearnApp(): logger.info('User "%s" logged in', uid) # get topics for this student and set its current state - query = select(StudentTopic).where(StudentTopic.student_id == uid) with Session(self._engine) as session: + query = select(StudentTopic).where(StudentTopic.student_id == uid) student_topics = session.execute(query).scalars().all() state = {t.topic_id: { @@ -220,8 +221,8 @@ class LearnApp(): password.encode('utf-8'), bcrypt.gensalt()) - query = select(Student).where(Student.id == uid) with Session(self._engine) as session: + query = select(Student).where(Student.id == uid) session.execute(query).scalar_one().password = str(hashed_pw) session.commit() @@ -273,10 +274,10 @@ class LearnApp(): date: str = str(student_state.get_topic_date(tid)) logger.info('"%s" finished "%s" (level=%.2f)', uid, tid, level) - query = select(StudentTopic) \ - .where(StudentTopic.student_id == uid) \ - .where(StudentTopic.topic_id == tid) with Session(self._engine) as session: + query = select(StudentTopic) \ + .where(StudentTopic.student_id == uid) \ + .where(StudentTopic.topic_id == tid) student_topic = session.execute(query).scalar_one_or_none() if student_topic is None: # insert new studenttopic into database @@ -351,11 +352,11 @@ class LearnApp(): raise LearnException('Database does not exist') # echo=True enables logging of the SQL emitted by sqlalchemy - self._engine = create_engine(f'sqlite:///{database}', echo=False) + self._engine = sa.create_engine(f'sqlite:///{database}', echo=False) try: - query_students = select(func.count(Student.id)) - query_topics = select(func.count(Topic.id)) - query_answers = select(func.count(Answer.id)) + query_students = select(sa.func.count(Student.id)) + query_topics = select(sa.func.count(Topic.id)) + query_answers = select(sa.func.count(Answer.id)) with Session(self._engine) as session: count_students = session.execute(query_students).scalar() count_topics = session.execute(query_topics).scalar() @@ -566,12 +567,12 @@ class LearnApp(): ''' logger.info('User "%s" rankings for "%s"', uid, cid) - query_students = select(Student.id, Student.name) - query_student_topics = select(StudentTopic.student_id, - StudentTopic.topic_id, - StudentTopic.level, - StudentTopic.date) with Session(self._engine) as session: + query_students = select(Student.id, Student.name) + query_student_topics = select(StudentTopic.student_id, + StudentTopic.topic_id, + StudentTopic.level, + StudentTopic.date) # all students in the database FIXME only with answers of this course students = session.execute(query_students).all() diff --git a/aprendizations/main.py b/aprendizations/main.py index 1a35c9b..a0dae56 100644 --- a/aprendizations/main.py +++ b/aprendizations/main.py @@ -16,16 +16,14 @@ import sys from typing import Dict # this project -from .learnapp import LearnApp, LearnException +from .learnapp import Application, LearnException from .serve import webserver from . import APP_NAME, APP_VERSION # ---------------------------------------------------------------------------- def parse_cmdline_arguments(): - ''' - Parses command line arguments. Uses the argparse package. - ''' + '''Parses command line arguments. Uses the argparse package''' parser = argparse.ArgumentParser( description='Webserver for interactive learning and practice. ' @@ -110,9 +108,7 @@ def get_logger_config(debug: bool = False) -> Dict: # ---------------------------------------------------------------------------- def main(): - ''' - Start application and webserver - ''' + '''Start application and webserver''' # --- Commandline argument parsing arg = parse_cmdline_arguments() @@ -162,10 +158,10 @@ def main(): # --- start application -------------------------------------------------- try: - app = LearnApp(courses=arg.courses, - prefix=arg.prefix, - dbase=arg.db, - check=arg.check) + app = Application(courses=arg.courses, + prefix=arg.prefix, + dbase=arg.db, + check=arg.check) except LearnException: logger.critical('Failed to start application') sys.exit(1) @@ -180,5 +176,5 @@ def main(): # ---------------------------------------------------------------------------- -if __name__ == "__main__": +if __name__ == '__main__': main() diff --git a/aprendizations/serve.py b/aprendizations/serve.py index fdf13fa..39d3244 100644 --- a/aprendizations/serve.py +++ b/aprendizations/serve.py @@ -32,7 +32,6 @@ logger = getLogger(__name__) # ============================================================================ # Handlers # ============================================================================ -# pylint: disable=abstract-method class BaseHandler(tornado.web.RequestHandler): '''Base handler common to all handlers.''' @@ -55,12 +54,12 @@ class LoginHandler(BaseHandler): async def post(self): '''Authenticate and redirect to application if successful''' - userid = self.get_body_argument('uid') or '' - passwd = self.get_body_argument('pw') + uid = self.get_body_argument('uid') or '' + pw = self.get_body_argument('pw') loop = tornado.ioloop.IOLoop.current() - login_ok = await self.app.login(userid, passwd, loop) + login_ok = await self.app.login(uid, pw, loop) if login_ok: - self.set_secure_cookie('aprendizations_user', userid) + self.set_secure_cookie('aprendizations_user', uid) self.redirect('/') else: self.render('login.html', error='NĂºmero ou senha incorrectos') @@ -73,22 +72,18 @@ class LogoutHandler(BaseHandler): @tornado.web.authenticated def get(self) -> None: '''Clear cookies and user session''' - self.app.logout(self.current_user) # FIXME + self.app.logout(self.current_user) self.clear_cookie('aprendizations_user') self.redirect('/') # ---------------------------------------------------------------------------- class ChangePasswordHandler(BaseHandler): - ''' - Handles password change - ''' + '''Handles password change''' @tornado.web.authenticated async def post(self) -> None: - ''' - Try to change password and show success/fail status - ''' + '''Try to change password and show success/fail status''' userid = self.current_user passwd = self.get_body_arguments('new_password')[0] # FIXME porque [0]? ok = await self.app.change_password(userid, passwd) @@ -98,9 +93,7 @@ class ChangePasswordHandler(BaseHandler): # ---------------------------------------------------------------------------- class RootHandler(BaseHandler): - ''' - Handles root / - ''' + '''Handle / (root)''' @tornado.web.authenticated def get(self) -> None: @@ -110,9 +103,7 @@ class RootHandler(BaseHandler): # ---------------------------------------------------------------------------- class CoursesHandler(BaseHandler): - ''' - Handles /courses - ''' + '''Handles /courses''' def set_default_headers(self, *_) -> None: self.set_header('Cache-Control', 'no-cache') @@ -132,10 +123,7 @@ class CoursesHandler(BaseHandler): class CourseHandler2(BaseHandler): @tornado.web.authenticated def get(self, course_id) -> None: - ''' - Handles get /course/... - Starts a given course and show list of topics - ''' + ''' Handles /course/... - start course and show topics''' uid = self.current_user logger.debug('[CourseHandler2] uid="%s", course_id="%s"', uid, course_id) @@ -157,16 +145,11 @@ class CourseHandler2(BaseHandler): # ============================================================================ class CourseHandler(BaseHandler): - ''' - Show topics for a particular course - ''' + '''Show topics for a particular course''' @tornado.web.authenticated def get(self, course_id) -> None: - ''' - Handles get /course/... - Starts a given course and show list of topics - ''' + ''' Handles /course/... - start course and show topics''' uid = self.current_user logger.debug('[CourseHandler] uid="%s", course_id="%s"', uid, course_id) @@ -189,18 +172,13 @@ class CourseHandler(BaseHandler): # ============================================================================ class TopicHandler(BaseHandler): - ''' - Handles a topic - ''' + '''Handle topic''' def set_default_headers(self, *_) -> None: self.set_header('Cache-Control', 'no-cache') @tornado.web.authenticated async def get(self, topic) -> None: - ''' - Handles get /topic/... - Starts a given topic - ''' + '''Handles get /topic/... - start topic''' uid = self.current_user logger.debug('[TopicHandler] %s', topic) try: @@ -217,15 +195,11 @@ class TopicHandler(BaseHandler): # ============================================================================ class FileHandler(BaseHandler): - ''' - Serves files from the /public subdir of the topics. - ''' + '''Serves files from the /public directory of a topic''' @tornado.web.authenticated async def get(self, filename) -> None: - ''' - Serve file from the /public subdirectory of a particular topic - ''' + '''Serve file from the /public directory of a topic''' uid = self.current_user public_dir = self.app.get_current_public_dir(uid) filepath = expanduser(join(public_dir, filename)) @@ -248,9 +222,8 @@ class FileHandler(BaseHandler): # ============================================================================ class QuestionHandler(BaseHandler): - ''' - Responds to AJAX to get a JSON question - ''' + '''Responds to AJAX to get a JSON question''' + templates = { 'checkbox': 'question-checkbox.html', 'radio': 'question-radio.html', @@ -268,9 +241,7 @@ class QuestionHandler(BaseHandler): # ------------------------------------------------------------------------ @tornado.web.authenticated async def get(self) -> None: - ''' - Get question to render or an animated trophy if no more questions. - ''' + '''Get question to render or an animated trophy''' logger.debug('[QuestionHandler]') user = self.current_user question = await self.app.get_question(user) @@ -306,7 +277,7 @@ class QuestionHandler(BaseHandler): async def post(self) -> None: ''' Correct answer and return status: right, wrong, try_again - Does not move to next question. + Does not move to the next question. ''' user = self.current_user answer = self.get_body_arguments('answer') # list @@ -455,7 +426,7 @@ async def webserver(app, ssl, port: int = 8443, debug: bool = False) -> None: 'debug': debug, } webapp = tornado.web.Application(handlers, **settings) - logger.info('Web application started (tornado.web.Application)') + logger.info('Web application created (tornado.web.Application)') # --- create tornado http server try: -- libgit2 0.21.2