Commit 65a5ad4aceead32255bb3bbd04a3f0d715c63519
1 parent
0392a334
Exists in
master
and in
1 other branch
Small fixes
Showing
2 changed files
with
31 additions
and
71 deletions
Show diff stats
aprendizations/learnapp.py
@@ -6,7 +6,6 @@ This is the main controller of the application. | @@ -6,7 +6,6 @@ This is the main controller of the application. | ||
6 | # python standard library | 6 | # python standard library |
7 | import asyncio | 7 | import asyncio |
8 | from collections import defaultdict | 8 | from collections import defaultdict |
9 | -# from contextlib import contextmanager # `with` statement in db sessions | ||
10 | from datetime import datetime | 9 | from datetime import datetime |
11 | import logging | 10 | import logging |
12 | from random import random | 11 | from random import random |
@@ -45,18 +44,25 @@ class LearnApp(): | @@ -45,18 +44,25 @@ class LearnApp(): | ||
45 | ''' | 44 | ''' |
46 | LearnApp - application logic | 45 | LearnApp - application logic |
47 | 46 | ||
48 | - self.deps - networkx topic dependencies | ||
49 | - self.courses - dict {course_id: {'title': ..., | ||
50 | - 'description': ..., | ||
51 | - 'goals': ...,}, ...} | ||
52 | - self.factory = dict {qref: QFactory()} | ||
53 | - self.online - dict {student_id: {'number': ..., | ||
54 | - 'name': ..., | ||
55 | - 'state': StudentState(), | ||
56 | - 'counter': ...}, ...} | 47 | + self.deps = networkx topic dependencies |
48 | + self.courses = { | ||
49 | + course_id: { | ||
50 | + 'title': ..., | ||
51 | + 'description': ..., | ||
52 | + 'goals': ..., | ||
53 | + }, ... | ||
54 | + } | ||
55 | + self.factory = { qref: QFactory() } | ||
56 | + self.online = { | ||
57 | + student_id: { | ||
58 | + 'number': ..., | ||
59 | + 'name': ..., | ||
60 | + 'state': StudentState(), | ||
61 | + 'counter': ... | ||
62 | + }, ... | ||
63 | + } | ||
57 | ''' | 64 | ''' |
58 | 65 | ||
59 | - # ------------------------------------------------------------------------ | ||
60 | def __init__(self, | 66 | def __init__(self, |
61 | courses: str, # filename with course configurations | 67 | courses: str, # filename with course configurations |
62 | prefix: str, # path to topics | 68 | prefix: str, # path to topics |
@@ -114,7 +120,6 @@ class LearnApp(): | @@ -114,7 +120,6 @@ class LearnApp(): | ||
114 | if check: | 120 | if check: |
115 | self._sanity_check_questions() | 121 | self._sanity_check_questions() |
116 | 122 | ||
117 | - # ------------------------------------------------------------------------ | ||
118 | def _sanity_check_questions(self) -> None: | 123 | def _sanity_check_questions(self) -> None: |
119 | ''' | 124 | ''' |
120 | Unit tests for all questions | 125 | Unit tests for all questions |
@@ -159,7 +164,6 @@ class LearnApp(): | @@ -159,7 +164,6 @@ class LearnApp(): | ||
159 | raise LearnException('Sanity checks') | 164 | raise LearnException('Sanity checks') |
160 | logger.info(' 0 errors found.') | 165 | logger.info(' 0 errors found.') |
161 | 166 | ||
162 | - # ------------------------------------------------------------------------ | ||
163 | async def login(self, uid: str, password: str) -> bool: | 167 | async def login(self, uid: str, password: str) -> bool: |
164 | '''user login''' | 168 | '''user login''' |
165 | 169 | ||
@@ -212,13 +216,11 @@ class LearnApp(): | @@ -212,13 +216,11 @@ class LearnApp(): | ||
212 | 216 | ||
213 | return pw_ok | 217 | return pw_ok |
214 | 218 | ||
215 | - # ------------------------------------------------------------------------ | ||
216 | def logout(self, uid: str) -> None: | 219 | def logout(self, uid: str) -> None: |
217 | '''User logout''' | 220 | '''User logout''' |
218 | del self.online[uid] | 221 | del self.online[uid] |
219 | logger.info('User "%s" logged out', uid) | 222 | logger.info('User "%s" logged out', uid) |
220 | 223 | ||
221 | - # ------------------------------------------------------------------------ | ||
222 | async def change_password(self, uid: str, password: str) -> bool: | 224 | async def change_password(self, uid: str, password: str) -> bool: |
223 | ''' | 225 | ''' |
224 | Change user Password. | 226 | Change user Password. |
@@ -242,7 +244,6 @@ class LearnApp(): | @@ -242,7 +244,6 @@ class LearnApp(): | ||
242 | logger.info('User "%s" changed password', uid) | 244 | logger.info('User "%s" changed password', uid) |
243 | return True | 245 | return True |
244 | 246 | ||
245 | - # ------------------------------------------------------------------------ | ||
246 | async def check_answer(self, uid: str, answer) -> Question: | 247 | async def check_answer(self, uid: str, answer) -> Question: |
247 | ''' | 248 | ''' |
248 | Checks answer and update database. | 249 | Checks answer and update database. |
@@ -271,7 +272,6 @@ class LearnApp(): | @@ -271,7 +272,6 @@ class LearnApp(): | ||
271 | 272 | ||
272 | return question | 273 | return question |
273 | 274 | ||
274 | - # ------------------------------------------------------------------------ | ||
275 | async def get_question(self, uid: str) -> Optional[Question]: | 275 | async def get_question(self, uid: str) -> Optional[Question]: |
276 | ''' | 276 | ''' |
277 | Get the question to show (current or new one) | 277 | Get the question to show (current or new one) |
@@ -318,7 +318,6 @@ class LearnApp(): | @@ -318,7 +318,6 @@ class LearnApp(): | ||
318 | 318 | ||
319 | return question | 319 | return question |
320 | 320 | ||
321 | - # ------------------------------------------------------------------------ | ||
322 | def start_course(self, uid: str, course_id: str) -> None: | 321 | def start_course(self, uid: str, course_id: str) -> None: |
323 | '''Start course''' | 322 | '''Start course''' |
324 | 323 | ||
@@ -331,9 +330,6 @@ class LearnApp(): | @@ -331,9 +330,6 @@ class LearnApp(): | ||
331 | else: | 330 | else: |
332 | logger.info('User "%s" course "%s"', uid, course_id) | 331 | logger.info('User "%s" course "%s"', uid, course_id) |
333 | 332 | ||
334 | - # ------------------------------------------------------------------------ | ||
335 | - # | ||
336 | - # ------------------------------------------------------------------------ | ||
337 | async def start_topic(self, uid: str, topic: str) -> None: | 333 | async def start_topic(self, uid: str, topic: str) -> None: |
338 | '''Start new topic''' | 334 | '''Start new topic''' |
339 | 335 | ||
@@ -350,9 +346,6 @@ class LearnApp(): | @@ -350,9 +346,6 @@ class LearnApp(): | ||
350 | else: | 346 | else: |
351 | logger.info('User "%s" started topic "%s"', uid, topic) | 347 | logger.info('User "%s" started topic "%s"', uid, topic) |
352 | 348 | ||
353 | - # ------------------------------------------------------------------------ | ||
354 | - # | ||
355 | - # ------------------------------------------------------------------------ | ||
356 | def _add_missing_topics(self, topics: Iterable[str]) -> None: | 349 | def _add_missing_topics(self, topics: Iterable[str]) -> None: |
357 | ''' | 350 | ''' |
358 | Fill db table 'Topic' with topics from the graph, if new | 351 | Fill db table 'Topic' with topics from the graph, if new |
@@ -365,7 +358,6 @@ class LearnApp(): | @@ -365,7 +358,6 @@ class LearnApp(): | ||
365 | session.commit() | 358 | session.commit() |
366 | logger.info('Added %d new topic(s) to the database', len(new)) | 359 | logger.info('Added %d new topic(s) to the database', len(new)) |
367 | 360 | ||
368 | - # ------------------------------------------------------------------------ | ||
369 | def _db_setup(self, database: str) -> None: | 361 | def _db_setup(self, database: str) -> None: |
370 | ''' | 362 | ''' |
371 | Setup and check database contents | 363 | Setup and check database contents |
@@ -395,7 +387,6 @@ class LearnApp(): | @@ -395,7 +387,6 @@ class LearnApp(): | ||
395 | logger.info('%6d topics', count_topics) | 387 | logger.info('%6d topics', count_topics) |
396 | logger.info('%6d answers', count_answers) | 388 | logger.info('%6d answers', count_answers) |
397 | 389 | ||
398 | - # ------------------------------------------------------------------------ | ||
399 | def _populate_graph(self, config: Dict[str, Any]) -> None: | 390 | def _populate_graph(self, config: Dict[str, Any]) -> None: |
400 | ''' | 391 | ''' |
401 | Populates a digraph. | 392 | Populates a digraph. |
@@ -437,12 +428,10 @@ class LearnApp(): | @@ -437,12 +428,10 @@ class LearnApp(): | ||
437 | # prefix/topic | 428 | # prefix/topic |
438 | topic['path'] = join(self.deps.graph['prefix'], tref) | 429 | topic['path'] = join(self.deps.graph['prefix'], tref) |
439 | 430 | ||
440 | - | ||
441 | - # ======================================================================== | 431 | + # ------------------------------------------------------------------------ |
442 | # methods that do not change state (pure functions) | 432 | # methods that do not change state (pure functions) |
443 | - # ======================================================================== | ||
444 | - | ||
445 | # ------------------------------------------------------------------------ | 433 | # ------------------------------------------------------------------------ |
434 | + | ||
446 | def _make_factory(self) -> Dict[str, QFactory]: | 435 | def _make_factory(self) -> Dict[str, QFactory]: |
447 | ''' | 436 | ''' |
448 | Buils dictionary of question factories | 437 | Buils dictionary of question factories |
@@ -519,38 +508,31 @@ class LearnApp(): | @@ -519,38 +508,31 @@ class LearnApp(): | ||
519 | 508 | ||
520 | return factory | 509 | return factory |
521 | 510 | ||
522 | - # ------------------------------------------------------------------------ | ||
523 | def get_login_counter(self, uid: str) -> int: | 511 | def get_login_counter(self, uid: str) -> int: |
524 | '''login counter''' # FIXME | 512 | '''login counter''' # FIXME |
525 | return int(self.online[uid]['counter']) | 513 | return int(self.online[uid]['counter']) |
526 | 514 | ||
527 | - # ------------------------------------------------------------------------ | ||
528 | def get_student_name(self, uid: str) -> str: | 515 | def get_student_name(self, uid: str) -> str: |
529 | '''Get the username''' | 516 | '''Get the username''' |
530 | return self.online[uid].get('name', '') | 517 | return self.online[uid].get('name', '') |
531 | 518 | ||
532 | - # ------------------------------------------------------------------------ | ||
533 | def get_student_state(self, uid: str) -> List[Dict[str, Any]]: | 519 | def get_student_state(self, uid: str) -> List[Dict[str, Any]]: |
534 | '''Get the knowledge state of a given user''' | 520 | '''Get the knowledge state of a given user''' |
535 | return self.online[uid]['state'].get_knowledge_state() | 521 | return self.online[uid]['state'].get_knowledge_state() |
536 | 522 | ||
537 | - # ------------------------------------------------------------------------ | ||
538 | def get_student_progress(self, uid: str) -> float: | 523 | def get_student_progress(self, uid: str) -> float: |
539 | '''Get the current topic progress of a given user''' | 524 | '''Get the current topic progress of a given user''' |
540 | return float(self.online[uid]['state'].get_topic_progress()) | 525 | return float(self.online[uid]['state'].get_topic_progress()) |
541 | 526 | ||
542 | - # ------------------------------------------------------------------------ | ||
543 | def get_current_question(self, uid: str) -> Optional[Question]: | 527 | def get_current_question(self, uid: str) -> Optional[Question]: |
544 | '''Get the current question of a given user''' | 528 | '''Get the current question of a given user''' |
545 | question: Optional[Question] = self.online[uid]['state'].get_current_question() | 529 | question: Optional[Question] = self.online[uid]['state'].get_current_question() |
546 | return question | 530 | return question |
547 | 531 | ||
548 | - # ------------------------------------------------------------------------ | ||
549 | def get_current_question_id(self, uid: str) -> str: | 532 | def get_current_question_id(self, uid: str) -> str: |
550 | '''Get id of the current question for a given user''' | 533 | '''Get id of the current question for a given user''' |
551 | return str(self.online[uid]['state'].get_current_question()['qid']) | 534 | return str(self.online[uid]['state'].get_current_question()['qid']) |
552 | 535 | ||
553 | - # ------------------------------------------------------------------------ | ||
554 | def get_student_question_type(self, uid: str) -> str: | 536 | def get_student_question_type(self, uid: str) -> str: |
555 | '''Get type of the current question for a given user''' | 537 | '''Get type of the current question for a given user''' |
556 | return str(self.online[uid]['state'].get_current_question()['type']) | 538 | return str(self.online[uid]['state'].get_current_question()['type']) |
@@ -559,12 +541,10 @@ class LearnApp(): | @@ -559,12 +541,10 @@ class LearnApp(): | ||
559 | # def get_student_topic(self, uid: str) -> str: | 541 | # def get_student_topic(self, uid: str) -> str: |
560 | # return str(self.online[uid]['state'].get_current_topic()) | 542 | # return str(self.online[uid]['state'].get_current_topic()) |
561 | 543 | ||
562 | - # ------------------------------------------------------------------------ | ||
563 | def get_student_course_title(self, uid: str) -> str: | 544 | def get_student_course_title(self, uid: str) -> str: |
564 | '''get the title of the current course for a given user''' | 545 | '''get the title of the current course for a given user''' |
565 | return str(self.online[uid]['state'].get_current_course_title()) | 546 | return str(self.online[uid]['state'].get_current_course_title()) |
566 | 547 | ||
567 | - # ------------------------------------------------------------------------ | ||
568 | def get_current_course_id(self, uid: str) -> Optional[str]: | 548 | def get_current_course_id(self, uid: str) -> Optional[str]: |
569 | '''get the current course (id) of a given user''' | 549 | '''get the current course (id) of a given user''' |
570 | cid: Optional[str] = self.online[uid]['state'].get_current_course_id() | 550 | cid: Optional[str] = self.online[uid]['state'].get_current_course_id() |
@@ -574,7 +554,6 @@ class LearnApp(): | @@ -574,7 +554,6 @@ class LearnApp(): | ||
574 | # def get_topic_name(self, ref: str) -> str: | 554 | # def get_topic_name(self, ref: str) -> str: |
575 | # return str(self.deps.nodes[ref]['name']) | 555 | # return str(self.deps.nodes[ref]['name']) |
576 | 556 | ||
577 | - # ------------------------------------------------------------------------ | ||
578 | def get_current_public_dir(self, uid: str) -> str: | 557 | def get_current_public_dir(self, uid: str) -> str: |
579 | ''' | 558 | ''' |
580 | Get the path for the 'public' directory of the current topic of the | 559 | Get the path for the 'public' directory of the current topic of the |
@@ -586,21 +565,18 @@ class LearnApp(): | @@ -586,21 +565,18 @@ class LearnApp(): | ||
586 | prefix: str = self.deps.graph['prefix'] | 565 | prefix: str = self.deps.graph['prefix'] |
587 | return join(prefix, topic, 'public') | 566 | return join(prefix, topic, 'public') |
588 | 567 | ||
589 | - # ------------------------------------------------------------------------ | ||
590 | def get_courses(self) -> Dict[str, Dict[str, Any]]: | 568 | def get_courses(self) -> Dict[str, Dict[str, Any]]: |
591 | ''' | 569 | ''' |
592 | Get dictionary with all courses {'course1': {...}, 'course2': {...}} | 570 | Get dictionary with all courses {'course1': {...}, 'course2': {...}} |
593 | ''' | 571 | ''' |
594 | return self.courses | 572 | return self.courses |
595 | 573 | ||
596 | - # ------------------------------------------------------------------------ | ||
597 | def get_course(self, course_id: str) -> Dict[str, Any]: | 574 | def get_course(self, course_id: str) -> Dict[str, Any]: |
598 | ''' | 575 | ''' |
599 | Get dictionary {'title': ..., 'description':..., 'goals':...} | 576 | Get dictionary {'title': ..., 'description':..., 'goals':...} |
600 | ''' | 577 | ''' |
601 | return self.courses[course_id] | 578 | return self.courses[course_id] |
602 | 579 | ||
603 | - # ------------------------------------------------------------------------ | ||
604 | def get_rankings(self, uid: str, cid: str) -> List[Tuple[str, str, float]]: | 580 | def get_rankings(self, uid: str, cid: str) -> List[Tuple[str, str, float]]: |
605 | ''' | 581 | ''' |
606 | Returns rankings for a certain cid (course_id). | 582 | Returns rankings for a certain cid (course_id). |
@@ -639,5 +615,3 @@ class LearnApp(): | @@ -639,5 +615,3 @@ class LearnApp(): | ||
639 | for u, name in students | 615 | for u, name in students |
640 | if u in progress and (len(u) > 2 or len(uid) <= 2)), | 616 | if u in progress and (len(u) > 2 or len(uid) <= 2)), |
641 | key=lambda x: x[2], reverse=True) | 617 | key=lambda x: x[2], reverse=True) |
642 | - | ||
643 | - # ------------------------------------------------------------------------ |
aprendizations/templates/maintopics-table.html
@@ -105,23 +105,23 @@ | @@ -105,23 +105,23 @@ | ||
105 | <tr> | 105 | <tr> |
106 | <th scope="row" class="text-muted text-center"> | 106 | <th scope="row" class="text-muted text-center"> |
107 | {% if t['type']=='chapter' %} | 107 | {% if t['type']=='chapter' %} |
108 | - <i class="bi bi-flag-fill"></i> | 108 | + <h5><i class="bi bi-flag-fill"></i></h5> |
109 | {% elif t['type']=='learn' %} | 109 | {% elif t['type']=='learn' %} |
110 | - <i class="bi bi-book"></i> | 110 | + <h5><i class="bi bi-book"></i></h5> |
111 | {% else %} | 111 | {% else %} |
112 | - <i class="bi bi-pencil"></i> | 112 | + <h5><i class="bi bi-pencil"></i></h5> |
113 | {% end %} | 113 | {% end %} |
114 | </th> | 114 | </th> |
115 | <td> | 115 | <td> |
116 | <div class="text-muted"> | 116 | <div class="text-muted"> |
117 | {% if t['ref'] not in course['goals'] %} | 117 | {% if t['ref'] not in course['goals'] %} |
118 | - <i class="bi bi-puzzle-fill"></i> | 118 | + <h5><i class="bi bi-puzzle-fill"></i></h5> |
119 | {% end %} | 119 | {% end %} |
120 | {{ t['name'] }} | 120 | {{ t['name'] }} |
121 | </div> | 121 | </div> |
122 | </td> | 122 | </td> |
123 | <td class="text-center"> | 123 | <td class="text-center"> |
124 | - <i class="bi bi-lock-fill text-muted"></i> | 124 | + <h5><i class="bi bi-lock-fill text-muted"></i></h5> |
125 | </td> | 125 | </td> |
126 | </tr> | 126 | </tr> |
127 | 127 | ||
@@ -131,30 +131,22 @@ | @@ -131,30 +131,22 @@ | ||
131 | <th scope="row" class="text-primary text-center"> | 131 | <th scope="row" class="text-primary text-center"> |
132 | {% if t['type']=='chapter' %} | 132 | {% if t['type']=='chapter' %} |
133 | <span class="text-nowrap" data-toggle="tooltip" data-placement="bottom" title="Fim do capítulo"> | 133 | <span class="text-nowrap" data-toggle="tooltip" data-placement="bottom" title="Fim do capítulo"> |
134 | - <h5> | ||
135 | - <i class="bi bi-flag-fill"></i> | ||
136 | - </h5> | 134 | + <h5><i class="bi bi-flag-fill"></i></h5> |
137 | </span> | 135 | </span> |
138 | {% elif t['type']=='learn' %} | 136 | {% elif t['type']=='learn' %} |
139 | <span class="text-nowrap" data-toggle="tooltip" data-placement="bottom" title="Texto com matéria"> | 137 | <span class="text-nowrap" data-toggle="tooltip" data-placement="bottom" title="Texto com matéria"> |
140 | - <h5> | ||
141 | - <i class="bi bi-book"></i> | ||
142 | - </h5> | 138 | + <h5><i class="bi bi-book"></i></h5> |
143 | </span> | 139 | </span> |
144 | {% else %} | 140 | {% else %} |
145 | <span class="text-nowrap" data-toggle="tooltip" data-placement="bottom" title="Exercícios"> | 141 | <span class="text-nowrap" data-toggle="tooltip" data-placement="bottom" title="Exercícios"> |
146 | - <h5> | ||
147 | - <i class="bi bi-pencil"></i> | ||
148 | - </h5> | 142 | + <h5><i class="bi bi-pencil"></i></h5> |
149 | </span> | 143 | </span> |
150 | {% end %} | 144 | {% end %} |
151 | </th> | 145 | </th> |
152 | <td class="text-primary"> | 146 | <td class="text-primary"> |
153 | {% if t['ref'] not in course['goals'] %} | 147 | {% if t['ref'] not in course['goals'] %} |
154 | <span class="text-nowrap" data-toggle="tooltip" data-placement="bottom" title="Pré-requisito para este curso"> | 148 | <span class="text-nowrap" data-toggle="tooltip" data-placement="bottom" title="Pré-requisito para este curso"> |
155 | - <h5> | ||
156 | - <i class="bi bi-puzzle-fill"></i> | ||
157 | - </h5> | 149 | + <h5><i class="bi bi-puzzle-fill"></i></h5> |
158 | </span> | 150 | </span> |
159 | {% end %} | 151 | {% end %} |
160 | {{ t['name'] }} | 152 | {{ t['name'] }} |
@@ -162,18 +154,12 @@ | @@ -162,18 +154,12 @@ | ||
162 | 154 | ||
163 | <td class="text-center"> | 155 | <td class="text-center"> |
164 | {% if t['level'] < 0.01 %} | 156 | {% if t['level'] < 0.01 %} |
165 | - <h5> | ||
166 | - <i class="bi bi-unlock-fill text-success"></i> | ||
167 | - </h5> | 157 | + <h5><i class="bi bi-unlock-fill text-success"></i></h5> |
168 | {% elif t['type']=='chapter' %} | 158 | {% elif t['type']=='chapter' %} |
169 | - <h5> | ||
170 | - <i class="bi bi-award-fill"></i> | ||
171 | - </h5> | 159 | + <h5><i class="bi bi-award-fill"></i></h5> |
172 | {% else %} | 160 | {% else %} |
173 | <span class="text-nowrap text-warning" data-toggle="tooltip" data-placement="bottom" title="{{round(t['level']*5, 3)}}"> | 161 | <span class="text-nowrap text-warning" data-toggle="tooltip" data-placement="bottom" title="{{round(t['level']*5, 3)}}"> |
174 | - <h5> | ||
175 | - {{ int(t['level']*5+0.25)*'<i class="bi bi-star-fill"></i>' }}{% if int(t['level']*5+0.25) < 5 %}{{'<i class="bi bi-star-half"></i>' if 0.25 <= t['level']*5-int(t['level']*5) < 0.75 else '<i class="bi bi-star"></i>'}}{% end %}{{ (4-int(t['level']*5+0.25))*'<i class="bi bi-star"></i>' }} | ||
176 | - </h5> | 162 | + <h5>{{ int(t['level']*5+0.25)*'<i class="bi bi-star-fill"></i>' }}{% if int(t['level']*5+0.25) < 5 %}{{'<i class="bi bi-star-half"></i>' if 0.25 <= t['level']*5-int(t['level']*5) < 0.75 else '<i class="bi bi-star"></i>'}}{% end %}{{ (4-int(t['level']*5+0.25))*'<i class="bi bi-star"></i>' }}</h5> |
177 | </span> | 163 | </span> |
178 | {% end %} <!-- if --> | 164 | {% end %} <!-- if --> |
179 | </td> | 165 | </td> |