Commit 1d65b0b71481e46943b1baa64534f1d507ff8db0

Authored by Miguel Barão
2 parents e55079ef 6c5a961a
Exists in master and in 1 other branch dev

Merge branch 'dev'

1 -# BUGS 1 +# Bugs and Wishlist
  2 +
  3 +## BUGS
2 4
3 - nao esta a respeitar o numero de tentativas `max_tries`. 5 - nao esta a respeitar o numero de tentativas `max_tries`.
4 - se na especificacao de um curso, a referencia do topico nao existir como 6 - se na especificacao de um curso, a referencia do topico nao existir como
5 directorio, rebenta. 7 directorio, rebenta.
6 - internal server error ao fazer logout no macos python3.8 8 - internal server error ao fazer logout no macos python3.8
7 -- GET can get filtered by browser cache  
8 - topicos chapter devem ser automaticamente completos assim que as dependencias 9 - topicos chapter devem ser automaticamente completos assim que as dependencias
9 são satisfeitas. Nao devia ser necessario (ou possivel?) clicar neles. 10 são satisfeitas. Nao devia ser necessario (ou possivel?) clicar neles.
10 - topicos do tipo learn deviam por defeito nao ser randomizados e assumir 11 - topicos do tipo learn deviam por defeito nao ser randomizados e assumir
@@ -23,11 +24,11 @@ @@ -23,11 +24,11 @@
23 - shift-enter não está a funcionar 24 - shift-enter não está a funcionar
24 - default prefix should be obtained from each course (yaml conf)? 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 - alterar tabelas para incluir email de recuperacao de password (e outros 29 - alterar tabelas para incluir email de recuperacao de password (e outros
30 avisos) 30 avisos)
  31 +- shuffle das perguntas dentro de um topico
31 - registar `last_seen` e remover os antigos de cada vez que houver um login. 32 - registar `last_seen` e remover os antigos de cada vez que houver um login.
32 - indicar qtos topicos faltam (>=50%) para terminar o curso. 33 - indicar qtos topicos faltam (>=50%) para terminar o curso.
33 - ao fim de 3 tentativas com password errada, envia email com nova password. 34 - ao fim de 3 tentativas com password errada, envia email com nova password.
@@ -50,8 +51,9 @@ @@ -50,8 +51,9 @@
50 mais falhadas, tempo médio por pergunta. 51 mais falhadas, tempo médio por pergunta.
51 - normalizar com perguntations. 52 - normalizar com perguntations.
52 53
53 -# FIXED 54 +## FIXED
54 55
  56 +- rankings rebenta se nunhum aluno tiver feito nenhum topico.
55 - templates question-*.html tem input hidden question_ref que não é usado. 57 - templates question-*.html tem input hidden question_ref que não é usado.
56 remover? 58 remover?
57 - goals se forem do tipo chapter deve importar todas as dependencias do chapter. 59 - goals se forem do tipo chapter deve importar todas as dependencias do chapter.
aprendizations/learnapp.py
@@ -288,7 +288,9 @@ class LearnApp(): @@ -288,7 +288,9 @@ class LearnApp():
288 logger.info('User "%s" finished "%s" (level=%.2f)', 288 logger.info('User "%s" finished "%s" (level=%.2f)',
289 uid, topic_id, level) 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 with Session(self._engine, future=True) as session: 294 with Session(self._engine, future=True) as session:
293 student_topic = session.execute(query).scalar_one_or_none() 295 student_topic = session.execute(query).scalar_one_or_none()
294 296
@@ -599,9 +601,9 @@ class LearnApp(): @@ -599,9 +601,9 @@ class LearnApp():
599 return self.courses[course_id] 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 User where uid have <=2 chars are considered ghosts are hidden from 607 User where uid have <=2 chars are considered ghosts are hidden from
606 the rankings. This is so that there can be users for development or 608 the rankings. This is so that there can be users for development or
607 testing purposes, which are not real users. 609 testing purposes, which are not real users.
@@ -609,16 +611,13 @@ class LearnApp(): @@ -609,16 +611,13 @@ class LearnApp():
609 This should be modified to have a "visible" flag 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 with Session(self._engine, future=True) as session: 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 # all students in the database FIXME only with answers of this course 622 # all students in the database FIXME only with answers of this course
624 students = session.execute(query_students).all() 623 students = session.execute(query_students).all()
@@ -626,28 +625,17 @@ class LearnApp(): @@ -626,28 +625,17 @@ class LearnApp():
626 # topic levels FIXME only topics of this course 625 # topic levels FIXME only topics of this course
627 student_topics = session.execute(query_student_topics).all() 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 # compute topic progress 628 # compute topic progress
641 now = datetime.now() 629 now = datetime.now()
642 - goals = self.courses[course_id]['goals'] 630 + goals = self.courses[cid]['goals']
643 progress: DefaultDict[str, float] = defaultdict(int) 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 if topic in goals: 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 progress[student] += level**(now - date).days / len(goals) 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 for u, name in students 639 for u, name in students
652 if u in progress and (len(u) > 2 or len(uid) <= 2)), 640 if u in progress and (len(u) > 2 or len(uid) <= 2)),
653 key=lambda x: x[2], reverse=True) 641 key=lambda x: x[2], reverse=True)
aprendizations/templates/rankings.html
@@ -61,7 +61,6 @@ @@ -61,7 +61,6 @@
61 <tr> 61 <tr>
62 <th scope="col" class="text-center">Posição</th> 62 <th scope="col" class="text-center">Posição</th>
63 <th scope="col">Aluno</th> 63 <th scope="col">Aluno</th>
64 - <th scope="col"></th>  
65 <th scope="col">Progresso</th> 64 <th scope="col">Progresso</th>
66 </tr> 65 </tr>
67 </thead> 66 </thead>
@@ -76,9 +75,6 @@ @@ -76,9 +75,6 @@
76 <td> <!-- student name --> 75 <td> <!-- student name -->
77 {{ ' '.join(r[1].split()[n] for n in (0,-1)) }} 76 {{ ' '.join(r[1].split()[n] for n in (0,-1)) }}
78 </td> 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 <td> <!-- progress --> 78 <td> <!-- progress -->
83 <div class="progress" style="height: 24px;"> 79 <div class="progress" style="height: 24px;">
84 <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> 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>
@@ -2,14 +2,14 @@ @@ -2,14 +2,14 @@
2 python_version = 3.9 2 python_version = 3.9
3 plugins = sqlalchemy.ext.mypy.plugin 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