Commit 8b4ac80ad8069fb0bb8d73b59baf6680b802547f

Authored by Miguel Barão
1 parent d187aad4
Exists in master and in 1 other branch dev

- fixed menus

- mathjax3 seems to be working fine
- fixed finish_topics redirect
working... with bugs...
BUGS.md
1 1  
2 2 # BUGS
3 3  
  4 +- nao esta a seguir o max_tries definido no ficheiro de dependencias.
  5 +- no curso de linear algebra, as perguntas estao shuffled, mas nao deviam estar... nao esta a obedecer a keyword shuffle.
  6 +- obter rankings por curso GET course=course_id
  7 +- impedir que quando students.db não é encontrado, crie um ficheiro vazio.
4 8 - classificacoes so devia mostrar os que ja fizeram alguma coisa
5   -- menu nao mostra as opcoes correctamente
6   -- mathjax nao esta a correr sobre o titulo e sobre as solucoes.
7 9 - QFactory.generate() devia fazer run da gen_async, ou remover.
8   -- finish topic vai para a lista de cursos. devia ficar no mesmo curso.
9 10 - marking all options right in a radio question breaks!
10   -- impedir que quando students.db não é encontrado, crie um ficheiro vazio.
11 11 - opcao --prefix devia afectar a base de dados?
12 12 - duplo clicks no botao "responder" dessincroniza as questões, ver debounce em https://stackoverflow.com/questions/20281546/how-to-prevent-calling-of-en-event-handler-twice-on-fast-clicks
13 13 - quando termina topico devia apagar as perguntas todas (se falhar a gerar novo topico, aparecem perguntas do antigo)
... ... @@ -16,8 +16,6 @@
16 16 - permitir configuracao para escolher entre static files locais ou remotos
17 17 - sqlalchemy.pool.impl.NullPool: Exception during reset or similar
18 18 sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread.
19   -
20   -- porque é que md() é usado nos templates e não directamente no codigo python?
21 19 - templates question-*.html tem input hidden question_ref que não é usado. remover?
22 20 - guardar o estado a meio de um nível.
23 21 - safari as vezes envia dois gets no inicio do topico. nesses casos, a segunda pergunta não é actualizada no browser... o topico tem de ser gerado qd se escolhe o topico em main_topics. O get nao deve alterar o estado.
... ... @@ -50,6 +48,9 @@ sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in
50 48  
51 49 # FIXED
52 50  
  51 +- menu nao mostra as opcoes correctamente
  52 +- finish topic vai para a lista de cursos. devia ficar no mesmo curso.
  53 +- mathjax nao esta a correr sobre o titulo.
53 54 - forgetting factor is hardcoded in student.py
54 55 - add aprendizatons --version
55 56 - se aluno abre dois tabs no browser, conseque navegar em simultaneo para perguntas diferentes. quando submete uma delas dá asneira. Tem de haver um campo hidden que tenha um céodigo único que indique qual a pergunta. do lado do servidor apnas há o codigo da pergunta corrente, se forem diferentes faz redirect para /.
... ...
aprendizations/learnapp.py
... ... @@ -268,6 +268,7 @@ class LearnApp(object):
268 268 student.start_course(course)
269 269 except Exception as e:
270 270 logger.warning(f'"{uid}" could not start course "{course}": {e}')
  271 + raise
271 272 else:
272 273 logger.info(f'"{uid}" started course "{course}"')
273 274  
... ... @@ -452,6 +453,10 @@ class LearnApp(object):
452 453 return self.online[uid]['state'].get_current_course_title()
453 454  
454 455 # ------------------------------------------------------------------------
  456 + def get_student_course_id(self, uid: str) -> str:
  457 + return self.online[uid]['state'].get_current_course_id()
  458 +
  459 + # ------------------------------------------------------------------------
