Commit a7d6b9e15cb57ee62aa31ac0f0dae7f6f35ad904

Authored by Miguel Barão
1 parent ac45791a
Exists in dev

renamed LearnApp to Application

and other minor changes
aprendizations/learnapp.py
... ... @@ -10,13 +10,14 @@ import logging
10 10 from random import random
11 11 from os.path import join, exists
12 12 from typing import Any, Dict, Iterable, List, Optional, Tuple, Set, DefaultDict
13   -import yaml
14 13  
15 14 # third party libraries
16 15 import bcrypt
17 16 import networkx as nx
18   -from sqlalchemy import create_engine, select, func
  17 +import sqlalchemy as sa
  18 +from sqlalchemy import select
19 19 from sqlalchemy.orm import Session
  20 +import yaml
20 21  
21 22 # this project
22 23 from aprendizations.models import Student, Answer, Topic, StudentTopic
... ... @@ -34,7 +35,7 @@ class LearnException(Exception):
34 35  
35 36  
36 37 # ============================================================================
37   -class LearnApp():
  38 +class Application():
38 39 '''
39 40 LearnApp - application logic
40 41  
... ... @@ -157,8 +158,8 @@ class LearnApp():
157 158 # wait random time to minimize timing attacks
158 159 await asyncio.sleep(random())
159 160  
160   - query = select(Student).where(Student.id == uid)
161 161 with Session(self._engine) as session:
  162 + query = select(Student).where(Student.id == uid)
162 163 student = session.execute(query).scalar_one_or_none()
163 164 if student is None:
164 165 logger.info('User "%s" does not exist', uid)
... ... @@ -177,8 +178,8 @@ class LearnApp():
177 178 logger.info('User "%s" logged in', uid)
178 179  
179 180 # get topics for this student and set its current state
180   - query = select(StudentTopic).where(StudentTopic.student_id == uid)
181 181 with Session(self._engine) as session:
  182 + query = select(StudentTopic).where(StudentTopic.student_id == uid)
182 183 student_topics = session.execute(query).scalars().all()
183 184  
184 185 state = {t.topic_id: {
... ... @@ -220,8 +221,8 @@ class LearnApp():
220 221 password.encode('utf-8'),
221 222 bcrypt.gensalt())
222 223  
223   - query = select(Student).where(Student.id == uid)
224 224 with Session(self._engine) as session:
  225 + query = select(Student).where(Student.id == uid)
225 226 session.execute(query).scalar_one().password = str(hashed_pw)
226 227 session.commit()
227 228  
... ... @@ -273,10 +274,10 @@ class LearnApp():
273 274 date: str = str(student_state.get_topic_date(tid))
274 275 logger.info('"%s" finished "%s" (level=%.2f)', uid, tid, level)
275 276  
276   - query = select(StudentTopic) \
277   - .where(StudentTopic.student_id == uid) \
278   - .where(StudentTopic.topic_id == tid)
279 277 with Session(self._engine) as session:
  278 + query = select(StudentTopic) \
  279 + .where(StudentTopic.student_id == uid) \
  280 + .where(StudentTopic.topic_id == tid)
280 281 student_topic = session.execute(query).scalar_one_or_none()
281 282 if student_topic is None:
282 283 # insert new studenttopic into database
... ... @@ -351,11 +352,11 @@ class LearnApp():
351 352 raise LearnException('Database does not exist')
352 353  
353 354 # echo=True enables logging of the SQL emitted by sqlalchemy
354   - self._engine = create_engine(f'sqlite:///{database}', echo=False)
  355 + self._engine = sa.create_engine(f'sqlite:///{database}', echo=False)
355 356 try:
356   - query_students = select(func.count(Student.id))
357   - query_topics = select(func.count(Topic.id))
358   - query_answers = select(func.count(Answer.id))
  357 + query_students = select(sa.func.count(Student.id))
  358 + query_topics = select(sa.func.count(Topic.id))
  359 + query_answers = select(sa.func.count(Answer.id))
359 360 with Session(self._engine) as session:
360 361 count_students = session.execute(query_students).scalar()
361 362 count_topics = session.execute(query_topics).scalar()
... ... @@ -566,12 +567,12 @@ class LearnApp():
566 567 '''
567 568  
568 569 logger.info('User "%s" rankings for "%s"', uid, cid)
569   - query_students = select(Student.id, Student.name)
570   - query_student_topics = select(StudentTopic.student_id,
571   - StudentTopic.topic_id,
572   - StudentTopic.level,
573   - StudentTopic.date)
574 570 with Session(self._engine) as session:
  571 + query_students = select(Student.id, Student.name)
  572 + query_student_topics = select(StudentTopic.student_id,
  573 + StudentTopic.topic_id,
  574 + StudentTopic.level,
  575 + StudentTopic.date)
