Commit 8b4ac80ad8069fb0bb8d73b59baf6680b802547f
1 parent
d187aad4
Exists in
master
and in
1 other branch
- fixed menus
- mathjax3 seems to be working fine - fixed finish_topics redirect working... with bugs...
Showing
12 changed files
with
73 additions
and
81 deletions
Show diff stats
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
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 | |
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 | }, | ... | ... |