455 460 # def get_title(self) -> str:
456 461 # # return self.deps.graph.get('title', '')
457 462 # return self.
... ... @@ -471,15 +476,15 @@ class LearnApp(object):
471 476 return self.courses
472 477  
473 478 # ------------------------------------------------------------------------
474   - def get_rankings(self, uid: str) -> Iterable[Tuple[str, str, float, float]]:
  479 + def get_rankings(self, uid: str, course_id: str) -> Iterable[Tuple[str, str, float, float]]:
475 480  
476   - logger.info(f'User "{uid}" get rankings')
  481 + logger.info(f'User "{uid}" get rankings for {course_id}')
477 482 with self.db_session() as s:
478 483 students = s.query(Student.id, Student.name).all()
479 484  
480 485 # topic progress
481 486 student_topics = s.query(StudentTopic.student_id,
482   - StudentTopic.topic_id,
  487 + StudentTopic.topic_id, # FIXME Filter topics of the course
483 488 StudentTopic.level,
484 489 StudentTopic.date).all()
485 490 total_topics = s.query(Topic).count()
... ...
aprendizations/serve.py
... ... @@ -48,11 +48,10 @@ class WebApplication(tornado.web.Application):
48 48 (r'/change_password', ChangePasswordHandler),
49 49 (r'/question', QuestionHandler), # render question
50 50 (r'/rankings', RankingsHandler), # rankings table
51   - # (r'/topics', TopicsHandler), # show list of topics
52 51 (r'/topic/(.+)', TopicHandler), # start topic
53 52 (r'/file/(.+)', FileHandler), # serve file
54 53 (r'/courses', CoursesHandler), # show list of courses
55   - (r'/course/(.+)', CourseHandler), # show course topics
  54 + (r'/course/(.*)', CourseHandler), # show course topics
56 55 (r'/', RootHandler), # redirects
57 56 ]
58 57 settings = {
... ... @@ -96,12 +95,17 @@ class RankingsHandler(BaseHandler):
96 95 @tornado.web.authenticated
97 96 def get(self):
98 97 uid = self.current_user
99   - rankings = self.learn.get_rankings(uid)
  98 + current_course = self.learn.get_student_course_id(uid)
  99 + course_id = self.get_query_argument('course', default=current_course)
  100 + rankings = self.learn.get_rankings(uid, course_id)
100 101 self.render('rankings.html',
101 102 appname=APP_NAME,
102 103 uid=uid,
103 104 name=self.learn.get_student_name(uid),
104   - rankings=rankings)
  105 + rankings=rankings,
  106 + course_id=course_id,
  107 + course_title=self.learn.get_student_course_title(uid), # FIXME get from course var
  108 + )
105 109  
106 110  
107 111 # ----------------------------------------------------------------------------
... ... @@ -202,40 +206,25 @@ class CourseHandler(BaseHandler):
202 206 @tornado.web.authenticated
203 207 def get(self, course):
204 208 uid = self.current_user
  209 + if course == '':
  210 + course = self.learn.get_student_course_id(uid)
205 211  
206 212 try:
207 213 self.learn.start_course(uid, course)
208 214 except KeyError:
209 215 self.redirect('/courses')
210 216  
211   - # print('TITULO: ---------------->', self.learn.get_title())
212 217 self.render('maintopics-table.html',
213 218 appname=APP_NAME,
214 219 uid=uid,
215 220 name=self.learn.get_student_name(uid),
216 221 state=self.learn.get_student_state(uid),
217   - title=self.learn.get_student_course_title(uid),
  222 + course_title=self.learn.get_student_course_title(uid),
  223 + course_id=self.learn.get_student_course_id(uid),
218 224 )
219 225  
220 226  
221 227 # ----------------------------------------------------------------------------
222   -# /topics
223   -# Shows a list of topics and proficiency (stars, locked).
224   -# ----------------------------------------------------------------------------
225   -# class TopicsHandler(BaseHandler):
226   -# @tornado.web.authenticated
227   -# def get(self):
228   -# uid = self.current_user
229   -# self.render('maintopics-table.html',
230   -# appname=APP_NAME,
231   -# uid=uid,
232   -# name=self.learn.get_student_name(uid),
233   -# state=self.learn.get_student_state(uid),
234   -# title=self.learn.get_title(),
235   -# )
236   -
237   -
238   -# ----------------------------------------------------------------------------
239 228 # /topic/...
240 229 # Start a given topic
241 230 # ----------------------------------------------------------------------------
... ... @@ -253,6 +242,8 @@ class TopicHandler(BaseHandler):
253 242 appname=APP_NAME,
254 243 uid=uid,
255 244 name=self.learn.get_student_name(uid),
  245 + # course_title=self.learn.get_student_course_title(uid),
  246 + course_id=self.learn.get_student_course_id(uid),
