chartManD commited on
Commit
9154c54
·
1 Parent(s): db9b8bc

Manejo de errores en login catador

Browse files
cata_system/settings.py CHANGED
@@ -32,6 +32,11 @@ DEBUG = True
32
 
33
  ALLOWED_HOSTS = []
34
 
 
 
 
 
 
35
 
36
  # Application definition
37
 
 
32
 
33
  ALLOWED_HOSTS = []
34
 
35
+ # SESSIONS TIMEOUT
36
+ SESSION_COOKIE_AGE = 30 * 60
37
+
38
+ SESSION_EXPIRE_AT_BROWSER_CLOSE = True
39
+
40
 
41
  # Application definition
42
 
tecnicas/controllers/__init__.py CHANGED
@@ -7,4 +7,5 @@ from .estilo_palabras_controller import EstiloPalabrasController
7
  from .palabras_controller import PalabrasController
8
  from .sesion_controller import SesionController
9
  from .calificacion_controller import CalificacionController
10
- from .detalles_sesion_controller import DetallesSesionController
 
 
7
  from .palabras_controller import PalabrasController
8
  from .sesion_controller import SesionController
9
  from .calificacion_controller import CalificacionController
10
+ from .detalles_sesion_controller import DetallesSesionController
11
+ from .login_tester_controller import LoginTesterController
tecnicas/controllers/login_tester_controller.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from ..models import Catador, SesionSensorial, Participacion
2
+ from ..utils import controller_error
3
+ from django.db import transaction
4
+
5
+
6
+ class LoginTesterController():
7
+ tester: Catador
8
+ session: SesionSensorial
9
+ taster_participation: Participacion
10
+
11
+ def __init__(self):
12
+ self.tester = Catador()
13
+ self.session = SesionSensorial()
14
+
15
+ def existCredential(self, user_tester: str, code_session: str):
16
+ try:
17
+ self.tester = Catador.objects.get(usuarioCatador=user_tester)
18
+ self.session = SesionSensorial.objects.get(
19
+ codigo_sesion=code_session)
20
+
21
+ return True
22
+ except (Catador.DoesNotExist, SesionSensorial.DoesNotExist):
23
+ return controller_error("Credenciales inválidas")
24
+
25
+ def validateEntry(self):
26
+ if not self.tester.nombre or not self.session.codigo_sesion:
27
+ return controller_error("Credenciales no definidas")
28
+
29
+ if not self.session.activo:
30
+ return controller_error("La sesión no está activa actualmente")
31
+
32
+ if self.session.tecnica.repecion > 1:
33
+ try:
34
+ self.taster_participation = Participacion.objects.get(
35
+ tecnica=self.session.tecnica, catador=self.tester)
36
+ return self.taster_participation
37
+ except Participacion.DoesNotExist:
38
+ return controller_error("No tienes permitido entrar a esta sesión")
39
+ else:
40
+ try:
41
+ self.taster_participation = Participacion.objects.get(
42
+ tecnica=self.session.tecnica, catador=self.tester)
43
+ return self.taster_participation
44
+ except Participacion.DoesNotExist:
45
+ with transaction.atomic():
46
+ code_session = self.session.codigo_sesion
47
+ self.session = SesionSensorial.objects.select_for_update().get(
48
+ codigo_sesion=code_session)
49
+
50
+ max_testers = self.session.tecnica.limite_catadores
51
+ current_num_testers = Participacion.objects.filter(
52
+ tecnica=self.session.tecnica).count()
53
+
54
+ if current_num_testers >= max_testers:
55
+ return controller_error("La sesión ha alcanzado el número máximo de catadores")
56
+
57
+ self.taster_participation = Participacion.objects.create(
58
+ tecnica=self.session.tecnica,
59
+ catador=self.tester
60
+ )
61
+
62
+ return self.taster_participation
tecnicas/migrations/0015_alter_sesionsensorial_codigo_sesion.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Generated by Django 5.2.1 on 2025-09-18 01:05
2
+
3
+ import shortuuid.main
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('tecnicas', '0014_alter_sesionsensorial_codigo_sesion_and_more'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterField(
15
+ model_name='sesionsensorial',
16
+ name='codigo_sesion',
17
+ field=models.CharField(default=shortuuid.main.ShortUUID.uuid, editable=False, max_length=22, primary_key=True, serialize=False),
18
+ ),
19
+ ]
tecnicas/migrations/0016_alter_sesionsensorial_codigo_sesion_participacion.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Generated by Django 5.2.1 on 2025-09-18 19:49
2
+
3
+ import django.db.models.deletion
4
+ import shortuuid.main
5
+ from django.db import migrations, models
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+
10
+ dependencies = [
11
+ ('tecnicas', '0015_alter_sesionsensorial_codigo_sesion'),
12
+ ]
13
+
14
+ operations = [
15
+ migrations.AlterField(
16
+ model_name='sesionsensorial',
17
+ name='codigo_sesion',
18
+ field=models.CharField(default=shortuuid.main.ShortUUID.uuid, editable=False, max_length=22, primary_key=True, serialize=False),
19
+ ),
20
+ migrations.CreateModel(
21
+ name='Participacion',
22
+ fields=[
23
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
24
+ ('activo', models.BooleanField(default=False)),
25
+ ('finalizado', models.BooleanField(default=True)),
26
+ ('catador', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='catador_participacion', to='tecnicas.catador')),
27
+ ('tecnica', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tecnica_participacion', to='tecnicas.tecnica')),
28
+ ],
29
+ ),
30
+ ]
tecnicas/migrations/0017_alter_sesionsensorial_codigo_sesion_and_more.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Generated by Django 5.2.1 on 2025-09-18 19:57
2
+
3
+ import shortuuid.main
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('tecnicas', '0016_alter_sesionsensorial_codigo_sesion_participacion'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterField(
15
+ model_name='sesionsensorial',
16
+ name='codigo_sesion',
17
+ field=models.CharField(default=shortuuid.main.ShortUUID.uuid, editable=False, max_length=22, primary_key=True, serialize=False),
18
+ ),
19
+ migrations.DeleteModel(
20
+ name='Participacion',
21
+ ),
22
+ ]
tecnicas/migrations/0018_alter_sesionsensorial_codigo_sesion_participacion.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Generated by Django 5.2.1 on 2025-09-18 19:58
2
+
3
+ import django.db.models.deletion
4
+ import shortuuid.main
5
+ from django.db import migrations, models
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+
10
+ dependencies = [
11
+ ('tecnicas', '0017_alter_sesionsensorial_codigo_sesion_and_more'),
12
+ ]
13
+
14
+ operations = [
15
+ migrations.AlterField(
16
+ model_name='sesionsensorial',
17
+ name='codigo_sesion',
18
+ field=models.CharField(default=shortuuid.main.ShortUUID.uuid, editable=False, max_length=22, primary_key=True, serialize=False),
19
+ ),
20
+ migrations.CreateModel(
21
+ name='Participacion',
22
+ fields=[
23
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
24
+ ('activo', models.BooleanField(default=False)),
25
+ ('finalizado', models.BooleanField(default=True)),
26
+ ('catador', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='catador_participacion', to='tecnicas.catador')),
27
+ ('tecnica', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tecnica_participacion', to='tecnicas.tecnica')),
28
+ ],
29
+ ),
30
+ ]
tecnicas/models/__init__.py CHANGED
@@ -25,4 +25,6 @@ from .dato_valor import ValorDecimal
25
  from .dato_valor import ValorBooleano
