Norberto Montalvo García commited on
Commit
7facb3f
·
unverified ·
2 Parent(s): 37215c6 1e97d90

Merge pull request #13 from CascoArcilla/HU4

Browse files
tecnicas/controllers/models_controller/calificacion_controller.py CHANGED
@@ -48,14 +48,9 @@ class CalificacionController():
48
  if not repetition:
49
  return {"error": "sin datos calficados aun"}
50
 
51
- data_rating = {}
52
 
53
- for i in range(repetition):
54
- response_data = Calificacion.objects.filter(
55
- id_tecnica=technique, num_repeticion=i+1)
56
- data_rating[f"repeticion_{i+1}"] = response_data
57
-
58
- return data_rating
59
 
60
  @staticmethod
61
  def getRatings(
 
48
  if not repetition:
49
  return {"error": "sin datos calficados aun"}
50
 
51
+ ratings = list(Calificacion.objects.filter(id_tecnica=technique))
52
 
53
+ return ratings
 
 
 
 
 
54
 
55
  @staticmethod
56
  def getRatings(
tecnicas/controllers/models_controller/dato_controller.py CHANGED
@@ -1,6 +1,7 @@
1
- from ...models import Calificacion, Dato, Palabra, ValorDecimal, ValorBooleano
2
  from ...utils import controller_error, getId
3
  from django.core.exceptions import ValidationError
 
4
 
5
 
6
  class DatoController():
@@ -36,7 +37,7 @@ class DatoController():
36
 
37
  def setInstanceValue(self):
38
  technique = self.data.id_calificacion.id_tecnica
39
-
40
  if technique.tipo_tecnica == "cata":
41
  self.value_data = ValorBooleano(
42
  id_dato=self.data,
@@ -72,3 +73,25 @@ class DatoController():
72
  id_calificacion_id__in=ids_ratings))
73
 
74
  return recoreded_data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from ...models import Calificacion, Dato, Palabra, ValorDecimal, ValorBooleano, Tecnica
2
  from ...utils import controller_error, getId
3
  from django.core.exceptions import ValidationError
4
+ from django.db.models import F
5
 
6
 
7
  class DatoController():
 
37
 
38
  def setInstanceValue(self):
39
  technique = self.data.id_calificacion.id_tecnica
40
+
41
  if technique.tipo_tecnica == "cata":
42
  self.value_data = ValorBooleano(
43
  id_dato=self.data,
 
73
  id_calificacion_id__in=ids_ratings))
74
 
75
  return recoreded_data
76
+
77
+ @staticmethod
78
+ def getWordValuesForConvecional(technique: Tecnica, ratings: list[Calificacion]):
79
+ model = ValorBooleano if technique.tipo_tecnica == "cata" else ValorDecimal
80
+
81
+ ids_ratings = [rat.id for rat in ratings]
82
+
83
+ result = (
84
+ model.objects
85
+ .filter(id_dato__id_calificacion_id__in=ids_ratings)
86
+ .values(
87
+ nombre_palabra=F("id_dato__id_palabra__nombre_palabra"),
88
+ repeticion=F("id_dato__id_calificacion__num_repeticion"),
89
+ producto_code=F(
90
+ "id_dato__id_calificacion__id_producto__codigoProducto"),
91
+ usuarioCatador=F(
92
+ "id_dato__id_calificacion__id_catador__usuarioCatador"),
93
+ dato_valor=F("valor")
94
+ )
95
+ )
96
+
97
+ return list(result)
tecnicas/controllers/models_controller/particiapacion_controller.py CHANGED
@@ -1,4 +1,4 @@
1
- from ...models import Participacion, Tecnica
2
  from ...utils import controller_error
3
 
4
 
@@ -13,7 +13,7 @@ class ParticipacionController():
13
  return participation
14
  except Participacion.DoesNotExist:
15
  return controller_error("No se ha encontrado la participación")
16
-
17
  @staticmethod
18
  def finishSession(id_participation: int):
19
  try:
@@ -24,7 +24,7 @@ class ParticipacionController():
24
  return participation
25
  except Participacion.DoesNotExist:
26
  return controller_error("No se ha encontrado la participación")
27
-
28
  @staticmethod
29
  def outSession(id_participation: int):
30
  try:
@@ -34,9 +34,33 @@ class ParticipacionController():
34
  return participation
35
  except Participacion.DoesNotExist:
36
  return controller_error("No se ha encontrado la participación")
37
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  @staticmethod
39
- def getParticipationsInTechinique(technique: Tecnica| int):
40
  filters = {}
41
 
42
  if isinstance(technique, int):
@@ -44,5 +68,4 @@ class ParticipacionController():
44
  else:
45
  filters["tecnica"] = technique
46
 
47
- participations = list(Participacion.objects.filter(**filters))
48
- return participations
 
1
+ from ...models import Participacion, Tecnica, SesionSensorial
2
  from ...utils import controller_error