256 247 )
257 248  
258 249  
... ...
aprendizations/static/js/topic.js
... ... @@ -55,7 +55,7 @@ function updateQuestion(response) {
55 55 $('#submit, #comments, #solution').remove();
56 56 $("#content").html(response["params"]["question"]).animateCSS('tada');
57 57 $('#topic_progress').css('width', '100%').attr('aria-valuenow', 100);
58   - setTimeout(function(){window.location.replace('/');}, 2000);
  58 + setTimeout(function(){window.location.replace('/course/');}, 2000);
59 59 break;
60 60 }
61 61 }
... ... @@ -137,7 +137,7 @@ function getFeedback(response) {
137 137 $("#right").hide();
138 138 $('#solution').html(params['solution']).animateCSS('flipInX');
139 139 // MathJax.Hub.Queue(["Typeset", MathJax.Hub, "#solution"]);
140   - MathJax.typeset();
  140 + MathJax.typeset();
141 141  
142 142 });
143 143 break;
... ...
aprendizations/student.py
... ... @@ -232,6 +232,10 @@ class StudentState(object):
232 232 return self.courses[self.current_course]['title']
233 233  
234 234 # ------------------------------------------------------------------------
  235 + def get_current_course_id(self) -> Optional[str]:
  236 + return self.current_course
  237 +
  238 + # ------------------------------------------------------------------------
235 239 def is_locked(self, topic: str) -> bool:
236 240 return topic not in self.state
237 241  
... ...
aprendizations/templates/courses.html
... ... @@ -33,16 +33,16 @@
33 33 </button>
34 34  
35 35 <div class="collapse navbar-collapse" id="navbarText">
36   - <ul class="navbar-nav mr-auto">
37   - <li class="nav-item active">
38   - <a class="nav-link" href="#">Cursos<span class="sr-only">(actual)</span></a>
39   - </li>
40   - </ul>
  36 + <div class="navbar-nav mr-auto">
  37 + <a class="nav-item nav-link active" href="#">Cursos <span class="sr-only">(actual)</span></a>
  38 + <a class="nav-item nav-link disabled" href="#">Tópicos</a>
  39 + <a class="nav-item nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Classificação</a>
  40 + </div>
41 41  
42 42 <ul class="navbar-nav">
43 43 <li class="nav-item dropdown">
44 44 <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
45   - <i class="fas fa-user" aria-hidden="true"></i>
  45 + <i class="fas fa-user-graduate" aria-hidden="true"></i>
46 46 <span id="name">{{ escape(name) }}</span>
47 47 <span class="caret"></span>
48 48 </a>
... ... @@ -62,7 +62,7 @@
62 62  
63 63 {% for k,v in courses.items() %}
64 64  
65   - <a href="/course/{{k}}" class="card text-dark mb-3">
  65 + <a href="/course/{{k}}" class="card text-dark mb-3" style="width: 18rem;">
