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