3
 
4
 
 
13
  return participation
14
  except Participacion.DoesNotExist:
15
  return controller_error("No se ha encontrado la participación")
16
+
17
  @staticmethod
18
  def finishSession(id_participation: int):
19
  try:
 
24
  return participation
25
  except Participacion.DoesNotExist:
26
  return controller_error("No se ha encontrado la participación")
27
+
28
  @staticmethod
29
  def outSession(id_participation: int):
30
  try:
 
34
  return participation
35
  except Participacion.DoesNotExist:
36
  return controller_error("No se ha encontrado la participación")
37
+
38
+ @staticmethod
39
+ def outAllInSession(session: SesionSensorial | str):
40
+ try:
41
+ if isinstance(session, str):
42
+ use_session = SesionSensorial.objects.get(
43
+ codigo_sesion=session)
44
+ else:
45
+ use_session = session
46
+
47
+ participations = Participacion.objects.filter(
48
+ tecnica=use_session.tecnica)
49
+
50
+ if not participations.exists():
51
+ message = "No se encontraron participaciones en la sesión"
52
+ return (False, message)
53
+
54
+ participations.update(finalizado=False)
55
+
56
+ message = "Participaciones actualizadas a finalizadas"
57
+ return (True, message)
58
+ except Exception as e:
59
+ print(f"Error al actualizar las participaciones: {str(e)}")
60
+ return (False, "Error al actualizar las participaciones")
61
+
62
  @staticmethod
63
+ def getParticipationsInTechinique(technique: Tecnica | int):
64
  filters = {}
65
 
66
  if isinstance(technique, int):
 
68
  else:
69
  filters["tecnica"] = technique
70
 
71
+ return list(Participacion.objects.filter(**filters))
 
tecnicas/controllers/models_controller/sesion_controller.py CHANGED
@@ -1,7 +1,8 @@
1
  from django.db import DatabaseError
2
  from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
3
- from ...models import Tecnica, Presentador, SesionSensorial
4
- from ...utils import controller_error
 
5
 
6
 
7
  class SesionController():
@@ -91,7 +92,7 @@ class SesionController():
91
  return session
92
  except SesionSensorial.DoesNotExist:
93
  return controller_error("La sesión ya no existe")
94
-
95
  @staticmethod
96
  def getSessionByCode(code: str):
97
  try:
@@ -111,3 +112,22 @@ class SesionController():
111
  return number_sessions/9
112
  except Presentador.DoesNotExist:
113
  return controller_error("presentador invalido")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from django.db import DatabaseError
2
  from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
3
+ from tecnicas.models import Tecnica, Presentador, SesionSensorial
4
+ from tecnicas.utils import controller_error
5
+ from ..models_controller.particiapacion_controller import ParticipacionController
6
 
7
 
8
  class SesionController():
 
92
  return session
93
  except SesionSensorial.DoesNotExist:
94
  return controller_error("La sesión ya no existe")
95
+
96
  @staticmethod
97
  def getSessionByCode(code: str):
98
  try:
 
112
  return number_sessions/9
113
  except Presentador.DoesNotExist:
114
  return controller_error("presentador invalido")
115
+
116
+ @staticmethod
117
+ def finishRepetion(session: SesionSensorial | str):
118
+ if isinstance(session, str):
119
+ use_session = SesionSensorial.objects.get(codigo_sesion=session)
120
+ else:
121
+ use_session = session
122
+
123
+ (is_update_participations,
124
+ message) = ParticipacionController.outAllInSession(use_session)
125
+
126
+ if not is_update_participations:
127
+ return controller_error(message)
128
+
129
+ use_session.activo = False
130
+
131
+ use_session.save()
132
+
133
+ return session
tecnicas/controllers/models_controller/tecnica_controller.py CHANGED
@@ -1,6 +1,6 @@
1
- from ...models import TipoTecnica, CategoriaTecnica, Tecnica, EstiloPalabra
2
  from django.db import DatabaseError
3
- from ...utils import controller_error
4
 
5
 
6
  class TecnicaController():
 
1
+ from tecnicas.models import TipoTecnica, CategoriaTecnica, Tecnica, EstiloPalabra
2
  from django.db import DatabaseError
3
+ from tecnicas.utils import controller_error
4
 
5
 
6
  class TecnicaController():
tecnicas/controllers/views_controller/detalles_sesion_controller.py CHANGED
@@ -1,24 +1,70 @@
1
- from ...models import SesionSensorial, Presentador, Tecnica
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  from .. import CalificacionController, PalabrasController
3
  from ...utils import controller_error
 
 
 
4
 
5
 
6
  class DetallesSesionController():
7
- @staticmethod
8
- def getContextForView(session_code: str):
9
- context = {}
 
 
10
 
11
- session = SesionSensorial.objects.get(codigo_sesion=session_code)
12
- context["sesion"] = session
13
 
