diff --git a/aprendizations/__init__.py b/aprendizations/__init__.py index dceaf80..401ae60 100644 --- a/aprendizations/__init__.py +++ b/aprendizations/__init__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2019 Miguel Barão +# Copyright © 2022 Miguel Barão # # THE MIT License # @@ -30,10 +30,10 @@ are progressively uncovered as the students progress. ''' APP_NAME = 'aprendizations' -APP_VERSION = '2022.08.dev1' +APP_VERSION = '2022.12.dev1' APP_DESCRIPTION = __doc__ __author__ = 'Miguel Barão' -__copyright__ = 'Copyright 2021, Miguel Barão' +__copyright__ = 'Copyright © 2022, Miguel Barão' __license__ = 'MIT license' __version__ = APP_VERSION diff --git a/aprendizations/serve.py b/aprendizations/serve.py index c45a40a..e34b772 100644 --- a/aprendizations/serve.py +++ b/aprendizations/serve.py @@ -11,6 +11,7 @@ import mimetypes from os.path import join, dirname, expanduser import signal import sys +import re from typing import List, Optional, Union import uuid @@ -21,7 +22,7 @@ import tornado.web from tornado.escape import to_unicode # this project -from aprendizations.tools import md_to_html +from aprendizations.renderer_markdown import md_to_html from aprendizations.learnapp import LearnException from aprendizations import APP_NAME @@ -82,6 +83,7 @@ class BaseHandler(tornado.web.RequestHandler): ''' Base handler common to all handlers. ''' + @property def learn(self): '''easier access to learnapp''' @@ -105,6 +107,7 @@ class RankingsHandler(BaseHandler): ''' Handles rankings page ''' + @tornado.web.authenticated def get(self) -> None: ''' @@ -130,33 +133,30 @@ class LoginHandler(BaseHandler): ''' Handles /login ''' + def get(self) -> None: ''' - Renders login page + Render login page ''' - self.render('login.html', - appname=APP_NAME, - error='') + self.render('login.html', appname=APP_NAME, error='') async def post(self): ''' - Perform authentication and redirects to application if successful + Authenticate and redirect to application if successful ''' - - userid = (self.get_body_argument('uid') or '').lstrip('l') + userid = self.get_body_argument('uid') or '' passwd = self.get_body_argument('pw') - - login_ok = await self.learn.login(userid, passwd) - - if login_ok: - counter = str(self.learn.get_login_counter(userid)) - self.set_secure_cookie('aprendizations_user', userid) - self.set_secure_cookie('counter', counter) - self.redirect('/') - else: - self.render('login.html', - appname=APP_NAME, - error='Número ou senha incorrectos') + match = re.search(r'[0-9]+', userid) # extract number + if match is not None: + userid = match.group(0) # get string with number + if await self.learn.login(userid, passwd): + counter = str(self.learn.get_login_counter(userid)) + self.set_secure_cookie('aprendizations_user', userid) + self.set_secure_cookie('counter', counter) + self.redirect('/') + self.render('login.html', + appname=APP_NAME, + error='Número ou senha incorrectos') # ---------------------------------------------------------------------------- @@ -167,7 +167,7 @@ class LogoutHandler(BaseHandler): @tornado.web.authenticated def get(self) -> None: ''' - clears cookies and removes user session + clear cookies and user session ''' self.clear_cookie('user') self.clear_cookie('counter') @@ -182,14 +182,14 @@ class ChangePasswordHandler(BaseHandler): ''' Handles password change ''' + @tornado.web.authenticated async def post(self) -> None: ''' - Tries to perform password change and then replies success/fail status + Try to change password and show success/fail status ''' userid = self.current_user passwd = self.get_body_arguments('new_password')[0] - changed_ok = await self.learn.change_password(userid, passwd) if changed_ok: notification = self.render_string( @@ -203,7 +203,6 @@ class ChangePasswordHandler(BaseHandler): type='danger', msg='A password não foi alterada!' ) - self.write({'msg': to_unicode(notification)}) @@ -212,9 +211,10 @@ class RootHandler(BaseHandler): ''' Handles root / ''' + @tornado.web.authenticated def get(self) -> None: - '''Simply redirects to the main entrypoint''' + '''Redirect to main entrypoint''' self.redirect('/courses') @@ -223,12 +223,13 @@ class CoursesHandler(BaseHandler): ''' Handles /courses ''' + def set_default_headers(self, *_) -> None: self.set_header('Cache-Control', 'no-cache') @tornado.web.authenticated def get(self) -> None: - '''Renders list of available courses''' + '''Render available courses''' uid = self.current_user self.render('courses.html', appname=APP_NAME, @@ -285,7 +286,7 @@ class TopicHandler(BaseHandler): Starts a given topic ''' uid = self.current_user - + logger.debug('[TopicHandler.get] %s', topic) try: await self.learn.start_topic(uid, topic) # FIXME GET should not modify state... except KeyError: @@ -304,15 +305,18 @@ class FileHandler(BaseHandler): ''' Serves files from the /public subdir of the topics. ''' + @tornado.web.authenticated async def get(self, filename) -> None: ''' - Serves files from /public subdirectories of a particular topic + Serve file from the /public subdirectory of a particular topic ''' uid = self.current_user public_dir = self.learn.get_current_public_dir(uid) filepath = expanduser(join(public_dir, filename)) + logger.debug('uid=%s, public_dir=%s, filepath=%s', uid, public_dir, + filepath) try: with open(filepath, 'rb') as file: data = file.read() @@ -350,10 +354,9 @@ class QuestionHandler(BaseHandler): @tornado.web.authenticated async def get(self) -> None: ''' - Gets question to render. - Shows an animated trophy if there are no more questions in the topic. + Get question to render or an animated trophy if no more questions. ''' - logger.debug('[QuestionHandler]') + logger.debug('[QuestionHandler.get]') user = self.current_user question = await self.learn.get_question(user) @@ -387,7 +390,7 @@ class QuestionHandler(BaseHandler): @tornado.web.authenticated async def post(self) -> None: ''' - Corrects answer and returns status: right, wrong, try_again + Correct answer and return status: right, wrong, try_again Does not move to next question. ''' user = self.current_user @@ -422,18 +425,16 @@ class QuestionHandler(BaseHandler): # --- check answer (nonblocking) and get corrected question and action question = await self.learn.check_answer(user, ans) - # --- built response to return + # --- build response response = {'method': question['status'], 'params': {}} if question['status'] == 'right': # get next question in the topic comments = self.render_string('comments-right.html', comments=question['comments'], md=md_to_html) - solution = self.render_string('solution.html', solution=question['solution'], md=md_to_html) - response['params'] = { 'type': question['type'], 'progress': self.learn.get_student_progress(user), @@ -445,7 +446,6 @@ class QuestionHandler(BaseHandler): comments = self.render_string('comments.html', comments=question['comments'], md=md_to_html) - response['params'] = { 'type': question['type'], 'progress': self.learn.get_student_progress(user), @@ -456,10 +456,8 @@ class QuestionHandler(BaseHandler): comments = self.render_string('comments.html', comments=question['comments'], md=md_to_html) - solution = self.render_string( 'solution.html', solution=question['solution'], md=md_to_html) - response['params'] = { 'type': question['type'], 'progress': self.learn.get_student_progress(user), @@ -501,7 +499,7 @@ def run_webserver(app, ssl, port: int = 8443, debug: bool = False) -> None: sys.exit(1) logger.info('Web application started (tornado.web.Application)') - # --- create tornado webserver + # --- create tornado http server try: httpserver = tornado.httpserver.HTTPServer(webapp, ssl_options=ssl) except ValueError: @@ -515,9 +513,11 @@ def run_webserver(app, ssl, port: int = 8443, debug: bool = False) -> None: logger.critical('Cannot bind port %d. Already in use?', port) sys.exit(1) logger.info('Webserver listening on %d... (Ctrl-C to stop)', port) + + # --- set signal handler for Control-C signal.signal(signal.SIGINT, signal_handler) - # --- run webserver + # --- run tornado webserver try: tornado.ioloop.IOLoop.current().start() # running... except Exception: diff --git a/aprendizations/templates/include-libs.html b/aprendizations/templates/include-libs.html index 2745272..f9590d6 100644 --- a/aprendizations/templates/include-libs.html +++ b/aprendizations/templates/include-libs.html @@ -1,5 +1,5 @@ - + @@ -7,3 +7,14 @@ + + + + + + + + + + + diff --git a/aprendizations/templates/question-checkbox.html b/aprendizations/templates/question-checkbox.html index 612ceed..6a7bfc0 100644 --- a/aprendizations/templates/question-checkbox.html +++ b/aprendizations/templates/question-checkbox.html @@ -3,13 +3,14 @@ {% block answer %}