26
 
27
  from .orden import Orden
28
- from .orden import Posicion
 
 
 
25
  from .dato_valor import ValorBooleano
26
 
27
  from .orden import Orden
28
+ from .orden import Posicion
29
+
30
+ from .participacion import Participacion
tecnicas/models/participacion.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from django.db import models
2
+ from .tecnica import Tecnica
3
+ from .catador import Catador
4
+
5
+
6
+ class Participacion(models.Model):
7
+ tecnica = models.ForeignKey(
8
+ Tecnica, on_delete=models.CASCADE, related_name="tecnica_participacion")
9
+ catador = models.ForeignKey(
10
+ Catador, on_delete=models.CASCADE, related_name="catador_participacion")
11
+ activo = models.BooleanField(default=False)
12
+ finalizado = models.BooleanField(default=True)
13
+
14
+ def __str__(self):
15
+ return f"{self.catador.usuarioCatador} {'activo' if self.activo else 'no activo'}"
tecnicas/pato.py DELETED
@@ -1,42 +0,0 @@
1
- from django.db import models
2
-
3
- class Presentador(models.Model):
4
- nombre = models.CharField(max_length=255)
5
- apellido = models.CharField(max_length=255)
6
- nombre_usuario = models.CharField(max_length=255)
7
- contrasena = models.CharField(max_length=255)
8
-
9
- class Palabra(models.Model):
10
- nombre_palabra = models.CharField(max_length=255, unique=True)
11
-
12
- class Vocabualario(models.Model):
13
- nomre_vocabulario = models.CharField(max_length=255, unique=True)
14
- palabras = models.ManyToManyField(Palabra)
15
-
16
- class EstiloPalabra(models.Model):
17
- nombre_estilo = models.CharField(max_length=255, unique=True)
18
-
19
- class EsAtributo(models.Model):
20
- id_estilo = models.ForeignKey(EstiloPalabra, on_delete=models.CASCADE, related_name="estilo_esatributo")
21
-
22
- class ListaPalabra(models.Model):
23
- id_palabra = models.ForeignKey(Palabra, on_delete=models.CASCADE, related_name="palabra_listapalabras")
24
- id_atributos = models.ForeignKey(EsAtributo, on_delete=models.CASCADE, related_name="atributo_listapalabras")
25
-
26
- class EsVocabulario(models.Model):
27
- id_estilo = models.ForeignKey(EstiloPalabra, on_delete=models.CASCADE, related_name="estilo_esvacabulario")
28
- id_vocabulario = models.ForeignKey(Vocabualario, on_delete=models.CASCADE, related_name="vocabulario_esvocabulario")
29
-
30
- class Tecnica(models.Model):
31
- nombre_tecnica = models.CharField(max_length=255)
32
- maximas_repeticiones = models.IntegerField(default=0)
33
- repecion = models.IntegerField(default=0)
34
- limite_catadores = models.IntegerField()
35
- instrucciones = models.CharField(max_length=255)
36
- id_estilo = models.ForeignKey(EstiloPalabra, on_delete=models.CASCADE, related_name="estilo_tecnica")
37
-
38
- class SesionSensorial(models.Model):
39
- fechaCreacion = models.DateTimeField("date published")
40
- activo = models.BooleanField(default=False)
41
- creadoPor = models.ForeignKey(Presentador, on_delete=models.CASCADE, related_name="presentador_sesion")
42
- tecnica = models.ForeignKey(Tecnica, on_delete=models.CASCADE, related_name="sesion_tecnica")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tecnicas/templates/tecnicas/cata-login.html CHANGED
@@ -4,20 +4,32 @@
4
 