14
- words = PalabrasController.getWordsInTechnique(session.tecnica)
15
- context["palabras"] = words
 
16
 
17
- rating = CalificacionController.getRatingsByTechnique(
18
- technique=session.tecnica)
19
- context["calificaciones"] = rating
20
 
21
- return context
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
  @staticmethod
24
  def startRepetition(session_code: str, username: str):
@@ -45,5 +91,5 @@ class DetallesSesionController():
45
 
46
  technique.save()
47
  session.save()
48
-
49
  return session
 
1
+ '''
2
+
3
+ Para Tecnicas Convencionales, CATA, RATA, Escala Hedonica
4
+ Encabezados de como deben de aparecer los datos por repeticion
5
+
6
+ | Repeticion: R
7
+ | Codigo Producto | Catador | P1 | P2 | P3 | Pn |
8
+
9
+ Encabezados de como deben de aparecer los datos juntos
10
+
11
+ | Repeticion | Codigo Producto | Catador | P1 | P2 | P3 | Pn |
12
+
13
+ '''
14
+
15
+ from ...models import SesionSensorial, Presentador, Tecnica, Palabra
16
  from .. import CalificacionController, PalabrasController
17
  from ...utils import controller_error
18
+ from collections import defaultdict
19
+ from tecnicas.controllers import DatoController
20
+ from tecnicas.utils import defaultdict_to_dict
21
 
22
 
23
  class DetallesSesionController():
24
+ def __init__(self, session_code: str):
25
+ self.session = SesionSensorial.objects.get(codigo_sesion=session_code)
26
+
27
+ def getContextForView(self):
28
+ self.context = {}
29
 
30
+ self.context["sesion"] = self.session
 
31
 
32
+ self.words = PalabrasController.getWordsInTechnique(
33
+ self.session.tecnica)
34
+ self.context["palabras"] = [word.nombre_palabra for word in self.words]
35
 
36
+ def getContextWithData(self):
37
+ ratings_for_repetition = []
 
38
 
39
+ ratings = CalificacionController.getRatingsByTechnique(
40
+ technique=self.session.tecnica)
41
+
42
+ if isinstance(ratings, dict) or not ratings:
43
+ self.context["calificaciones"] = ratings_for_repetition
44
+ self.context["existen_calificaciones"] = False
45
+ return self.context
46
+
47
+ data = DatoController.getWordValuesForConvecional(
48
+ ratings=ratings, technique=self.session.tecnica)
49
+
50
+ ratings_for_repetition = defaultdict(
51
+ lambda: defaultdict(lambda: defaultdict(list)))
52
+
53
+ for item in data:
54
+ user = item["usuarioCatador"]
55
+ rep = item["repeticion"]
56
+ prod = item["producto_code"]
57
+
58
+ ratings_for_repetition[rep][user][prod].append({
59
+ "nombre_palabra": item["nombre_palabra"],
60
+ "dato_valor": item["dato_valor"]
61
+ })
62
+
63
+ self.context["calificaciones"] = defaultdict_to_dict(
64
+ ratings_for_repetition)
65
+ self.context["existen_calificaciones"] = True
66
+
67
+ return self.context
68
 
69
  @staticmethod
70
  def startRepetition(session_code: str, username: str):
 
91
 
92
  technique.save()
93
  session.save()
94
+
95
  return session
tecnicas/controllers/views_controller/main_tester_form_controller.py CHANGED
@@ -1,4 +1,4 @@
1
- from ...models import Catador, SesionSensorial, Orden, Participacion, Producto, EsAtributo, Calificacion, EsVocabulario
2
  from ...utils import controller_error, shuffleArray
3
  from django.db import transaction
4
 
@@ -45,15 +45,12 @@ class MainTesterFormController():
45
  return controller_error("Catador sin orden")
46
 
47
  def isEndedSession(self, id_participation: int, repetition: int):
48
- if not self.order or not id_participation:
49
- return controller_error("Se requieren datos para comprobar la finalización")
50
-
51
  try:
52
  participation = Participacion.objects.get(id=id_participation)
53
 
54
  # ////////////////////////////////////////////////////////////// #
55
  #
56
- # Si numero_calificaciones_esperadas = productos * palabras
57
  # Es igual a numero_calificaciones_actuales en la repetcion R
58
  # Ha terminado la repeticion
59
  #
 
1
+ from tecnicas.models import Catador, SesionSensorial, Orden, Participacion, Producto, EsAtributo, Calificacion, EsVocabulario
2
  from ...utils import controller_error, shuffleArray
3
  from django.db import transaction
4
 
 
45
  return controller_error("Catador sin orden")
46
 
47
  def isEndedSession(self, id_participation: int, repetition: int):
 
 
 
48
  try:
49
  participation = Participacion.objects.get(id=id_participation)
50
 
51
  # ////////////////////////////////////////////////////////////// #
52
  #
53
+ # Si numero_calificaciones_esperadas = num_productos * num_palabras
54
  # Es igual a numero_calificaciones_actuales en la repetcion R
