diff --git a/mindmap/apps.py b/mindmap/apps.py index 07a6692..0c0ec00 100644 --- a/mindmap/apps.py +++ b/mindmap/apps.py @@ -23,5 +23,16 @@ class MindMapConfig(AppConfig): "test": {"relative_path": "settings.test"}, "production": {"relative_path": "settings.production"}, }, + }, + "signals_config": { + "lms.djangoapp": { + "relative_path": "receivers", + "receivers": [ + { + "receiver_func_name": "update_student_submission_status", + "signal_path": "submissions.models.score_reset", + }, + ] + }, } } diff --git a/mindmap/locale/en/LC_MESSAGES/text.po b/mindmap/locale/en/LC_MESSAGES/text.po index 1275936..fa1eb92 100644 --- a/mindmap/locale/en/LC_MESSAGES/text.po +++ b/mindmap/locale/en/LC_MESSAGES/text.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-18 11:39-0500\n" +"POT-Creation-Date: 2023-09-20 09:07-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Bryann Valderrama \n" "Language-Team: LANGUAGE \n" @@ -22,65 +22,77 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: mindmap.py:41 public/html/mindmap_edit.html:7 +#: mindmap.py:34 +msgid "Not attempted" +msgstr "" + +#: mindmap.py:35 +msgid "Submitted" +msgstr "" + +#: mindmap.py:36 +msgid "Completed" +msgstr "" + +#: mindmap.py:50 public/html/mindmap_edit.html:7 msgid "Display name" msgstr "" -#: mindmap.py:48 +#: mindmap.py:57 msgid "" "Whether the mind map is static or not. If it is static, the instructor can " "create a mind map and it will be the same for all students. If it is not " "static, the students can create their own mind maps." msgstr "" -#: mindmap.py:52 public/html/mindmap_edit.html:30 +#: mindmap.py:61 public/html/mindmap_edit.html:30 msgid "Is a static mindmap?" msgstr "" -#: mindmap.py:59 +#: mindmap.py:68 msgid "" "The mind map that will be shown to students if the\"Is a static mindmap?\" " "field is set to \"True\"" msgstr "" -#: mindmap.py:62 +#: mindmap.py:71 msgid "Mindmap body" msgstr "" -#: mindmap.py:82 +#: mindmap.py:91 msgid "" "The body of the mind map. It is a dictionary with the following structure: " "{'root': {'text': 'Root', 'children': [{'text': 'Child 1', 'children': []}]}}" msgstr "" -#: mindmap.py:85 +#: mindmap.py:94 msgid "Mindmap student body" msgstr "" -#: mindmap.py:91 +#: mindmap.py:100 msgid "Problem Weight" msgstr "" -#: mindmap.py:93 +#: mindmap.py:102 msgid "" "Defines the number of points each problem is worth. If the value is not set, " "the problem is worth the sum of the option point values." msgstr "" -#: mindmap.py:102 +#: mindmap.py:111 msgid "Maximum score" msgstr "" -#: mindmap.py:103 +#: mindmap.py:112 msgid "Maximum grade score given to assignment by instructors." msgstr "" -#: mindmap.py:109 -msgid "Submitted" +#: mindmap.py:118 +msgid "Submission status" msgstr "" -#: mindmap.py:110 -msgid "Whether the student has submitted their submission." +#: mindmap.py:119 +msgid "The submission status of the assignment." msgstr "" #: public/html/mindmap.html:8 @@ -132,15 +144,15 @@ msgid "Save assignment" msgstr "" #: public/html/mindmap.html:58 -#: public/js/src/mindmap.js:159 +#: public/js/src/mindmap.js:162 msgid "Submit" msgstr "" -#: public/html/mindmap.html:62 -msgid "Your score is:" +#: public/html/mindmap.html:61 +msgid "points" msgstr "" -#: public/html/mindmap.html:66 +#: public/html/mindmap.html:64 msgid "Grade submissions" msgstr "" @@ -180,66 +192,70 @@ msgstr "" msgid "Uploaded" msgstr "" -#: public/js/src/mindmap.js:85 public/js/src/mindmap.js:165 +#: public/js/src/mindmap.js:85 +msgid "Submission Status" +msgstr "" + +#: public/js/src/mindmap.js:86 public/js/src/mindmap.js:166 msgid "Grade" msgstr "" -#: public/js/src/mindmap.js:86 +#: public/js/src/mindmap.js:87 msgid "Actions" msgstr "" -#: public/js/src/mindmap.js:108 +#: public/js/src/mindmap.js:109 msgid "Mindmap submissions" msgstr "" -#: public/js/src/mindmap.js:109 +#: public/js/src/mindmap.js:110 msgid "Review" msgstr "" -#: public/js/src/mindmap.js:110 +#: public/js/src/mindmap.js:111 msgid "Search" msgstr "" -#: public/js/src/mindmap.js:111 +#: public/js/src/mindmap.js:112 msgid "Showing _START_ to _END_ of _TOTAL_ entries" msgstr "" -#: public/js/src/mindmap.js:112 +#: public/js/src/mindmap.js:113 msgid "No data available in table" msgstr "" -#: public/js/src/mindmap.js:113 +#: public/js/src/mindmap.js:114 msgid "Showing 0 to 0 of 0 entries" msgstr "" -#: public/js/src/mindmap.js:114 +#: public/js/src/mindmap.js:115 msgid "No matching records found" msgstr "" -#: public/js/src/mindmap.js:115 +#: public/js/src/mindmap.js:116 msgid "(filtered from _MAX_ total entries)" msgstr "" -#: public/js/src/mindmap.js:162 +#: public/js/src/mindmap.js:163 msgid "Remove grade" msgstr "" -#: public/js/src/mindmap.js:163 +#: public/js/src/mindmap.js:164 msgid "Loading..." msgstr "" -#: public/js/src/mindmap.js:164 +#: public/js/src/mindmap.js:165 msgid "Back" msgstr "" -#: public/js/src/mindmap.js:186 +#: public/js/src/mindmap.js:187 msgid "Reviewing Mindmap for student: " msgstr "" -#: public/js/src/mindmap.js:230 +#: public/js/src/mindmap.js:231 msgid "Invalid grade must be a number" msgstr "" -#: public/js/src/mindmap.js:231 +#: public/js/src/mindmap.js:232 msgid "Please enter a lower grade, maximum grade allowed is:" msgstr "" diff --git a/mindmap/locale/es_419/LC_MESSAGES/text.mo b/mindmap/locale/es_419/LC_MESSAGES/text.mo index f139e8a..8696935 100644 Binary files a/mindmap/locale/es_419/LC_MESSAGES/text.mo and b/mindmap/locale/es_419/LC_MESSAGES/text.mo differ diff --git a/mindmap/locale/es_419/LC_MESSAGES/text.po b/mindmap/locale/es_419/LC_MESSAGES/text.po index ce71bf0..7db1e47 100644 --- a/mindmap/locale/es_419/LC_MESSAGES/text.po +++ b/mindmap/locale/es_419/LC_MESSAGES/text.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-18 11:39-0500\n" +"POT-Creation-Date: 2023-09-20 09:07-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Bryann Valderrama \n" "Language-Team: LANGUAGE \n" @@ -22,11 +22,23 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: mindmap.py:41 public/html/mindmap_edit.html:7 +#: mindmap.py:34 +msgid "Not attempted" +msgstr "No intentado" + +#: mindmap.py:35 +msgid "Submitted" +msgstr "Enviado" + +#: mindmap.py:36 +msgid "Completed" +msgstr "Completado" + +#: mindmap.py:50 public/html/mindmap_edit.html:7 msgid "Display name" msgstr "Nombre a mostrar" -#: mindmap.py:48 +#: mindmap.py:57 msgid "" "Whether the mind map is static or not. If it is static, the instructor can " "create a mind map and it will be the same for all students. If it is not " @@ -36,11 +48,11 @@ msgstr "" "crear un mapa mental y será el mismo para todos los estudiantes. Si no es " "estático, los estudiantes pueden crear sus propios mapas mentales." -#: mindmap.py:52 public/html/mindmap_edit.html:30 +#: mindmap.py:61 public/html/mindmap_edit.html:30 msgid "Is a static mindmap?" msgstr "¿Es un mapa mental estático?" -#: mindmap.py:59 +#: mindmap.py:68 msgid "" "The mind map that will be shown to students if the\"Is a static mindmap?\" " "field is set to \"True\"" @@ -48,11 +60,11 @@ msgstr "" "El mapa mental que se mostrará a los estudiantes si el campo \"¿Es un mapa " "mental estático?\" está establecido en \"Verdadero\"" -#: mindmap.py:62 +#: mindmap.py:71 msgid "Mindmap body" msgstr "Contenido del mapa mental" -#: mindmap.py:82 +#: mindmap.py:91 msgid "" "The body of the mind map. It is a dictionary with the following structure: " "{'root': {'text': 'Root', 'children': [{'text': 'Child 1', 'children': []}]}}" @@ -60,15 +72,15 @@ msgstr "" "El contenido del mapa mental. Es un diccionario con la siguiente estructura: " "{'root': {'text': 'Root', 'children': [{'text': 'Child 1', 'children': []}]}}" -#: mindmap.py:85 +#: mindmap.py:94 msgid "Mindmap student body" msgstr "Contenido del mapa mental del estudiante" -#: mindmap.py:91 +#: mindmap.py:100 msgid "Problem Weight" msgstr "Peso del problema" -#: mindmap.py:93 +#: mindmap.py:102 msgid "" "Defines the number of points each problem is worth. If the value is not set, " "the problem is worth the sum of the option point values." @@ -77,21 +89,21 @@ msgstr "" "establecido, el problema vale la suma de los valores de puntos de las " "opciones." -#: mindmap.py:102 +#: mindmap.py:111 msgid "Maximum score" msgstr "Puntaje máximo" -#: mindmap.py:103 +#: mindmap.py:112 msgid "Maximum grade score given to assignment by instructors." msgstr "Puntaje máximo de calificación otorgado a la tarea por los instructores." -#: mindmap.py:109 -msgid "Submitted" -msgstr "Enviado" +#: mindmap.py:118 +msgid "Submission status" +msgstr "Estado del envío" -#: mindmap.py:110 -msgid "Whether the student has submitted their submission." -msgstr "Si el estudiante ha realizado su envío." +#: mindmap.py:119 +msgid "The submission status of the assignment." +msgstr "El estado del envío de la tarea." #: public/html/mindmap.html:8 msgid "Instructions for use" @@ -142,15 +154,15 @@ msgid "Save assignment" msgstr "Guardar asignación" #: public/html/mindmap.html:58 -#: public/js/src/mindmap.js:159 +#: public/js/src/mindmap.js:162 msgid "Submit" msgstr "Enviar" -#: public/html/mindmap.html:62 -msgid "Your score is:" -msgstr "Tu puntaje es:" +#: public/html/mindmap.html:61 +msgid "points" +msgstr "puntos" -#: public/html/mindmap.html:66 +#: public/html/mindmap.html:64 msgid "Grade submissions" msgstr "Calificar envíos" @@ -190,66 +202,70 @@ msgstr "Nombre de usuario" msgid "Uploaded" msgstr "Subido" -#: public/js/src/mindmap.js:85 public/js/src/mindmap.js:165 +#: public/js/src/mindmap.js:85 +msgid "Submission Status" +msgstr "Estado del Envío" + +#: public/js/src/mindmap.js:86 public/js/src/mindmap.js:166 msgid "Grade" msgstr "Calificación" -#: public/js/src/mindmap.js:86 +#: public/js/src/mindmap.js:87 msgid "Actions" msgstr "Acciones" -#: public/js/src/mindmap.js:108 +#: public/js/src/mindmap.js:109 msgid "Mindmap submissions" msgstr "Envíos de mapas mentales" -#: public/js/src/mindmap.js:109 +#: public/js/src/mindmap.js:110 msgid "Review" msgstr "Revisar" -#: public/js/src/mindmap.js:110 +#: public/js/src/mindmap.js:111 msgid "Search" msgstr "Buscar" -#: public/js/src/mindmap.js:111 +#: public/js/src/mindmap.js:112 msgid "Showing _START_ to _END_ of _TOTAL_ entries" msgstr "Mostrando registros del _START_ al _END_ de un total de _TOTAL_ registros" -#: public/js/src/mindmap.js:112 +#: public/js/src/mindmap.js:113 msgid "No data available in table" msgstr "Ningún dato disponible en esta tabla" -#: public/js/src/mindmap.js:113 +#: public/js/src/mindmap.js:114 msgid "Showing 0 to 0 of 0 entries" msgstr "Mostrando registros del 0 al 0 de un total de 0 registros" -#: public/js/src/mindmap.js:114 +#: public/js/src/mindmap.js:115 msgid "No matching records found" msgstr "No se encontraron resultados" -#: public/js/src/mindmap.js:115 +#: public/js/src/mindmap.js:116 msgid "(filtered from _MAX_ total entries)" msgstr "(filtrado de un total de _MAX_ registros)" -#: public/js/src/mindmap.js:162 +#: public/js/src/mindmap.js:163 msgid "Remove grade" msgstr "Eliminar calificación" -#: public/js/src/mindmap.js:163 +#: public/js/src/mindmap.js:164 msgid "Loading..." msgstr "Cargando..." -#: public/js/src/mindmap.js:164 +#: public/js/src/mindmap.js:165 msgid "Back" msgstr "Volver" -#: public/js/src/mindmap.js:186 +#: public/js/src/mindmap.js:187 msgid "Reviewing Mindmap for student: " msgstr "Revisando Mapa Mental para el estudiante: " -#: public/js/src/mindmap.js:230 +#: public/js/src/mindmap.js:231 msgid "Invalid grade must be a number" msgstr "Calificación inválida, debe ser un número" -#: public/js/src/mindmap.js:231 +#: public/js/src/mindmap.js:232 msgid "Please enter a lower grade, maximum grade allowed is:" msgstr "Por favor ingresa una calificación menor, la calificación máxima permitida es:" diff --git a/mindmap/locale/es_ES/LC_MESSAGES/text.mo b/mindmap/locale/es_ES/LC_MESSAGES/text.mo index f139e8a..8696935 100644 Binary files a/mindmap/locale/es_ES/LC_MESSAGES/text.mo and b/mindmap/locale/es_ES/LC_MESSAGES/text.mo differ diff --git a/mindmap/locale/es_ES/LC_MESSAGES/text.po b/mindmap/locale/es_ES/LC_MESSAGES/text.po index ce71bf0..7db1e47 100644 --- a/mindmap/locale/es_ES/LC_MESSAGES/text.po +++ b/mindmap/locale/es_ES/LC_MESSAGES/text.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-18 11:39-0500\n" +"POT-Creation-Date: 2023-09-20 09:07-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Bryann Valderrama \n" "Language-Team: LANGUAGE \n" @@ -22,11 +22,23 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: mindmap.py:41 public/html/mindmap_edit.html:7 +#: mindmap.py:34 +msgid "Not attempted" +msgstr "No intentado" + +#: mindmap.py:35 +msgid "Submitted" +msgstr "Enviado" + +#: mindmap.py:36 +msgid "Completed" +msgstr "Completado" + +#: mindmap.py:50 public/html/mindmap_edit.html:7 msgid "Display name" msgstr "Nombre a mostrar" -#: mindmap.py:48 +#: mindmap.py:57 msgid "" "Whether the mind map is static or not. If it is static, the instructor can " "create a mind map and it will be the same for all students. If it is not " @@ -36,11 +48,11 @@ msgstr "" "crear un mapa mental y será el mismo para todos los estudiantes. Si no es " "estático, los estudiantes pueden crear sus propios mapas mentales." -#: mindmap.py:52 public/html/mindmap_edit.html:30 +#: mindmap.py:61 public/html/mindmap_edit.html:30 msgid "Is a static mindmap?" msgstr "¿Es un mapa mental estático?" -#: mindmap.py:59 +#: mindmap.py:68 msgid "" "The mind map that will be shown to students if the\"Is a static mindmap?\" " "field is set to \"True\"" @@ -48,11 +60,11 @@ msgstr "" "El mapa mental que se mostrará a los estudiantes si el campo \"¿Es un mapa " "mental estático?\" está establecido en \"Verdadero\"" -#: mindmap.py:62 +#: mindmap.py:71 msgid "Mindmap body" msgstr "Contenido del mapa mental" -#: mindmap.py:82 +#: mindmap.py:91 msgid "" "The body of the mind map. It is a dictionary with the following structure: " "{'root': {'text': 'Root', 'children': [{'text': 'Child 1', 'children': []}]}}" @@ -60,15 +72,15 @@ msgstr "" "El contenido del mapa mental. Es un diccionario con la siguiente estructura: " "{'root': {'text': 'Root', 'children': [{'text': 'Child 1', 'children': []}]}}" -#: mindmap.py:85 +#: mindmap.py:94 msgid "Mindmap student body" msgstr "Contenido del mapa mental del estudiante" -#: mindmap.py:91 +#: mindmap.py:100 msgid "Problem Weight" msgstr "Peso del problema" -#: mindmap.py:93 +#: mindmap.py:102 msgid "" "Defines the number of points each problem is worth. If the value is not set, " "the problem is worth the sum of the option point values." @@ -77,21 +89,21 @@ msgstr "" "establecido, el problema vale la suma de los valores de puntos de las " "opciones." -#: mindmap.py:102 +#: mindmap.py:111 msgid "Maximum score" msgstr "Puntaje máximo" -#: mindmap.py:103 +#: mindmap.py:112 msgid "Maximum grade score given to assignment by instructors." msgstr "Puntaje máximo de calificación otorgado a la tarea por los instructores." -#: mindmap.py:109 -msgid "Submitted" -msgstr "Enviado" +#: mindmap.py:118 +msgid "Submission status" +msgstr "Estado del envío" -#: mindmap.py:110 -msgid "Whether the student has submitted their submission." -msgstr "Si el estudiante ha realizado su envío." +#: mindmap.py:119 +msgid "The submission status of the assignment." +msgstr "El estado del envío de la tarea." #: public/html/mindmap.html:8 msgid "Instructions for use" @@ -142,15 +154,15 @@ msgid "Save assignment" msgstr "Guardar asignación" #: public/html/mindmap.html:58 -#: public/js/src/mindmap.js:159 +#: public/js/src/mindmap.js:162 msgid "Submit" msgstr "Enviar" -#: public/html/mindmap.html:62 -msgid "Your score is:" -msgstr "Tu puntaje es:" +#: public/html/mindmap.html:61 +msgid "points" +msgstr "puntos" -#: public/html/mindmap.html:66 +#: public/html/mindmap.html:64 msgid "Grade submissions" msgstr "Calificar envíos" @@ -190,66 +202,70 @@ msgstr "Nombre de usuario" msgid "Uploaded" msgstr "Subido" -#: public/js/src/mindmap.js:85 public/js/src/mindmap.js:165 +#: public/js/src/mindmap.js:85 +msgid "Submission Status" +msgstr "Estado del Envío" + +#: public/js/src/mindmap.js:86 public/js/src/mindmap.js:166 msgid "Grade" msgstr "Calificación" -#: public/js/src/mindmap.js:86 +#: public/js/src/mindmap.js:87 msgid "Actions" msgstr "Acciones" -#: public/js/src/mindmap.js:108 +#: public/js/src/mindmap.js:109 msgid "Mindmap submissions" msgstr "Envíos de mapas mentales" -#: public/js/src/mindmap.js:109 +#: public/js/src/mindmap.js:110 msgid "Review" msgstr "Revisar" -#: public/js/src/mindmap.js:110 +#: public/js/src/mindmap.js:111 msgid "Search" msgstr "Buscar" -#: public/js/src/mindmap.js:111 +#: public/js/src/mindmap.js:112 msgid "Showing _START_ to _END_ of _TOTAL_ entries" msgstr "Mostrando registros del _START_ al _END_ de un total de _TOTAL_ registros" -#: public/js/src/mindmap.js:112 +#: public/js/src/mindmap.js:113 msgid "No data available in table" msgstr "Ningún dato disponible en esta tabla" -#: public/js/src/mindmap.js:113 +#: public/js/src/mindmap.js:114 msgid "Showing 0 to 0 of 0 entries" msgstr "Mostrando registros del 0 al 0 de un total de 0 registros" -#: public/js/src/mindmap.js:114 +#: public/js/src/mindmap.js:115 msgid "No matching records found" msgstr "No se encontraron resultados" -#: public/js/src/mindmap.js:115 +#: public/js/src/mindmap.js:116 msgid "(filtered from _MAX_ total entries)" msgstr "(filtrado de un total de _MAX_ registros)" -#: public/js/src/mindmap.js:162 +#: public/js/src/mindmap.js:163 msgid "Remove grade" msgstr "Eliminar calificación" -#: public/js/src/mindmap.js:163 +#: public/js/src/mindmap.js:164 msgid "Loading..." msgstr "Cargando..." -#: public/js/src/mindmap.js:164 +#: public/js/src/mindmap.js:165 msgid "Back" msgstr "Volver" -#: public/js/src/mindmap.js:186 +#: public/js/src/mindmap.js:187 msgid "Reviewing Mindmap for student: " msgstr "Revisando Mapa Mental para el estudiante: " -#: public/js/src/mindmap.js:230 +#: public/js/src/mindmap.js:231 msgid "Invalid grade must be a number" msgstr "Calificación inválida, debe ser un número" -#: public/js/src/mindmap.js:231 +#: public/js/src/mindmap.js:232 msgid "Please enter a lower grade, maximum grade allowed is:" msgstr "Por favor ingresa una calificación menor, la calificación máxima permitida es:" diff --git a/mindmap/mindmap.py b/mindmap/mindmap.py index 821b91f..ceb7608 100644 --- a/mindmap/mindmap.py +++ b/mindmap/mindmap.py @@ -4,6 +4,7 @@ import json import logging +from enum import Enum import pkg_resources from django.core.exceptions import PermissionDenied @@ -27,6 +28,13 @@ ATTR_KEY_USER_ROLE = 'edx-platform.user_role' +class SubmissionStatus(Enum): + """Submission status enum""" + NOT_ATTEMPTED = "Not attempted" + SUBMITTED = "Submitted" + COMPLETED = "Completed" + + @XBlock.wants("user") @XBlock.needs("i18n") class MindMapXBlock(XBlock): @@ -105,13 +113,6 @@ class MindMapXBlock(XBlock): scope=Scope.settings, ) - submitted = Boolean( - display_name=_("Submitted"), - help=_("Whether the student has submitted their submission."), - default=False, - scope=Scope.user_state, - ) - @property def block_id(self): """ @@ -194,6 +195,14 @@ def get_context(self, user): else: editable = in_student_view + submission = self.get_submission() + submission_status = SubmissionStatus.NOT_ATTEMPTED.value + if submission: + submission_status = submission.get("answer", {}).get( + "submission_status", + SubmissionStatus.NOT_ATTEMPTED.value, + ) + return { "display_name": self.display_name, "in_student_view": in_student_view, @@ -204,6 +213,7 @@ def get_context(self, user): "can_submit_assignment": self.submit_allowed(), "score": self.score, "max_score": self.max_score(), + "submission_status": submission_status, } def get_js_context(self, user, context): @@ -386,15 +396,15 @@ def submit_assignment(self, data, _suffix="") -> dict: require(self.submit_allowed()) + # Create a new submission self.mindmap_student_body = data.get("mind_map") answer = { "mindmap_student_body": json.dumps(self.mindmap_student_body), + "submission_status": SubmissionStatus.SUBMITTED.value, } student_item_dict = self.get_student_item_dict() create_submission(student_item_dict, answer) - self.submitted = True - return { "success": True, } @@ -424,22 +434,37 @@ def get_student_data() -> dict: students = SubmissionsStudent.objects.filter( course_id=self.course_id, item_id=self.block_id ) + for student in students: + submission = self.get_submission(student.student_id) + if not submission: continue + answer = submission.get("answer", {}) + + if ( + not submission or + answer.get("submission_status", SubmissionStatus.NOT_ATTEMPTED.value) == + SubmissionStatus.NOT_ATTEMPTED.value + ): + continue + + # student_module = self.get_or_create_student_module(user) + # state = json.loads(student_module.state) user = user_by_anonymous_id(student.student_id) score = self.get_score(student.student_id) + yield { "student_id": student.student_id, "submission_id": submission["uuid"], - "answer_body": submission["answer"], + "answer_body": answer, "username": user.username, "timestamp": submission["created_at"].strftime( DateTime.DATETIME_FORMAT ), "score": score, - "submitted": self.submitted, + "submission_status": answer.get("submission_status"), } return { @@ -461,23 +486,46 @@ def enter_grade(self, data, _suffix="") -> dict: dict: A dictionary containing the handler result. """ # Lazy import: import here to avoid app not ready errors - from submissions.api import set_score # pylint: disable=import-outside-toplevel + from submissions.api import set_score, create_submission # pylint: disable=import-outside-toplevel require(self.is_instructor()) score = int(data.get("grade")) - uuid = data.get("submission_id") - if not score or not uuid: + # uuid = data.get("submission_id") + + if not score: raise JsonHandlerError(400, "Missing required parameters") if score > self.max_score(): raise JsonHandlerError(400, "Score cannot be greater than max score") - set_score(uuid, score, self.max_score()) + latest_submission = self.update_student_submission_status( + data.get("student_id"), SubmissionStatus.COMPLETED.value, + ) + set_score(latest_submission["uuid"], score, self.max_score()) return { "success": True, } + def update_student_submission_status(self, student_id, submission_status): + """ + Update the submission status for a student. + + Args: + submission_id (str): The submission id. + student_id (str): The student id. + submission_status (str): The submission status. + """ + from submissions.api import create_submission + student_submission = self.get_submission(student_id) + mindmap_student_body = student_submission.get("answer", {}).get("mindmap_student_body", {}) + answer = { + "mindmap_student_body": mindmap_student_body, + "submission_status": submission_status, + } + student_item_dict = self.get_student_item_dict(student_id) + return create_submission(student_item_dict, answer) + @XBlock.json_handler def remove_grade(self, data, _suffix="") -> dict: """ @@ -491,15 +539,20 @@ def remove_grade(self, data, _suffix="") -> dict: dict: A dictionary containing the handler result. """ # Lazy import: import here to avoid app not ready errors - from submissions.api import reset_score # pylint: disable=import-outside-toplevel + from submissions.api import reset_score # pylint: disable=import-outside-toplevel require(self.is_instructor()) student_id = data.get("student_id") - if not student_id: + submission_id = data.get("submission_id") + if not student_id or not submission_id: raise JsonHandlerError(400, "Missing required parameters") - reset_score(student_id, self.block_course_id, self.block_id) + reset_score(submission_id, self.block_course_id, self.block_id) + + self.update_student_submission_status( + data.get("student_id"), SubmissionStatus.SUBMITTED.value, + ) return { "success": True, @@ -543,10 +596,20 @@ def submit_allowed(self) -> bool: Returns: bool: True if student is allowed to submit an assignment. """ + student_submission = self.get_submission() + if not student_submission: + return ( + not self.past_due() + and self.score is None + ) + submission_status = student_submission.get("answer", {}).get( + "submission_status", + SubmissionStatus.NOT_ATTEMPTED.value, + ) return ( not self.past_due() and self.score is None - and not self.submitted + and submission_status == SubmissionStatus.NOT_ATTEMPTED.value ) def get_score(self, student_id=None) -> int: @@ -669,13 +732,6 @@ def _get_statici18n_js_url(): return text_js.format(locale_code=code) return None - @staticmethod - def get_dummy(): - """ - Dummy method to generate initial i18n - """ - return translation.gettext_noop('Dummy') - def require(assertion): """ diff --git a/mindmap/public/html/mindmap.html b/mindmap/public/html/mindmap.html index f815090..2bca504 100644 --- a/mindmap/public/html/mindmap.html +++ b/mindmap/public/html/mindmap.html @@ -53,15 +53,17 @@
+{% if not score %} +