66 66 <div class="card-body">
67 67 <h6 class="card-title">{{ v['title'] }}</h6>
68 68 </div>
... ...
aprendizations/templates/maintopics-table.html
... ... @@ -33,22 +33,16 @@
33 33 </button>
34 34  
35 35 <div class="collapse navbar-collapse" id="navbarText">
36   - <ul class="navbar-nav mr-auto">
37   - <li class="nav-item">
38   - <a class="nav-link" href="/courses">Cursos</a>
39   - </li>
40   - <li class="nav-item active">
41   - <a class="nav-link" href="#">Tópicos<span class="sr-only">(actual)</span></a>
42   - </li>
43   - <li class="nav-item">
44   - <a class="nav-link" href="/rankings">Classificação</a>
45   - </li>
46   - </ul>
  36 + <div class="navbar-nav mr-auto">
  37 + <a class="nav-item nav-link" href="/courses">Cursos</a>
  38 + <a class="nav-item nav-link active" href="#">Tópicos <span class="sr-only">(actual)</span></a>
  39 + <a class="nav-item nav-link" href="/rankings?course={{course_id}}">Classificação</a>
  40 + </div>
47 41  
48 42 <ul class="navbar-nav">
49 43 <li class="nav-item dropdown">
50 44 <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
51   - <i class="fas fa-user" aria-hidden="true"></i>
  45 + <i class="fas fa-user-graduate" aria-hidden="true"></i>
52 46 <span id="name">{{ escape(name) }}</span>
53 47 <span class="caret"></span>
54 48 </a>
... ... @@ -66,7 +60,7 @@
66 60  
67 61 <div id="notifications"></div>
68 62  
69   - <h4>{{ title }}</h4>
  63 + <h4>{{ course_title }}</h4>
70 64  
71 65 <table class="table table-hover">
72 66 <thead>
... ...
aprendizations/templates/question.html
1 1 {% autoescape %}
2 2  
3   -<h2 class="page-header">{{ question['title'] }}</h4>
  3 +<h2 class="page-header">{{ md(question['title']) }}</h4>
4 4  
5 5 <div id="text">
6 6 {{ md(question['text']) }}
... ...
aprendizations/templates/rankings.html
... ... @@ -33,19 +33,16 @@
33 33 </button>
34 34  
35 35 <div class="collapse navbar-collapse" id="navbarText">
36   - <ul class="navbar-nav mr-auto">
37   - <li class="nav-item">
38   - <a class="nav-link" href="/">Tópicos</a>
39   - </li>
40   - <li class="nav-item active">
41   - <a class="nav-link" href="/rankings">Classificação<span class="sr-only">(current)</span></a>
42   - </li>
43   - </ul>
  36 + <div class="navbar-nav mr-auto">
  37 + <a class="nav-item nav-link" href="/courses">Cursos <span class="sr-only">(actual)</span></a>
  38 + <a class="nav-item nav-link" href="/course/{{course_id}}">Tópicos</a>
  39 + <a class="nav-item nav-link active" href="#">Classificação</a>
  40 + </div>
44 41  
45 42 <ul class="navbar-nav">
46 43 <li class="nav-item dropdown">
47 44 <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
48   - <i class="fas fa-user" aria-hidden="true"></i>
  45 + <i class="fas fa-user-graduate" aria-hidden="true"></i>
49 46 <span id="name">{{ escape(name) }}</span>
50 47 <span class="caret"></span>
51 48 </a>
... ... @@ -60,7 +57,7 @@
60 57 </nav>
61 58 <!-- ===================================================================== -->
62 59 <div class="container">
63   -<h4>Classificação geral</h4>
  60 +<h4>{{course_title}}</h4>
64 61 <table class="table table-hover">
65 62 <col width="100">
66 63 <thead>
... ... @@ -87,8 +84,8 @@
87 84 <td> <!-- student name -->
88 85 {{ ' '.join(r[1].split()[n] for n in (0,-1)) }}
89 86 &nbsp;
90   - {{ '<i class="fas fa-brain fa-2x text-success" title="Mais de 75% de respostas correctas"></i>' if r[3] > 0.75 else '' }}
91   - {{ '<i class="fas fa-frown text-secondary" title="Menos de 50% de respostas correctas" ></i>' if 0.0 < r[3] < 0.5 else '' }}
  87 + {{ '<i class="far fa-thumbs-up text-success" title="Mais de 75% de respostas correctas"></i>' if r[3] > 0.75 else '' }}
  88 + {{ '<i class="fas fa-bug" title="Menos de 50% de respostas correctas" ></i>' if 0.0 < r[3] < 0.5 else '' }}