55
  # Ha terminado la repeticion
56
  #
tecnicas/controllers/views_controller/monitor_sesion_controller.py CHANGED
@@ -1,5 +1,5 @@
1
- from tecnicas.models import SesionSensorial
2
- from tecnicas.controllers import ParticipacionController
3
  from tecnicas.utils import controller_error
4
 
5
 
@@ -7,6 +7,10 @@ class MonitorSesionController():
7
  def __init__(self, session_code: str):
8
  self.code_session = session_code
9
 
 
 
 
 
10
  def monitorView(self):
11
  try:
12
  self.sensorial_session = SesionSensorial.objects.select_related(
@@ -30,3 +34,49 @@ class MonitorSesionController():
30
  }
31
 
32
  return context
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from tecnicas.models import SesionSensorial, EsAtributo, EsVocabulario, Producto, Calificacion
2
+ from tecnicas.controllers import ParticipacionController, SesionController
3
  from tecnicas.utils import controller_error
4
 
5
 
 
7
  def __init__(self, session_code: str):
8
  self.code_session = session_code
9
 
10
+ def defineSession(self):
11
+ self.session = SesionSensorial.objects.get(
12
+ codigo_sesion=self.code_session)
13
+
14
  def monitorView(self):
15
  try:
16
  self.sensorial_session = SesionSensorial.objects.select_related(
 
34
  }
35
 
36
  return context
37
+
38
+ def getExpectedRatings(self):
39
+ num_products = Producto.objects.filter(
40
+ id_tecnica=self.session.tecnica).count()
41
+
42
+ style_words = self.session.tecnica.id_estilo
43
+
44
+ num_words: int
45
+
46
+ if style_words.nombre_estilo == "atributos":
47
+ num_words = EsAtributo.objects.get(
48
+ id_tecnica=self.session.tecnica).palabras.count()
49
+ elif style_words.nombre_estilo == "vocabulario":
50
+ num_words = EsVocabulario.objects.get(
51
+ id_tecnica=self.session.tecnica).id_vocabulario.palabras.count()
52
+
53
+ return num_products * num_words
54
+
55
+ def checkAllParticipantsEnded(self):
56
+ self.defineSession()
57
+
58
+ technique = self.session.tecnica
59
+
60
+ expected_ratings_repetition = self.getExpectedRatings()
61
+
62
+ all_participations = ParticipacionController.getParticipationsInTechinique(
63
+ technique=technique)
64
+
65
+ if len(all_participations) < technique.limite_catadores:
66
+ return (False, "No se ha alcanzado el número máximo de Catadores")
67
+
68
+ for particiapation in all_participations:
69
+ num_ratings_now = Calificacion.objects.filter(
70
+ id_tecnica=technique, id_catador=particiapation.catador, num_repeticion=technique.repeticion).count()
71
+
72
+ if num_ratings_now < expected_ratings_repetition:
73
+ return (False, "No todos los catadores han finalizado su evaluación")
74
+
75
+ return (True, "Puedes finalizar la sesión")
76
+
77
+ def finishSession(self):
78
+ response = SesionController.finishRepetion(self.session)
79
+ if isinstance(response, dict):
80
+ return controller_error(response["error"])
81
+ self.defineSession()
82
+ return self.session
tecnicas/models/dato.py CHANGED
@@ -3,6 +3,12 @@ from django.db import models
3
  from .palabra import Palabra
4
  from .calificacion import Calificacion
5
 
 
6
  class Dato(models.Model):
7
- id_palabra = models.ForeignKey(Palabra, on_delete=models.CASCADE, related_name="dato_palabra")
8
- id_calificacion = models.ForeignKey(Calificacion, on_delete=models.CASCADE, related_name="dato_calificacion")
 
 
 
 
 
 
3
  from .palabra import Palabra
4
  from .calificacion import Calificacion
5
 
6
+
7
  class Dato(models.Model):
8
+ id_palabra = models.ForeignKey(
9
+ Palabra, on_delete=models.CASCADE, related_name="dato_palabra")
10
+ id_calificacion = models.ForeignKey(
11
+ Calificacion, on_delete=models.CASCADE, related_name="dato_calificacion")
12
+
13
+ def __str__(self):
14
+ return f"{self.id_palabra.nombre_palabra} - {self.id_calificacion.id_producto.codigoProducto} - {self.id_calificacion.id_catador.usuarioCatador}"
tecnicas/models/dato_valor.py CHANGED
@@ -2,16 +2,20 @@ from django.db import models
2
 
3
  from .dato import Dato
4
 
 
5
  class ValorDecimal(models.Model):
6
- id_dato = models.OneToOneField(Dato, on_delete=models.CASCADE, related_name="dato_decimal")
 
7
  valor = models.FloatField()
8
 
9
  def __str__(self):
10
- return f"{self.id} - {self.id_dato.id_palabra}: {self.valor}"
 