(0/{{ max_score }} {% trans "points" %}) {% trans submission_status %}

+{% else %} +

({{ score }}/{{ max_score }} {% trans "points" %}) {% trans submission_status %}

+{% endif %} + {% if editable and in_student_view and can_submit_assignment %} {% endif %} -{% if score %} -

{% trans "Your score is:" %} {{ score }}.

-{% endif %} - {% if is_instructor and in_student_view and not is_static %} diff --git a/mindmap/public/js/src/mindmap.js b/mindmap/public/js/src/mindmap.js index 06bd136..09980ee 100644 --- a/mindmap/public/js/src/mindmap.js +++ b/mindmap/public/js/src/mindmap.js @@ -82,6 +82,7 @@ function MindMapXBlock(runtime, element, context) { const dataTableHeaderColumns = [ gettext("Username"), gettext("Uploaded"), + gettext("Submission Status"), gettext("Grade"), gettext("Actions"), ]; @@ -125,7 +126,7 @@ function MindMapXBlock(runtime, element, context) { columns: [ { data: "username" }, { data: "timestamp" }, - // TODO: add this line { data: "submitted" }, + { data: "submission_status" }, { data: "score" }, { data: null, @@ -226,7 +227,7 @@ function MindMapXBlock(runtime, element, context) { e.preventDefault(); const typeAction = $(this).attr("data-type"); const grade = $("#grade_value").val(); - const { submission_id, student_id } = submissionData; + const { student_id, submission_id } = submissionData; const invalidGradeMessage = gettext("Invalid grade must be a number"); const maxGradeMessage = gettext("Please enter a lower grade, maximum grade allowed is:"); const gradeParsed = parseInt(grade, 10); @@ -252,7 +253,7 @@ function MindMapXBlock(runtime, element, context) { apiUrl = enterGradeURL; data = { grade: grade, - submission_id: submission_id, + student_id: student_id, }; } @@ -260,6 +261,7 @@ function MindMapXBlock(runtime, element, context) { apiUrl = removeGradeURL; data = { student_id: student_id, + submission_id: submission_id, }; } diff --git a/mindmap/public/js/translations/es_419/text.js b/mindmap/public/js/translations/es_419/text.js index 07abdb1..7eafde9 100644 --- a/mindmap/public/js/translations/es_419/text.js +++ b/mindmap/public/js/translations/es_419/text.js @@ -29,6 +29,7 @@ "Actions": "Acciones", "Back": "Volver", "Cancel": "Cancelar", + "Completed": "Completado", "Defines the number of points each problem is worth. If the value is not set, the problem is worth the sum of the option point values.": "Define el n\u00famero de puntos que vale cada problema. Si el valor no est\u00e1 establecido, el problema vale la suma de los valores de puntos de las opciones.", "Display name": "Nombre a mostrar", "False": "Falso", @@ -46,6 +47,7 @@ "Mindmap submissions": "Env\u00edos de mapas mentales", "No data available in table": "Ning\u00fan dato disponible en esta tabla", "No matching records found": "No se encontraron resultados", + "Not attempted": "No intentado", "Please enter a lower grade, maximum grade allowed is:": "Por favor ingresa una calificaci\u00f3n menor, la calificaci\u00f3n m\u00e1xima permitida es:", "Points": "Puntos", "Problem Weight": "Peso del problema", @@ -57,19 +59,21 @@ "Search": "Buscar", "Showing 0 to 0 of 0 entries": "Mostrando registros del 0 al 0 de un total de 0 registros", "Showing _START_ to _END_ of _TOTAL_ entries": "Mostrando registros del _START_ al _END_ de un total de _TOTAL_ registros", + "Submission Status": "Estado del Env\u00edo", + "Submission status": "Estado del env\u00edo", "Submit": "Enviar", "Submitted": "Enviado", "The body of the mind map. It is a dictionary with the following structure: {'root': {'text': 'Root', 'children': [{'text': 'Child 1', 'children': []}]}}": "El contenido del mapa mental. Es un diccionario con la siguiente estructura: {'root': {'text': 'Root', 'children': [{'text': 'Child 1', 'children': []}]}}", "The mind map that will be shown to students if the\"Is a static mindmap?\" field is set to \"True\"": "El mapa mental que se mostrar\u00e1 a los estudiantes si el campo \"\u00bfEs un mapa mental est\u00e1tico?\" est\u00e1 establecido en \"Verdadero\"", + "The submission status of the assignment.": "El estado del env\u00edo de la tarea.", "True": "Verdadero", "Uploaded": "Subido", "Username": "Nombre de usuario", "Weight": "Peso", "Whether the mind map is static or not. If it is static, the instructor can create a mind map and it will be the same for all students. If it is not static, the students can create their own mind maps.": "Si el mapa mental es est\u00e1tico o no. Si es est\u00e1tico, el instructor puede crear un mapa mental y ser\u00e1 el mismo para todos los estudiantes. Si no es est\u00e1tico, los estudiantes pueden crear sus propios mapas mentales.", - "Whether the student has submitted their submission.": "Si el estudiante ha realizado su env\u00edo.", "With the keyboard": "Con el teclado", "With the mouse": "Con el mouse", - "Your score is:": "Tu puntaje es:", + "points": "puntos", "\u2192 Click the circle to expand or collapse the child nodes.": "\u2192 Haga clic en el c\u00edrculo para expandir o contraer los nodos hijos.", "\u2192 Ctrl + Enter: Create a new child node for the selected node.": "\u2192 Ctrl + Enter: Crear un nuevo nodo hijo para el nodo seleccionado.", "\u2192 Delete/Supr: Delete the selected node.": "\u2192 Delete/Supr: Eliminar el nodo seleccionado.", diff --git a/mindmap/public/js/translations/es_ES/text.js b/mindmap/public/js/translations/es_ES/text.js index 07abdb1..7eafde9 100644 --- a/mindmap/public/js/translations/es_ES/text.js +++ b/mindmap/public/js/translations/es_ES/text.js @@ -29,6 +29,7 @@ "Actions": "Acciones", "Back": "Volver", "Cancel": "Cancelar", + "Completed": "Completado", "Defines the number of points each problem is worth. If the value is not set, the problem is worth the sum of the option point values.": "Define el n\u00famero de puntos que vale cada problema. Si el valor no est\u00e1 establecido, el problema vale la suma de los valores de puntos de las opciones.", "Display name": "Nombre a mostrar", "False": "Falso", @@ -46,6 +47,7 @@ "Mindmap submissions": "Env\u00edos de mapas mentales", "No data available in table": "Ning\u00fan dato disponible en esta tabla", "No matching records found": "No se encontraron resultados", + "Not attempted": "No intentado", "Please enter a lower grade, maximum grade allowed is:": "Por favor ingresa una calificaci\u00f3n menor, la calificaci\u00f3n m\u00e1xima permitida es:", "Points": "Puntos", "Problem Weight": "Peso del problema", @@ -57,19 +59,21 @@ "Search": "Buscar", "Showing 0 to 0 of 0 entries": "Mostrando registros del 0 al 0 de un total de 0 registros", "Showing _START_ to _END_ of _TOTAL_ entries": "Mostrando registros del _START_ al _END_ de un total de _TOTAL_ registros", + "Submission Status": "Estado del Env\u00edo", + "Submission status": "Estado del env\u00edo", "Submit": "Enviar", "Submitted": "Enviado", "The body of the mind map. It is a dictionary with the following structure: {'root': {'text': 'Root', 'children': [{'text': 'Child 1', 'children': []}]}}": "El contenido del mapa mental. Es un diccionario con la siguiente estructura: {'root': {'text': 'Root', 'children': [{'text': 'Child 1', 'children': []}]}}", "The mind map that will be shown to students if the\"Is a static mindmap?\" field is set to \"True\"": "El mapa mental que se mostrar\u00e1 a los estudiantes si el campo \"\u00bfEs un mapa mental est\u00e1tico?\" est\u00e1 establecido en \"Verdadero\"", + "The submission status of the assignment.": "El estado del env\u00edo de la tarea.", "True": "Verdadero", "Uploaded": "Subido", "Username": "Nombre de usuario", "Weight": "Peso", "Whether the mind map is static or not. If it is static, the instructor can create a mind map and it will be the same for all students. If it is not static, the students can create their own mind maps.": "Si el mapa mental es est\u00e1tico o no. Si es est\u00e1tico, el instructor puede crear un mapa mental y ser\u00e1 el mismo para todos los estudiantes. Si no es est\u00e1tico, los estudiantes pueden crear sus propios mapas mentales.", - "Whether the student has submitted their submission.": "Si el estudiante ha realizado su env\u00edo.", "With the keyboard": "Con el teclado", "With the mouse": "Con el mouse", - "Your score is:": "Tu puntaje es:", + "points": "puntos", "\u2192 Click the circle to expand or collapse the child nodes.": "\u2192 Haga clic en el c\u00edrculo para expandir o contraer los nodos hijos.", "\u2192 Ctrl + Enter: Create a new child node for the selected node.": "\u2192 Ctrl + Enter: Crear un nuevo nodo hijo para el nodo seleccionado.", "\u2192 Delete/Supr: Delete the selected node.": "\u2192 Delete/Supr: Eliminar el nodo seleccionado.", diff --git a/mindmap/receivers.py b/mindmap/receivers.py new file mode 100644 index 0000000..409b461 --- /dev/null +++ b/mindmap/receivers.py @@ -0,0 +1,23 @@ +from mindmap.mindmap import SubmissionStatus + + +def update_student_submission_status(*args, **kwargs): + """Update the submission status for a student after resetting their score.""" + from submissions.api import get_submissions # pylint: disable=import-outside-toplevel + from submissions.api import create_submission + + student_item_dict = { + "student_id": kwargs.get("anonymous_user_id"), + "item_id": kwargs.get("item_id"), + "item_type": "mindmap", + "course_id": kwargs.get("course_id"), + } + submissions = get_submissions(student_item_dict) + if not submissions: + return + + student_submission = submissions[0] + new_answer = student_submission.get("answer") + new_answer["submission_status"] = SubmissionStatus.NOT_ATTEMPTED.value + + create_submission(student_item_dict, new_answer) diff --git a/mindmap/tests/test_mindmap.py b/mindmap/tests/test_mindmap.py index 2da5d9d..2276769 100644 --- a/mindmap/tests/test_mindmap.py +++ b/mindmap/tests/test_mindmap.py @@ -43,6 +43,7 @@ def setUp(self) -> None: self.xblock.display_name = "Test MindMap" self.xblock.points = 100 self.xblock.weight = 1 + self.xblock.submission_status = "Not attempted" self.xblock.course_id = "test-course-id" @@ -75,6 +76,7 @@ def test_student_view_with_mind_map(self, initialize_js_mock: Mock): "can_submit_assignment": True, "score": 0, "max_score": self.xblock.max_score(), + "submission_status": self.xblock.submission_status, } expected_js_context = { "author": self.student.full_name, @@ -114,6 +116,7 @@ def test_student_view_empty_mind_map(self, initialize_js_mock: Mock): "can_submit_assignment": True, "score": 0, "max_score": self.xblock.max_score(), + "submission_status": self.xblock.submission_status, } expected_js_context = { "author": self.student.full_name, @@ -153,6 +156,7 @@ def test_static_mind_map_in_student_view(self): "can_submit_assignment": True, "score": 0, "max_score": self.xblock.max_score(), + "submission_status": self.xblock.submission_status, } self.xblock.student_view() @@ -184,6 +188,7 @@ def test_student_view_for_instructor(self): "score": 0, "max_score": self.xblock.max_score(), "is_instructor": True, + "submission_status": self.xblock.submission_status, } self.xblock.student_view() @@ -221,6 +226,7 @@ def test_studio_view(self): "weight": 1, "weight_field": self.xblock.fields["weight"], "max_score": self.xblock.max_score(), + "submission_status": self.xblock.submission_status, } self.xblock.studio_view() @@ -259,6 +265,7 @@ def test_student_not_allowed_submission(self, initialize_js_mock: Mock): "can_submit_assignment": False, "score": 0, "max_score": self.xblock.max_score(), + "submission_status": self.xblock.submission_status, } expected_js_context = { "author": self.student.full_name, @@ -382,8 +389,9 @@ def test_submit_assignment(self, create_submission_mock: Mock): expected_answer, ) + @patch("mindmap.mindmap.MindMapXBlock.get_student_module") @patch("submissions.api.set_score") - def test_enter_grade(self, set_score_mock: Mock): + def test_enter_grade(self, set_score_mock: Mock, get_student_module_mock: Mock): """ Check enter grade handler. @@ -397,6 +405,7 @@ def test_enter_grade(self, set_score_mock: Mock): } ).encode("utf-8") self.xblock.is_instructor = Mock(return_value=True) + get_student_module_mock.return_value = Mock(state='{"test-state": "mindmap"}') response = self.xblock.enter_grade(self.request) @@ -407,8 +416,9 @@ def test_enter_grade(self, set_score_mock: Mock): self.xblock.max_score(), ) + @patch("mindmap.mindmap.MindMapXBlock.get_student_module") @patch("submissions.api.reset_score") - def test_remove_grade(self, reset_score_mock: Mock): + def test_remove_grade(self, reset_score_mock: Mock, get_student_module_mock: Mock): """ Check remove grade handler. @@ -417,6 +427,7 @@ def test_remove_grade(self, reset_score_mock: Mock): """ self.request.body = json.dumps({"student_id": self.student_id}).encode("utf-8") self.xblock.is_instructor = Mock(return_value=True) + get_student_module_mock.return_value = Mock(state='{"test-state": "mindmap"}') response = self.xblock.remove_grade(self.request) @@ -427,9 +438,15 @@ def test_remove_grade(self, reset_score_mock: Mock): self.xblock.block_id, ) + @patch("mindmap.mindmap.MindMapXBlock.get_or_create_student_module") @patch("mindmap.mindmap.user_by_anonymous_id") @patch("submissions.models.StudentItem") - def test_get_instructor_grading_data(self, student_item_mock: Mock, user_by_anonymous_id_mock: Mock): + def test_get_instructor_grading_data( + self, + student_item_mock: Mock, + user_by_anonymous_id_mock: Mock, + get_or_create_student_module_mock: Mock, + ): """ Check get instructor grading data handler. @@ -444,6 +461,7 @@ def test_get_instructor_grading_data(self, student_item_mock: Mock, user_by_anon ), ] current_datetime = datetime.datetime.now() + module_id = 1 self.xblock.get_submission = Mock(return_value={ "uuid": "test-submission-id", "answer": { @@ -453,10 +471,11 @@ def test_get_instructor_grading_data(self, student_item_mock: Mock, user_by_anon }) self.xblock.is_instructor = Mock(return_value=True) user_by_anonymous_id_mock.return_value = Mock(username=self.student.student_id) - self.xblock.submitted = True + self.xblock.submission_status = "Submitted" expected_result = { "assignments": [ { + "module_id": module_id, "student_id": self.student.student_id, "submission_id": "test-submission-id", "answer_body": { @@ -465,13 +484,16 @@ def test_get_instructor_grading_data(self, student_item_mock: Mock, user_by_anon "username": self.student.student_id, "timestamp": current_datetime.strftime(DateTime.DATETIME_FORMAT), "score": 50, - "submitted": self.xblock.submitted, + "submission_status": self.xblock.submission_status, }, ], "display_name": self.xblock.display_name, "max_score": self.xblock.max_score(), } + get_or_create_student_module_mock.return_value = Mock( + state='{"submission_status": "Submitted"}', id=module_id, + ) response = self.xblock.get_instructor_grading_data(self.request)