92 89 </td>
93 90 <td> <!-- progress -->
94 91 <div class="progress">
... ...
aprendizations/templates/topic.html
... ... @@ -49,16 +49,16 @@
49 49 </button>
50 50  
51 51 <div class="collapse navbar-collapse" id="navbarText">
52   - <ul class="navbar-nav mr-auto">
53   - <li class="nav-item">
54   - <a class="nav-link" href="/">Tópicos</a>
55   - </li>
56   - </ul>
  52 + <div class="navbar-nav mr-auto">
  53 + <a class="nav-item nav-link" href="/courses">Cursos</a>
  54 + <a class="nav-item nav-link active" href="/course/{{course_id}}">Tópicos <span class="sr-only">(actual)</span></a>
  55 + <a class="nav-item nav-link" href="/rankings?course={{course_id}}">Classificação</a>
  56 + </div>
57 57  
58 58 <ul class="navbar-nav">
59 59 <li class="nav-item dropdown">
60 60 <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
61   - <i class="fas fa-user" aria-hidden="true"></i>
  61 + <i class="fas fa-user-graduate" aria-hidden="true"></i>
62 62 <span id="name">{{ escape(name) }}</span>
63 63 <span class="caret"></span>
64 64 </a>
... ...
package-lock.json
... ... @@ -131,9 +131,9 @@
131 131 }
132 132 },
133 133 "@fortawesome/fontawesome-free": {
134   - "version": "5.10.2",
135   - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.10.2.tgz",
136   - "integrity": "sha512-9pw+Nsnunl9unstGEHQ+u41wBEQue6XPBsILXtJF/4fNN1L3avJcMF/gGF86rIjeTAgfLjTY9ndm68/X4f4idQ=="
  134 + "version": "5.11.2",
  135 + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.11.2.tgz",
  136 + "integrity": "sha512-XiUPoS79r1G7PcpnNtq85TJ7inJWe0v+b5oZJZKb0pGHNIV6+UiNeQWiFGmuQ0aj7GEhnD/v9iqxIsjuRKtEnQ=="
137 137 },
138 138 "ansi-styles": {
139 139 "version": "3.2.1",
... ... @@ -154,9 +154,9 @@
154 154 }
155 155 },
156 156 "codemirror": {
157   - "version": "5.48.4",
158   - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.48.4.tgz",
159   - "integrity": "sha512-pUhZXDQ6qXSpWdwlgAwHEkd4imA0kf83hINmUEzJpmG80T/XLtDDEzZo8f6PQLuRCcUQhmzqqIo3ZPTRaWByRA=="
  157 + "version": "5.49.0",
  158 + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.49.0.tgz",
  159 + "integrity": "sha512-Hyzr0HToBdZpLBN9dYFO/KlJAsKH37/cXVHPAqa+imml0R92tb9AkmsvjnXL+SluEvjjdfkDgRjc65NG5jnMYA=="
160 160 },
161 161 "color-convert": {
162 162 "version": "1.9.3",
... ...
package.json
... ... @@ -2,8 +2,8 @@
2 2 "description": "Javascript libraries required to run the server",
3 3 "email": "mjsb@uevora.pt",
4 4 "dependencies": {
5   - "@fortawesome/fontawesome-free": "^5",
6   - "codemirror": "^5.48",
  5 + "@fortawesome/fontawesome-free": "^5.11.2",
  6 + "codemirror": "^5.49.0",
7 7 "mathjax": "^3",
8 8 "mdbootstrap": "^4.8.10"
9 9 },
... ...