11
 
12
  class ValorBooleano(models.Model):
13
- id_dato = models.OneToOneField(Dato, on_delete=models.CASCADE, related_name="dato_boolean")
 
14
  valor = models.BooleanField()
15
 
16
  def __str__(self):
17
- return f"{self.id} - {self.id_dato.id_palabra}: {self.valor}"
 
2
 
3
  from .dato import Dato
4
 
5
+
6
  class ValorDecimal(models.Model):
7
+ id_dato = models.OneToOneField(
8
+ Dato, on_delete=models.CASCADE, related_name="dato_decimal")
9
  valor = models.FloatField()
10
 
11
  def __str__(self):
12
+ return f"{self.id} - {self.id_dato.id_palabra}: {self.valor} - {self.id_dato.id_calificacion.id_catador.usuarioCatador}"
13
+
14
 
15
  class ValorBooleano(models.Model):
16
+ id_dato = models.OneToOneField(
17
+ Dato, on_delete=models.CASCADE, related_name="dato_boolean")
18
  valor = models.BooleanField()
19
 
20
  def __str__(self):
21
+ return f"{self.id} - {self.id_dato.id_palabra}: {self.valor} - {self.id_dato.id_calificacion.id_catador.usuarioCatador}"
tecnicas/static/js/finish-session.js ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ function finishSession() {
2
+ const form = document.querySelector(".action-form");
3
+ form.querySelector("input").value = "finish_session";
4
+ form.submit();
5
+ }
tecnicas/templates/tecnicas/components/error-message.html ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ <article class="bg-surface-ligt border-b-2 border-ct-success p-4 text-black rounded cts-message shadow-lg">
2
+ <p class="font-sans text-xl text-center">
3
+ {{ message }}
4
+ </p>
5
+ </article>
tecnicas/templates/tecnicas/components/table-convencional.html ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <section>
2
+ <h2 class="text-lg font-bold mb-3">Repetición {{ repeticion }}</h2>
3
+
4
+ <div class="overflow-x-auto rounded-lg border border-surface-general">
5
+ <table class="min-w-max w-full text-sm text-center border-collapse">
6
+ <thead class="bg-surface-sweet text-black font-semibold">
7
+ <tr>
8
+ <th class="py-2 px-3 border border-surface-general">Usuario</th>
9
+ <th class="py-2 px-3 border border-surface-general">Producto</th>
10
+ {% for palabra in palabras %}
11
+ <th class="py-2 px-3 border border-surface-general uppercase">{{ palabra }}</th>
12
+ {% endfor %}
13
+ </tr>
14
+ </thead>
15
+ <tbody class="bg-surface-ligt divide-y divide-gray-200">
16
+ {% for usuario, productos in catadores.items %}
17
+ {% for codigo, valores in productos.items %}
18
+ <tr>
19
+ <td class="py-2 px-3 border border-surface-general">{{ usuario }}</td>
20
+ <td class="py-2 px-3 border border-surface-general">{{ codigo }}</td>
21
+ {% for palabra in palabras %}
22
+ <td class="py-2 px-3 border border-surface-general">
23
+ {% with match=None %}
24
+ {% for valor in valores %}
25
+ {% if valor.nombre_palabra == palabra %}
26
+ {{ palabra }} <br>
27
+ {{ valor.dato_valor }}
28
+ {% with match=True %}{% endwith %}
29
+ {% endif %}
30
+ {% endfor %}
31
+ {% if not match %}0{% endif %}
32
+ {% endwith %}
33
+ </td>
34
+ {% endfor %}
35
+ </tr>
36
+ {% endfor %}
37
+ {% endfor %}
38
+ </tbody>
39
+ </table>
40
+ </div>
41
+
42
+ <div class="flex justify-end mt-3">
43
+ <button class="cts-btn-general cts-btn-primary btn-push">
44
+ Descargar CSV
45
+ </button>
46
+ </div>
47
+ </section>
tecnicas/templates/tecnicas/manage_sesions/detalles-sesion.html CHANGED
@@ -6,20 +6,17 @@
6
  {% block content %}
7
  <article class="cts-container-main">
8
  <article class="cts-wrap-content">
9
- <header class="text-center flex-row w-full flex justify-around items-center flex-wrap gap-10">
10
  <h1 class="text-black rounded-xl font-bold text-2xl bg-surface-card shadow-lg p-4 flex-1">
11
  Detalles de la sesión
12
  </h1>
13
- <a href="{% url 'cata_system:index' %}" class="w-fit">
14
- <button
15
- class="cts-btn-general cts-btn-error btn-push">
16
- Volver a las Sesiones
17
- </button>
18
- </a>
19
  </header>
20
 
21
  {% if error %}
22
- <article class="bg-red-600 p-4 text-white rounded-xl ct-notification-error">
23
  <p class="block font-sans text-white text-xl antialiased font-bold uppercase tracking-wider text-center">