575 576  
576 577 # all students in the database FIXME only with answers of this course
577 578 students = session.execute(query_students).all()
... ...
aprendizations/main.py
... ... @@ -16,16 +16,14 @@ import sys
16 16 from typing import Dict
17 17  
18 18 # this project
19   -from .learnapp import LearnApp, LearnException
  19 +from .learnapp import Application, LearnException
20 20 from .serve import webserver
21 21 from . import APP_NAME, APP_VERSION
22 22  
23 23  
24 24 # ----------------------------------------------------------------------------
25 25 def parse_cmdline_arguments():
26   - '''
27   - Parses command line arguments. Uses the argparse package.
28   - '''
  26 + '''Parses command line arguments. Uses the argparse package'''
29 27  
30 28 parser = argparse.ArgumentParser(
31 29 description='Webserver for interactive learning and practice. '
... ... @@ -110,9 +108,7 @@ def get_logger_config(debug: bool = False) -> Dict:
110 108  
111 109 # ----------------------------------------------------------------------------
112 110 def main():
113   - '''
114   - Start application and webserver
115   - '''
  111 + '''Start application and webserver'''
116 112  
117 113 # --- Commandline argument parsing
118 114 arg = parse_cmdline_arguments()
... ... @@ -162,10 +158,10 @@ def main():
162 158  
163 159 # --- start application --------------------------------------------------
164 160 try:
165   - app = LearnApp(courses=arg.courses,
166   - prefix=arg.prefix,
167   - dbase=arg.db,
168   - check=arg.check)
  161 + app = Application(courses=arg.courses,
  162 + prefix=arg.prefix,
  163 + dbase=arg.db,
  164 + check=arg.check)
169 165 except LearnException:
170 166 logger.critical('Failed to start application')
171 167 sys.exit(1)
... ... @@ -180,5 +176,5 @@ def main():
180 176  
181 177  
182 178 # ----------------------------------------------------------------------------
183   -if __name__ == "__main__":
  179 +if __name__ == '__main__':
184 180 main()
... ...
aprendizations/serve.py
... ... @@ -32,7 +32,6 @@ logger = getLogger(__name__)
32 32 # ============================================================================
33 33 # Handlers
34 34 # ============================================================================
35   -# pylint: disable=abstract-method
36 35 class BaseHandler(tornado.web.RequestHandler):
37 36 '''Base handler common to all handlers.'''
38 37  
... ... @@ -55,12 +54,12 @@ class LoginHandler(BaseHandler):
55 54  
56 55 async def post(self):
57 56 '''Authenticate and redirect to application if successful'''
58   - userid = self.get_body_argument('uid') or ''
59   - passwd = self.get_body_argument('pw')
  57 + uid = self.get_body_argument('uid') or ''
  58 + pw = self.get_body_argument('pw')
60 59 loop = tornado.ioloop.IOLoop.current()
61   - login_ok = await self.app.login(userid, passwd, loop)
  60 + login_ok = await self.app.login(uid, pw, loop)
62 61 if login_ok:
63   - self.set_secure_cookie('aprendizations_user', userid)
  62 + self.set_secure_cookie('aprendizations_user', uid)
64 63 self.redirect('/')
65 64 else:
66 65 self.render('login.html', error='Número ou senha incorrectos')
... ... @@ -73,22 +72,18 @@ class LogoutHandler(BaseHandler):
73 72 @tornado.web.authenticated
74 73 def get(self) -> None:
75 74 '''Clear cookies and user session'''
76   - self.app.logout(self.current_user) # FIXME
  75 + self.app.logout(self.current_user)
77 76 self.clear_cookie('aprendizations_user')
78 77 self.redirect('/')
79 78  
80 79  
81 80 # ----------------------------------------------------------------------------
82 81 class ChangePasswordHandler(BaseHandler):
83   - '''
84   - Handles password change
85   - '''
  82 + '''Handles password change'''
86 83  
87 84 @tornado.web.authenticated
88 85 async def post(self) -> None:
89   - '''
90   - Try to change password and show success/fail status
91   - '''
  86 + '''Try to change password and show success/fail status'''
92 87 userid = self.current_user
93 88 passwd = self.get_body_arguments('new_password')[0] # FIXME porque [0]?
94 89 ok = await self.app.change_password(userid, passwd)
... ... @@ -98,9 +93,7 @@ class ChangePasswordHandler(BaseHandler):
98 93  
99 94 # ----------------------------------------------------------------------------
100 95 class RootHandler(BaseHandler):
101   - '''
102   - Handles root /
103   - '''
  96 + '''Handle / (root)'''
104 97  
105 98 @tornado.web.authenticated
106 99 def get(self) -> None:
... ... @@ -110,9 +103,7 @@ class RootHandler(BaseHandler):
110 103  
111 104 # ----------------------------------------------------------------------------
112 105 class CoursesHandler(BaseHandler):
113   - '''
114   - Handles /courses
115   - '''
  106 + '''Handles /courses'''
116 107 def set_default_headers(self, *_) -> None:
117 108 self.set_header('Cache-Control', 'no-cache')
118 109  
... ... @@ -132,10 +123,7 @@ class CoursesHandler(BaseHandler):
132 123 class CourseHandler2(BaseHandler):
133 124 @tornado.web.authenticated
134 125 def get(self, course_id) -> None:
135   - '''
136   - Handles get /course/...
137   - Starts a given course and show list of topics
138   - '''
  126 + ''' Handles /course/... - start course and show topics'''
139 127 uid = self.current_user
140 128 logger.debug('[CourseHandler2] uid="%s", course_id="%s"', uid, course_id)
141 129  
... ... @@ -157,16 +145,11 @@ class CourseHandler2(BaseHandler):
157 145  
158 146 # ============================================================================
159 147 class CourseHandler(BaseHandler):
160   - '''
161   - Show topics for a particular course
162   - '''
  148 + '''Show topics for a particular course'''
163 149  
164 150 @tornado.web.authenticated
165 151 def get(self, course_id) -> None:
166   - '''
167   - Handles get /course/...
168   - Starts a given course and show list of topics
169   - '''
  152 + ''' Handles /course/... - start course and show topics'''
170 153 uid = self.current_user
171 154 logger.debug('[CourseHandler] uid="%s", course_id="%s"', uid, course_id)
172 155  
... ... @@ -189,18 +172,13 @@ class CourseHandler(BaseHandler):
189 172  
190 173 # ============================================================================
191 174 class TopicHandler(BaseHandler):
192   - '''
193   - Handles a topic
194   - '''
  175 + '''Handle topic'''
195 176 def set_default_headers(self, *_) -> None:
196 177 self.set_header('Cache-Control', 'no-cache')
197 178  
198 179 @tornado.web.authenticated
199 180 async def get(self, topic) -> None:
200   - '''
201   - Handles get /topic/...
202   - Starts a given topic
203   - '''
  181 + '''Handles get /topic/... - start topic'''
204 182 uid = self.current_user
205 183 logger.debug('[TopicHandler] %s', topic)
206 184 try:
... ... @@ -217,15 +195,11 @@ class TopicHandler(BaseHandler):
217 195  
218 196 # ============================================================================
219 197 class FileHandler(BaseHandler):
220   - '''
221   - Serves files from the /public subdir of the topics.
222   - '''
  198 + '''Serves files from the /public directory of a topic'''
223 199  
224 200 @tornado.web.authenticated
225 201 async def get(self, filename) -> None:
226   - '''
227   - Serve file from the /public subdirectory of a particular topic
228   - '''
  202 + '''Serve file from the /public directory of a topic'''
229 203 uid = self.current_user
230 204 public_dir = self.app.get_current_public_dir(uid)
231 205 filepath = expanduser(join(public_dir, filename))
... ... @@ -248,9 +222,8 @@ class FileHandler(BaseHandler):
248 222  
249 223 # ============================================================================
250 224 class QuestionHandler(BaseHandler):
251   - '''
252   - Responds to AJAX to get a JSON question
253   - '''
  225 + '''Responds to AJAX to get a JSON question'''
  226 +
254 227 templates = {
255 228 'checkbox': 'question-checkbox.html',
256 229 'radio': 'question-radio.html',
... ... @@ -268,9 +241,7 @@ class QuestionHandler(BaseHandler):
268 241 # ------------------------------------------------------------------------
269 242 @tornado.web.authenticated
270 243 async def get(self) -> None:
271   - '''
272   - Get question to render or an animated trophy if no more questions.
273   - '''
  244 + '''Get question to render or an animated trophy'''
274 245 logger.debug('[QuestionHandler]')
275 246 user = self.current_user
276 247 question = await self.app.get_question(user)
... ... @@ -306,7 +277,7 @@ class QuestionHandler(BaseHandler):
306 277 async def post(self) -> None:
307 278 '''
308 279 Correct answer and return status: right, wrong, try_again
309   - Does not move to next question.
  280 + Does not move to the next question.
310 281 '''
311 282 user = self.current_user
312 283 answer = self.get_body_arguments('answer') # list
... ... @@ -455,7 +426,7 @@ async def webserver(app, ssl, port: int = 8443, debug: bool = False) -> None:
455 426 'debug': debug,
456 427 }
457 428 webapp = tornado.web.Application(handlers, **settings)
458   - logger.info('Web application started (tornado.web.Application)')
  429 + logger.info('Web application created (tornado.web.Application)')
459 430  
460 431 # --- create tornado http server
461 432 try:
... ...