Commit 1d65b0b71481e46943b1baa64534f1d507ff8db0
Exists in
master
and in
1 other branch
Merge branch 'dev'
Showing
4 changed files
with
30 additions
and
44 deletions
Show diff stats
BUGS.md
| 1 | -# BUGS | |
| 1 | +# Bugs and Wishlist | |
| 2 | + | |
| 3 | +## BUGS | |
| 2 | 4 | |
| 3 | 5 | - nao esta a respeitar o numero de tentativas `max_tries`. |
| 4 | 6 | - se na especificacao de um curso, a referencia do topico nao existir como |
| 5 | 7 | directorio, rebenta. |
| 6 | 8 | - internal server error ao fazer logout no macos python3.8 |
| 7 | -- GET can get filtered by browser cache | |
| 8 | 9 | - topicos chapter devem ser automaticamente completos assim que as dependencias |
| 9 | 10 | são satisfeitas. Nao devia ser necessario (ou possivel?) clicar neles. |
| 10 | 11 | - topicos do tipo learn deviam por defeito nao ser randomizados e assumir |
| ... | ... | @@ -23,11 +24,11 @@ |
| 23 | 24 | - shift-enter não está a funcionar |
| 24 | 25 | - default prefix should be obtained from each course (yaml conf)? |
| 25 | 26 | |
| 26 | -# TODO | |
| 27 | +## TODO | |
| 27 | 28 | |
| 28 | -- shuffle das perguntas dentro de um topico | |
| 29 | 29 | - alterar tabelas para incluir email de recuperacao de password (e outros |
| 30 | 30 | avisos) |
| 31 | +- shuffle das perguntas dentro de um topico | |
| 31 | 32 | - registar `last_seen` e remover os antigos de cada vez que houver um login. |
| 32 | 33 | - indicar qtos topicos faltam (>=50%) para terminar o curso. |
| 33 | 34 | - ao fim de 3 tentativas com password errada, envia email com nova password. |
| ... | ... | @@ -50,8 +51,9 @@ |
| 50 | 51 | mais falhadas, tempo médio por pergunta. |
| 51 | 52 | - normalizar com perguntations. |
| 52 | 53 | |
| 53 | -# FIXED | |
| 54 | +## FIXED | |
| 54 | 55 | |
| 56 | +- rankings rebenta se nunhum aluno tiver feito nenhum topico. | |
| 55 | 57 | - templates question-*.html tem input hidden question_ref que não é usado. |
| 56 | 58 | remover? |
| 57 | 59 | - goals se forem do tipo chapter deve importar todas as dependencias do chapter. | ... | ... |
aprendizations/learnapp.py
| ... | ... | @@ -288,7 +288,9 @@ class LearnApp(): |
| 288 | 288 | logger.info('User "%s" finished "%s" (level=%.2f)', |
| 289 | 289 | uid, topic_id, level) |
| 290 | 290 | |
| 291 | - query = select(StudentTopic).where(StudentTopic.student_id == uid).where(StudentTopic.topic_id == topic_id) | |
| 291 | + query = select(StudentTopic) \ | |
| 292 | + .where(StudentTopic.student_id == uid) \ | |
| 293 | + .where(StudentTopic.topic_id == topic_id) | |
| 292 | 294 | with Session(self._engine, future=True) as session: |
| 293 | 295 | student_topic = session.execute(query).scalar_one_or_none() |
| 294 | 296 | |
| ... | ... | @@ -599,9 +601,9 @@ class LearnApp(): |
| 599 | 601 | return self.courses[course_id] |
| 600 | 602 | |
| 601 | 603 | # ------------------------------------------------------------------------ |
| 602 | - def get_rankings(self, uid: str, course_id: str) -> Iterable[Tuple[str, str, float, float]]: | |
| 604 | + def get_rankings(self, uid: str, cid: str) -> List[Tuple[str, str, float]]: | |
| 603 | 605 | ''' |
| 604 | - Returns rankings for a certain course_id. | |
| 606 | + Returns rankings for a certain cid (course_id). | |
| 605 | 607 | User where uid have <=2 chars are considered ghosts are hidden from |
| 606 | 608 | the rankings. This is so that there can be users for development or |
| 607 | 609 | testing purposes, which are not real users. |
| ... | ... | @@ -609,16 +611,13 @@ class LearnApp(): |
| 609 | 611 | This should be modified to have a "visible" flag |
| 610 | 612 | ''' |
| 611 | 613 | |
| 612 | - logger.info('User "%s" rankings for "%s"', uid, course_id) | |
| 614 | + logger.info('User "%s" rankings for "%s"', uid, cid) | |
| 615 | + query_students = select(Student.id, Student.name) | |
| 616 | + query_student_topics = select(StudentTopic.student_id, | |
| 617 | + StudentTopic.topic_id, | |
| 618 | + StudentTopic.level, | |
| 619 | + StudentTopic.date) | |
| 613 | 620 | with Session(self._engine, future=True) as session: |
| 614 | - query_students = select(Student.id, Student.name) | |
| 615 | - query_student_topics = select(StudentTopic.student_id, | |
| 616 | - StudentTopic.topic_id, | |
| 617 | - StudentTopic.level, | |
| 618 | - StudentTopic.date) | |
| 619 | - query_total = select(Answer.student_id, func.count(Answer.ref)) | |
| 620 | - query_right = select(Answer.student_id, func.count(Answer.ref)) \ | |
| 621 | - .where(Answer.grade == 1.0) | |
| 622 | 621 | |
| 623 | 622 | # all students in the database FIXME only with answers of this course |
| 624 | 623 | students = session.execute(query_students).all() |
| ... | ... | @@ -626,28 +625,17 @@ class LearnApp(): |
| 626 | 625 | # topic levels FIXME only topics of this course |
| 627 | 626 | student_topics = session.execute(query_student_topics).all() |
| 628 | 627 | |
| 629 | - # answer performance | |
| 630 | - | |
| 631 | - # FIXME this does not work when nobody has done anything... | |
| 632 | - # FIXME row to dict seems to be deprecated in 1.4+ | |
| 633 | - total = dict(session.execute(query_total).all()) | |
| 634 | - right = dict(session.execute(query_right).all()) | |
| 635 | - | |
| 636 | - # compute percentage of right answers | |
| 637 | - perf: Dict[str, float] = {u: right.get(u, 0.0) / total[u] | |
| 638 | - for u in total} | |
| 639 | - | |
| 640 | 628 | # compute topic progress |
| 641 | 629 | now = datetime.now() |
| 642 | - goals = self.courses[course_id]['goals'] | |
| 630 | + goals = self.courses[cid]['goals'] | |
| 643 | 631 | progress: DefaultDict[str, float] = defaultdict(int) |
| 644 | 632 | |
| 645 | - for student, topic, level, date in student_topics: | |
| 633 | + for student, topic, level, datestr in student_topics: | |
| 646 | 634 | if topic in goals: |
| 647 | - date = datetime.strptime(date, "%Y-%m-%d %H:%M:%S.%f") | |
| 635 | + date = datetime.strptime(datestr, "%Y-%m-%d %H:%M:%S.%f") | |
| 648 | 636 | progress[student] += level**(now - date).days / len(goals) |
| 649 | 637 | |
| 650 | - return sorted(((u, name, progress[u], perf.get(u, 0.0)) | |
| 638 | + return sorted(((u, name, progress[u]) | |
| 651 | 639 | for u, name in students |
| 652 | 640 | if u in progress and (len(u) > 2 or len(uid) <= 2)), |
| 653 | 641 | key=lambda x: x[2], reverse=True) | ... | ... |
aprendizations/templates/rankings.html
| ... | ... | @@ -61,7 +61,6 @@ |
| 61 | 61 | <tr> |
| 62 | 62 | <th scope="col" class="text-center">Posição</th> |
| 63 | 63 | <th scope="col">Aluno</th> |
| 64 | - <th scope="col"></th> | |
| 65 | 64 | <th scope="col">Progresso</th> |
| 66 | 65 | </tr> |
| 67 | 66 | </thead> |
| ... | ... | @@ -76,9 +75,6 @@ |
| 76 | 75 | <td> <!-- student name --> |
| 77 | 76 | {{ ' '.join(r[1].split()[n] for n in (0,-1)) }} |
| 78 | 77 | </td> |
| 79 | - <td> <!-- nice --> | |
| 80 | - {{ '<i class="far fa-thumbs-up text-success" title="Mais de 75% de respostas correctas"></i>' if r[3] > 0.75 else '' }} | |
| 81 | - </td> | |
| 82 | 78 | <td> <!-- progress --> |
| 83 | 79 | <div class="progress" style="height: 24px;"> |
| 84 | 80 | <div class="progress-bar" role="progressbar" style="width: {{ 100*r[2] }}%;" aria-valuenow="{{round(100*r[2])}}%" aria-valuemin="0" aria-valuemax="100">{{round(100*r[2])}}%</div> | ... | ... |
mypy.ini
| ... | ... | @@ -2,14 +2,14 @@ |
| 2 | 2 | python_version = 3.9 |
| 3 | 3 | plugins = sqlalchemy.ext.mypy.plugin |
| 4 | 4 | |
| 5 | -[mypy-pygments.*] | |
| 6 | -ignore_missing_imports = True | |
| 5 | +; [mypy-pygments.*] | |
| 6 | +; ignore_missing_imports = True | |
| 7 | 7 | |
| 8 | -[mypy-networkx.*] | |
| 9 | -ignore_missing_imports = True | |
| 8 | +; [mypy-networkx.*] | |
| 9 | +; ignore_missing_imports = True | |
| 10 | 10 | |
| 11 | -[mypy-bcrypt.*] | |
| 12 | -ignore_missing_imports = True | |
| 11 | +; [mypy-bcrypt.*] | |
| 12 | +; ignore_missing_imports = True | |
| 13 | 13 | |
| 14 | -[mypy-mistune.*] | |
| 15 | -ignore_missing_imports = True | |
| 14 | +; [mypy-mistune.*] | |
| 15 | +; ignore_missing_imports = True | ... | ... |