24
  {{ error }}
25
  </p>
@@ -111,7 +108,7 @@
111
  </section>
112
 
113
  <section>
114
- <p class="font-medium">
115
  Rep. Max:
116
  </p>
117
  <p class="font-sans text-lg max-sm:text-base font-normal">
@@ -137,7 +134,7 @@
137
  {% for palabra in palabras %}
138
  <section>
139
  <p class="block text-black text-xl antialiased font-medium">
140
- {{ palabra.nombre_palabra }}
141
  </p>
142
  </section>
143
  {% endfor %}
@@ -182,16 +179,16 @@
182
  Datos obtenidos
183
  </p>
184
 
185
- {% if calificaciones.error %}
186
- <article class="bg-surface-card p-4 text-white rounded-xl">
187
- <p class="block font-sans text-xl antialiased font-normal uppercase tracking-wider text-center">
188
- {{ calificaciones.error }}
189
- </p>
190
  </article>
191
  {% else %}
192
- <article class="bg-surface-card p-4 text-white rounded-xl">
193
- </article>
194
  {% endif %}
 
195
  <form action="" method="post" class="form-action-session hidden">
196
  {% csrf_token %}
197
  </form>
 
6
  {% block content %}
7
  <article class="cts-container-main">
8
  <article class="cts-wrap-content">
9
+ <header class="text-center flex-row max-sm:flex-col w-full flex justify-around items-center flex-wrap gap-10">
10
  <h1 class="text-black rounded-xl font-bold text-2xl bg-surface-card shadow-lg p-4 flex-1">
11
  Detalles de la sesión
12
  </h1>
13
+ <button class="cts-btn-general cts-btn-error btn-push" onclick="window.history.back()">
14
+ Volver a las Sesiones
15
+ </button>
 
 
 
16
  </header>
17
 
18
  {% if error %}
19
+ <article class=" bg-red-600 p-4 text-white rounded-xl ct-notification-error">
20
  <p class="block font-sans text-white text-xl antialiased font-bold uppercase tracking-wider text-center">
21
  {{ error }}
22
  </p>
 
108
  </section>
109
 
110
  <section>
111
+ <p class="font-bold">
112
  Rep. Max:
113
  </p>
114
  <p class="font-sans text-lg max-sm:text-base font-normal">
 
134
  {% for palabra in palabras %}
135
  <section>
136
  <p class="block text-black text-xl antialiased font-medium">
137
+ {{ palabra }}
138
  </p>
139
  </section>
140
  {% endfor %}
 
179
  Datos obtenidos
180
  </p>
181
 
182
+ {% if existen_calificaciones %}
183
+ <article class="bg-surface-card p-4 max-sm:px-2 text-black rounded">
184
+ {% for repeticion, catadores in calificaciones.items %}
185
+ {% include "../components/table-convencional.html" with repeticion=repeticion catadores=catadores palabras=palabras %}
186
+ {% endfor %}
187
  </article>
188
  {% else %}
189
+ {% include "../components/error-message.html" with message='Sin calificaciones que mostrar aún' %}
 
190
  {% endif %}
191
+
192
  <form action="" method="post" class="form-action-session hidden">
193
  {% csrf_token %}
194
  </form>
tecnicas/templates/tecnicas/manage_sesions/monitor-sesion.html CHANGED
@@ -1,4 +1,5 @@
1
  {% extends 'tecnicas/layouts/base.html' %}
 
2
 
3
  {% block title %}Monitoreo{% endblock %}
4
 
@@ -17,22 +18,36 @@
17
  </article>
18
  {% endif %}
19
 
20
- <section class="flex flex-col sm:flex-row justify-between items-center gap-10 mb-6">
21
  <p class="text-xl text-center bg-surface-card p-4 text-black rounded-lg shadow-lg">
22
  Código de sesión:<br>
23
  <span class="font-mono text-2xl font-bold">{{ code_session }}</span>
24
  </p>
25
- <button
26
- class="uppercase text-lg max-sm:text-base tracking-wider p-4 rounded-xl bg-ct-error text-white font-bold border-red-800 btn-push">
27
- Finalizar sesión
28
- </button>
 
 
 
 
 
 
29
  </section>
30
 
 
 
 
 
 
 
 
 
 
31
  <section aria-labelledby="catadores-titulo">
32
  <article
33
  class="flex max-sm:flex-col justify-around bg-surface-card border border-gray-300 rounded-md p-3 mb-4 items-center shadow-lg">
34
- <button
35
- class="uppercase text-lg max-sm:text-base tracking-wider p-2 px-3 transition-all rounded-xl bg-btn-secondary font-bold btn-push border-pink-800"
36
  onclick="reloadPage()">
37
  Actualizar lista
38
  </button>
@@ -108,4 +123,5 @@
108
  location.reload()
109
  }
110
  </script>
 
111
  {% endblock %}
 
1
  {% extends 'tecnicas/layouts/base.html' %}