5
  {% block content %}
6
  <article class="w-full h-full flex flex-col justify-center items-center bg-gray-600">
7
- <form action="./auth" method="post" class="bg-gray-200 w-xl p-8 rounded-xl">
 
8
  <header class="text-center">
9
  <h1 class="text-5xl font-bold">Cateo System</h1>
10
  <p class="text-2xl font-medium mt-3">Catadores</p>
11
  </header>
12
- <section class="flex flex-col gap-6 items-center w-full mt-5">
 
 
 
 
 
 
 
 
 
13
  <label for="id">
14
- <input type="text" name="id" id="id" placeholder="Codigo de sesion"
15
- class="placeholder:text-gray-100 placeholder:text-xl bg-gray-400 py-3 px-6 rounded-xl w-sm border-b-2 border-blue-700" required>
 
16
  </label>
17
 
18
  <label for="id">
19
- <input type="text" name="id" id="id" placeholder="Nombre de usuario"
20
- class="placeholder:text-gray-100 placeholder:text-xl bg-gray-400 py-3 px-6 rounded-xl w-sm border-b-2 border-blue-700" required>
 
21
  </label>
22
 
23
  <section class="flex flex-row flex-wrap gap-4 w-f ull justify-center">
@@ -25,7 +37,16 @@
25
  class="text-white bg-blue-600 hover:bg-blue-700 active:outline-none active:ring-4 active:ring-blue-300 font-medium rounded-xl text-xl px-8 py-2 text-center uppercase">Ingresar</button>
26
  </section>
27
 
28
- </section>
29
  </form>
30
  </article>
 
 
 
 
 
 
 
 
 
31
  {% endblock %}
 
4
 
5
  {% block content %}
6
  <article class="w-full h-full flex flex-col justify-center items-center bg-gray-600">
7
+ <form action="" method="post" class="bg-gray-200 w-xl p-8 rounded-xl">
8
+ {% csrf_token %}
9
  <header class="text-center">