2
+ {% load static %}
3
 
4
  {% block title %}Monitoreo{% endblock %}
5
 
 
18
  </article>
19
  {% endif %}
20
 
21
+ <section class="flex flex-col sm:flex-row justify-between items-center gap-10">
22
  <p class="text-xl text-center bg-surface-card p-4 text-black rounded-lg shadow-lg">
23
  Código de sesión:<br>
24
  <span class="font-mono text-2xl font-bold">{{ code_session }}</span>
25
  </p>
26
+ <div class="flex flex-col gap-2">
27
+ <button class="uppercase cts-btn-general-compress cts-btn-secondary py-2 px-6 btn-push"
28
+ onclick="finishSession()">
29
+ Finalizar sesión
30
+ </button>
31
+ <button class="uppercase cts-btn-general-compress cts-btn-error py-2 px-6 btn-push"
32
+ onclick="window.history.back()">
33
+ Regresar
34
+ </button>
35
+ </div>
36
  </section>
37
 
38
+ <form action="" method="post" class="hidden action-form">
39
+ <input type="hidden" name="action">
40
+ {% csrf_token %}
41
+ </form>
42
+
43
+ {% if message %}
44
+ {% include "../components/error-message.html" with message=message %}
45
+ {% endif %}
46
+
47
  <section aria-labelledby="catadores-titulo">
48
  <article
49
  class="flex max-sm:flex-col justify-around bg-surface-card border border-gray-300 rounded-md p-3 mb-4 items-center shadow-lg">
50
+ <button class="uppercase cts-btn-general-compress cts-btn-tertiary py-2 px-6 btn-push"
 
51
  onclick="reloadPage()">
52
  Actualizar lista
53
  </button>
 
123
  location.reload()
124
  }
125
  </script>
126
+ <script src="{% static 'js/finish-session.js' %}"></script>
127
  {% endblock %}
tecnicas/templates/tecnicas/manage_sesions/sesiones-panel.html CHANGED
@@ -22,7 +22,7 @@
22
  <section class="grid grid-cols-3 max-lg:grid-cols-2 max-sm:grid-cols-1 w-full gap-4 justify-center">
23
  {% for sesion in sessions %}
24
  <div class="card bg-surface-card shadow-lg text-black sm:max-w-80 w-full flex justify-center items-center">
25
- <div class="card-body flex flex-col justify-between">
26
  <div class="flex flex-col gap-1 [&>*]:first:text-xl [&>*]:first:font-bold [&>*]:first:border-b">
27
  {% if sesion.nombre_sesion %}
28
  <h2>{{ sesion.nombre_sesion }}</h2>
 
22
  <section class="grid grid-cols-3 max-lg:grid-cols-2 max-sm:grid-cols-1 w-full gap-4 justify-center">
23
  {% for sesion in sessions %}
24
  <div class="card bg-surface-card shadow-lg text-black sm:max-w-80 w-full flex justify-center items-center">
25
+ <div class="card-body flex flex-col justify-between w-full">
26
  <div class="flex flex-col gap-1 [&>*]:first:text-xl [&>*]:first:font-bold [&>*]:first:border-b">
27
  {% if sesion.nombre_sesion %}
28
  <h2>{{ sesion.nombre_sesion }}</h2>
tecnicas/utils/__init__.py CHANGED
@@ -2,4 +2,5 @@ from .code_generate import generarCodigo
2
  from .code_generate import generarCodigos
3
  from .personal_errors import general_error, controller_error
4
  from .shuffle_arrays import shuffleArray
5
- from .general_controllers import getId
 
 
2
  from .code_generate import generarCodigos
3
  from .personal_errors import general_error, controller_error
4
  from .shuffle_arrays import shuffleArray
5
+ from .general_controllers import getId
6
+ from .to_dict import defaultdict_to_dict
tecnicas/utils/to_dict.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ from collections import defaultdict
2
+
3
+
4
+ def defaultdict_to_dict(d):
5
+ if isinstance(d, defaultdict):
6
+ d = {k: defaultdict_to_dict(v) for k, v in d.items()}
7
+ elif isinstance(d, dict):
8
+ d = {k: defaultdict_to_dict(v) for k, v in d.items()}
9
+ return d
tecnicas/views/sessions_management/session_details.py CHANGED
@@ -5,19 +5,21 @@ from ...controllers import DetallesSesionController
5
 
6
 
7
  def sessionDetails(req: HttpRequest, session_code: str):
8
- context = DetallesSesionController.getContextForView(session_code)
 
9
 
10
  if req.method == "GET":
 
11
  return render(req, "tecnicas/manage_sesions/detalles-sesion.html", context)
12
  elif req.method == "POST":
13
  if req.POST["action"] == "start_session":
14
  response = DetallesSesionController.startRepetition(
15
  session_code=session_code, username=req.POST["username"])
16
  if isinstance(response, dict):
 
17
  context["error"] = response["error"]
18
  return render(req, "tecnicas/manage_sesions/detalles-sesion.html", context)
19
- context["message"] = "La sesión ha iniciado"
20
- return render(req, "tecnicas/manage_sesions/detalles-sesion.html", context)
21
  elif req.POST.get("action") == "delete_session":
22
  pass
23
  elif req.POST.get("action") == "monitor_session":
 
5
 
6
 
7
  def sessionDetails(req: HttpRequest, session_code: str):
8
+ controller_view = DetallesSesionController(session_code)
9
+ context = controller_view.getContextForView()
10
 
11
  if req.method == "GET":
12
+ context = controller_view.getContextWithData()
13
  return render(req, "tecnicas/manage_sesions/detalles-sesion.html", context)
14
  elif req.method == "POST":
15
  if req.POST["action"] == "start_session":
16
  response = DetallesSesionController.startRepetition(
17
  session_code=session_code, username=req.POST["username"])
18
  if isinstance(response, dict):
19
+ context = controller_view.getContextWithData()
20
  context["error"] = response["error"]
21
  return render(req, "tecnicas/manage_sesions/detalles-sesion.html", context)
22
+ return redirect(reverse("cata_system:monitor_sesion"))
 
23
  elif req.POST.get("action") == "delete_session":
24
  pass
25
  elif req.POST.get("action") == "monitor_session":
tecnicas/views/sessions_management/session_monitor.py CHANGED
@@ -1,17 +1,44 @@
 
 
 
 
 
 
1
  from django.http import HttpRequest, JsonResponse
2
- from django.shortcuts import render
 
3
  from tecnicas.controllers import MonitorSesionController
 
4
 
5
 
6
  def sessionMonitor(req: HttpRequest, session_code: str):
7
- if req.method == "GET":
8
- controll_view = MonitorSesionController(session_code)
9
 
10
- context = controll_view.monitorView()
11
  if "error" in context:
12
  return render(req, "tecnicas/manage_sesions/monitor-sesion.html", context)
13
-
14
  context["code_session"] = session_code
15
  return render(req, "tecnicas/manage_sesions/monitor-sesion.html", context)
 
 
 
 
 
 
16
  else:
17
  return JsonResponse({"error": "Método no permitido"})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Para finalizar la sesion se debe realizar lo siguiente
3
+ # Obtener todas las participaciones
4
+
5
+ '''
6
+
7
  from django.http import HttpRequest, JsonResponse
8
+ from django.shortcuts import render, redirect
9
+ from django.urls import reverse
10
  from tecnicas.controllers import MonitorSesionController
11
+ from tecnicas.utils import general_error
12
 
13
 
14
  def sessionMonitor(req: HttpRequest, session_code: str):
15
+ controll_view = MonitorSesionController(session_code)
16
+ context = controll_view.monitorView()
17
 
18
+ if req.method == "GET":
19
  if "error" in context:
20
  return render(req, "tecnicas/manage_sesions/monitor-sesion.html", context)
21
+
22
  context["code_session"] = session_code
23
  return render(req, "tecnicas/manage_sesions/monitor-sesion.html", context)
24
+ elif req.method == "POST":
25
+ action = req.POST["action"]
26
+ if action == "finish_session":
27
+ return actionFinishSession(context=context, session_code=session_code, controll_view=controll_view, req=req)
28
+ else:
29
+ return general_error("No se ha especificado la acción")
30
  else:
31
  return JsonResponse({"error": "Método no permitido"})
32
+
33
+
34
+ def actionFinishSession(context: dict, session_code: str, controll_view: MonitorSesionController, req: HttpRequest):
35
+ context["code_session"] = session_code
36
+ (is_all_end, message) = controll_view.checkAllParticipantsEnded()
37
+ context["message"] = message
38
+ if not is_all_end:
39
+ return render(req, "tecnicas/manage_sesions/monitor-sesion.html", context)
40
+ response = controll_view.finishSession()
41
+ if isinstance(response, dict):
42
+ context["message"] = response["error"]
43
+ return render(req, "tecnicas/manage_sesions/monitor-sesion.html", context)
44
+ return redirect(reverse("cata_system:detalles_sesion", kwargs={"session_code": session_code}))
theme/static_src/tailwind.config.js CHANGED
@@ -16,7 +16,7 @@ module.exports = {
16
  "surface-alter-card": "#91C4C3",
17
  "btn-primary": "#4CAF50",
18
  "btn-secondary": "#E45A92",
19
- "btn-tertiary": "#CCECC0",
20
  "ct-success": "#2E7D32",
21
  "ct-error": "#E62727",
22
  },
 
16
  "surface-alter-card": "#91C4C3",
17
  "btn-primary": "#4CAF50",
18
  "btn-secondary": "#E45A92",
19
+ "btn-tertiary": "#88EE88",
20
  "ct-success": "#2E7D32",
21
  "ct-error": "#E62727",
22
  },