10
  <h1 class="text-5xl font-bold">Cateo System</h1>
11
  <p class="text-2xl font-medium mt-3">Catadores</p>
12
  </header>
13
+
14
+ {% if error %}
15
+ <article class="bg-red-600 p-4 text-white rounded-xl ct-notification-error">
16
+ <p class="block font-sans text-white text-xl antialiased font-bold uppercase tracking-wider text-center">
17
+ {{ error }}
18
+ </p>
19
+ </article>
20
+ {% endif %}
21
+
22
+ <article class="flex flex-col gap-6 items-center w-full mt-5">
23
  <label for="id">
24
+ <input type="text" name="code_session" id="id" placeholder="Codigo de sesion"
25
+ class="placeholder:text-gray-100 placeholder:text-xl bg-gray-400 py-3 px-6 rounded-xl w-sm border-b-2 border-blue-700"
26
+ required>
27
  </label>
28
 
29
  <label for="id">
30
+ <input type="text" name="user_tester" id="id" placeholder="Nombre de usuario"
31
+ class="placeholder:text-gray-100 placeholder:text-xl bg-gray-400 py-3 px-6 rounded-xl w-sm border-b-2 border-blue-700"
32
+ required>
33
  </label>
34
 
35
  <section class="flex flex-row flex-wrap gap-4 w-f ull justify-center">
 
37
  class="text-white bg-blue-600 hover:bg-blue-700 active:outline-none active:ring-4 active:ring-blue-300 font-medium rounded-xl text-xl px-8 py-2 text-center uppercase">Ingresar</button>
38
  </section>
39
 
40
+ </article>
41
  </form>
42
  </article>
43
+ {% endblock %}
44
+
45
+ {% block extra_js %}
46
+ <script>
47
+ const error = document.querySelector(".ct-notification-error")
48
+ setTimeout(() => {
49
+ error.classList.add("hidden")
50
+ }, 2500)
51
+ </script>
52
  {% endblock %}
tecnicas/urls.py CHANGED
@@ -13,7 +13,7 @@ urlpatterns = [
13
  name="autenticacion"),
14
 
15
  path("catador-login",
16
- views.catadorLogin,
17
  name="catador_login"),
18
 
19
 
 
13
  name="autenticacion"),
14
 
15
  path("catador-login",
16
+ views.testerLogin,
17
  name="catador_login"),
18
 
19
 
tecnicas/views/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
  from .autentication import autentication
2
- from .login_catador import catadorLogin
3
  from .main_panel import mainPanel
4
 
5
  from .sessions_management.sessions_panel import sesionsPanel
 
1
  from .autentication import autentication
2
+ from .login_tester import testerLogin
3
  from .main_panel import mainPanel
4
 
5
  from .sessions_management.sessions_panel import sesionsPanel
tecnicas/views/login_catador.py DELETED
@@ -1,4 +0,0 @@
1
- from django.shortcuts import render
2
-
3
- def catadorLogin(req):
4
- return render(req, "tecnicas/cata-login.html")
 
 
 
 
 
tecnicas/views/login_tester.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from django.http import HttpRequest
2
+ from django.shortcuts import render
3
+ from ..utils import general_error
4
+ from ..controllers import LoginTesterController
5
+
6
+
7
+ def testerLogin(req: HttpRequest):
8
+ if req.method == "GET":
9
+ return render(req, "tecnicas/cata-login.html")
10
+ elif req.method == "POST":
11
+ tester_user = req.POST.get("user_tester")
12
+ session_code = req.POST.get("code_session")
13
+ if not tester_user or not session_code:
14
+ return general_error("Se esperan credenciales")
15
+
16
+ login_controller = LoginTesterController()
17
+
18
+ existCredentials = login_controller.existCredential(
19
+ tester_user, session_code)
20
+ if isinstance(existCredentials, dict):
21
+ context = {"error": existCredentials["error"]}
22
+ return render(req, "tecnicas/cata-login.html", context)
23
+
24
+ taster_participation = login_controller.validateEntry()
25
+ if isinstance(taster_participation, dict):
26
+ context = {"error": taster_participation["error"]}
27
+ return render(req, "tecnicas/cata-login.html", context)
28
+
29
+ req.session["cata_username"] = tester_user
30
+ req.session["code_session"] = session_code
31
+
32
+ req.session.set_expiry(20*60)
33
+ else:
34
+ return render(req, "tecnicas/cata-login.html")