Spaces:
Running
Running
Merge pull request #3 from CascoArcilla/HU8
Browse files- cata_system/settings.py +6 -0
- tecnicas/admin.py +2 -0
- tecnicas/controllers/__init__.py +3 -1
- tecnicas/controllers/detalles_sesion_controller.py +8 -5
- tecnicas/controllers/login_tester_controller.py +62 -0
- tecnicas/controllers/main_tester_form_controller.py +48 -0
- tecnicas/controllers/presentador_controller.py +14 -0
- tecnicas/controllers/sesion_controller.py +28 -7
- tecnicas/controllers/tecnica_controller.py +8 -0
- tecnicas/middlewares/__init__.py +1 -0
- tecnicas/middlewares/login_tester_middleware.py +19 -0
- tecnicas/migrations/0015_alter_sesionsensorial_codigo_sesion.py +19 -0
- tecnicas/migrations/0016_alter_sesionsensorial_codigo_sesion_participacion.py +30 -0
- tecnicas/migrations/0017_alter_sesionsensorial_codigo_sesion_and_more.py +22 -0
- tecnicas/migrations/0018_alter_sesionsensorial_codigo_sesion_participacion.py +30 -0
- tecnicas/models/__init__.py +3 -1
- tecnicas/models/participacion.py +15 -0
- tecnicas/models/sesion_sensorial.py +1 -1
- tecnicas/pato.py +0 -42
- tecnicas/static/img/check.svg +4 -0
- tecnicas/static/img/exit.svg +12 -0
- tecnicas/static/img/monitor.svg +12 -0
- tecnicas/static/js/details-session.js +1 -1
- tecnicas/static/js/start-tester-test.js +4 -0
- tecnicas/templates/tecnicas/cata-login.html +28 -7
- tecnicas/templates/tecnicas/forms_tester/main_tester.html +118 -0
- tecnicas/templates/tecnicas/manage_sesions/detalles-sesion.html +16 -0
- tecnicas/urls.py +9 -4
- tecnicas/utils/__init__.py +1 -0
- tecnicas/utils/shuffle_arrays.py +7 -0
- tecnicas/views/__init__.py +3 -1
- tecnicas/views/login_catador.py +0 -4
- tecnicas/views/login_tester.py +36 -0
- tecnicas/views/sessions_management/session_details.py +3 -3
- tecnicas/views/tester_forms/main_tester_form.py +33 -0
cata_system/settings.py
CHANGED
|
@@ -32,6 +32,11 @@ DEBUG = True
|
|
| 32 |
|
| 33 |
ALLOWED_HOSTS = []
|
| 34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
# Application definition
|
| 37 |
|
|
@@ -65,6 +70,7 @@ MIDDLEWARE = [
|
|
| 65 |
|
| 66 |
'django_browser_reload.middleware.BrowserReloadMiddleware',
|
| 67 |
|
|
|
|
| 68 |
]
|
| 69 |
|
| 70 |
ROOT_URLCONF = 'cata_system.urls'
|
|
|
|
| 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 |
|
|
|
|
| 70 |
|
| 71 |
'django_browser_reload.middleware.BrowserReloadMiddleware',
|
| 72 |
|
| 73 |
+
'tecnicas.middlewares.LoginTesterMiddleware'
|
| 74 |
]
|
| 75 |
|
| 76 |
ROOT_URLCONF = 'cata_system.urls'
|
tecnicas/admin.py
CHANGED
|
@@ -20,6 +20,7 @@ from .models import Escala
|
|
| 20 |
from .models import EtiquetasEscala
|
| 21 |
|
| 22 |
from .models import Producto
|
|
|
|
| 23 |
|
| 24 |
# Register your models here.
|
| 25 |
admin.site.register(CategoriaTecnica)
|
|
@@ -41,3 +42,4 @@ admin.site.register(Escala)
|
|
| 41 |
admin.site.register(EtiquetasEscala)
|
| 42 |
|
| 43 |
admin.site.register(Producto)
|
|
|
|
|
|
| 20 |
from .models import EtiquetasEscala
|
| 21 |
|
| 22 |
from .models import Producto
|
| 23 |
+
from .models import Participacion
|
| 24 |
|
| 25 |
# Register your models here.
|
| 26 |
admin.site.register(CategoriaTecnica)
|
|
|
|
| 42 |
admin.site.register(EtiquetasEscala)
|
| 43 |
|
| 44 |
admin.site.register(Producto)
|
| 45 |
+
admin.site.register(Participacion)
|
tecnicas/controllers/__init__.py
CHANGED
|
@@ -7,4 +7,6 @@ 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
|
| 12 |
+
from .main_tester_form_controller import MainTesterFormController
|
tecnicas/controllers/detalles_sesion_controller.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
from ..models import SesionSensorial, Presentador
|
| 2 |
from . import CalificacionController, PalabrasController
|
| 3 |
from ..utils import controller_error
|
| 4 |
|
|
@@ -25,22 +25,25 @@ class DetallesSesionController():
|
|
| 25 |
try:
|
| 26 |
creator = Presentador.objects.get(nombre_usuario=username)
|
| 27 |
session = SesionSensorial.objects.get(codigo_sesion=session_code)
|
|
|
|
| 28 |
except Presentador.DoesNotExist:
|
| 29 |
return controller_error("no existe presentador")
|
| 30 |
except SesionSensorial.DoesNotExist:
|
| 31 |
return controller_error("no existe sesión sensorial")
|
|
|
|
|
|
|
| 32 |
|
| 33 |
if creator.nombre_usuario != session.creadoPor.nombre_usuario:
|
| 34 |
return controller_error("solo el presentador que crea la sesión puede iniciar la repetición")
|
| 35 |
elif session.activo:
|
| 36 |
return controller_error("la sesión ya está activada")
|
| 37 |
-
elif
|
| 38 |
return controller_error("se ha alcanzado el número de repeticiones máxima")
|
| 39 |
|
| 40 |
session.activo = True
|
| 41 |
-
|
| 42 |
-
session.tecnica.repecion = rep + 1
|
| 43 |
|
|
|
|
| 44 |
session.save()
|
| 45 |
-
|
| 46 |
return session
|
|
|
|
| 1 |
+
from ..models import SesionSensorial, Presentador, Tecnica
|
| 2 |
from . import CalificacionController, PalabrasController
|
| 3 |
from ..utils import controller_error
|
| 4 |
|
|
|
|
| 25 |
try:
|
| 26 |
creator = Presentador.objects.get(nombre_usuario=username)
|
| 27 |
session = SesionSensorial.objects.get(codigo_sesion=session_code)
|
| 28 |
+
technique = Tecnica.objects.get(id=session.tecnica.id)
|
| 29 |
except Presentador.DoesNotExist:
|
| 30 |
return controller_error("no existe presentador")
|
| 31 |
except SesionSensorial.DoesNotExist:
|
| 32 |
return controller_error("no existe sesión sensorial")
|
| 33 |
+
except Tecnica.DoesNotExist:
|
| 34 |
+
return controller_error("Ha ocurrido un error al recuperar la técnica")
|
| 35 |
|
| 36 |
if creator.nombre_usuario != session.creadoPor.nombre_usuario:
|
| 37 |
return controller_error("solo el presentador que crea la sesión puede iniciar la repetición")
|
| 38 |
elif session.activo:
|
| 39 |
return controller_error("la sesión ya está activada")
|
| 40 |
+
elif technique.repecion == technique.repeticiones_max:
|
| 41 |
return controller_error("se ha alcanzado el número de repeticiones máxima")
|
| 42 |
|
| 43 |
session.activo = True
|
| 44 |
+
technique.repecion = technique.repecion + 1
|
|
|
|
| 45 |
|
| 46 |
+
technique.save()
|
| 47 |
session.save()
|
| 48 |
+
|
| 49 |
return session
|
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/controllers/main_tester_form_controller.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from ..models import Catador, SesionSensorial, Orden
|
| 2 |
+
from ..utils import controller_error, shuffleArray
|
| 3 |
+
from django.db import transaction
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class MainTesterFormController():
|
| 7 |
+
tester: Catador
|
| 8 |
+
session: SesionSensorial
|
| 9 |
+
order: Orden | dict
|
| 10 |
+
|
| 11 |
+
def __init__(self, code_session: str, user_tester: str):
|
| 12 |
+
try:
|
| 13 |
+
self.tester = Catador.objects.get(usuarioCatador=user_tester)
|
| 14 |
+
self.session = SesionSensorial.objects.get(
|
| 15 |
+
codigo_sesion=code_session)
|
| 16 |
+
except (Catador.DoesNotExist, SesionSensorial.DoesNotExist):
|
| 17 |
+
return controller_error("Parámetros inexistentes")
|
| 18 |
+
|
| 19 |
+
def assignOrder(self):
|
| 20 |
+
self.checkAssignOrder()
|
| 21 |
+
if isinstance(self.order, Orden):
|
| 22 |
+
return self.order
|
| 23 |
+
|
| 24 |
+
with transaction.atomic():
|
| 25 |
+
orders_without_tester = Orden.objects.select_for_update().filter(
|
| 26 |
+
id_tecnica=self.session.tecnica, id_catador=None)
|
| 27 |
+
|
| 28 |
+
if not len(orders_without_tester):
|
| 29 |
+
return controller_error("Las ordenes se han acabado")
|
| 30 |
+
|
| 31 |
+
shuffle_orders = shuffleArray(orders_without_tester)
|
| 32 |
+
self.order_to_assign = shuffle_orders.pop()
|
| 33 |
+
|
| 34 |
+
self.order_to_assign.id_catador = self.tester
|
| 35 |
+
self.order_to_assign.save()
|
| 36 |
+
|
| 37 |
+
return self.order_to_assign
|
| 38 |
+
|
| 39 |
+
def checkAssignOrder(self):
|
| 40 |
+
if not self.tester or self.session:
|
| 41 |
+
return controller_error("Atributos no establecidos")
|
| 42 |
+
|
| 43 |
+
try:
|
| 44 |
+
res_order = Orden.objects.get(
|
| 45 |
+
id_tecnica=self.session.tecnica, id_catador=self.tester.id)
|
| 46 |
+
self.order = res_order
|
| 47 |
+
except Orden.DoesNotExist:
|
| 48 |
+
return controller_error("Catador sin orden")
|
tecnicas/controllers/presentador_controller.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from ..models import Presentador
|
| 2 |
+
from ..utils import controller_error
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class PresentadorController():
|
| 6 |
+
def __init__(self):
|
| 7 |
+
pass
|
| 8 |
+
|
| 9 |
+
@staticmethod
|
| 10 |
+
def getPresenterByUsername(username: str):
|
| 11 |
+
try:
|
| 12 |
+
presenter = Presentador.objects.get(nombre_usuario=username)
|
| 13 |
+
except Presentador.DoesNotExist:
|
| 14 |
+
return controller_error("Presentador inexistente")
|
tecnicas/controllers/sesion_controller.py
CHANGED
|
@@ -54,7 +54,8 @@ class SesionController():
|
|
| 54 |
queryset = SesionSensorial.objects.select_related(
|
| 55 |
"tecnica",
|
| 56 |
"tecnica__tipo_tecnica",
|
| 57 |
-
"tecnica__id_estilo"
|
|
|
|
| 58 |
"codigo_sesion",
|
| 59 |
"nombre_sesion",
|
| 60 |
"fechaCreacion",
|
|
@@ -64,21 +65,41 @@ class SesionController():
|
|
| 64 |
|
| 65 |
paginator = Paginator(queryset, elements_by_page)
|
| 66 |
sessions_in_page = paginator.get_page(page)
|
|
|
|
|
|
|
| 67 |
except PageNotAnInteger:
|
| 68 |
return controller_error("indice invalido")
|
| 69 |
except EmptyPage:
|
| 70 |
return controller_error("sin registros de sessiones")
|
| 71 |
|
| 72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
|
| 74 |
@staticmethod
|
| 75 |
def getNumberSessionsByCreator(user_name: str):
|
| 76 |
try:
|
| 77 |
creator = Presentador.objects.get(nombre_usuario=user_name)
|
| 78 |
-
except Presentador.DoesNotExist:
|
| 79 |
-
return controller_error("presentador invalido")
|
| 80 |
|
| 81 |
-
|
| 82 |
-
|
| 83 |
|
| 84 |
-
|
|
|
|
|
|
|
|
|
| 54 |
queryset = SesionSensorial.objects.select_related(
|
| 55 |
"tecnica",
|
| 56 |
"tecnica__tipo_tecnica",
|
| 57 |
+
"tecnica__id_estilo"
|
| 58 |
+
).only(
|
| 59 |
"codigo_sesion",
|
| 60 |
"nombre_sesion",
|
| 61 |
"fechaCreacion",
|
|
|
|
| 65 |
|
| 66 |
paginator = Paginator(queryset, elements_by_page)
|
| 67 |
sessions_in_page = paginator.get_page(page)
|
| 68 |
+
|
| 69 |
+
return sessions_in_page
|
| 70 |
except PageNotAnInteger:
|
| 71 |
return controller_error("indice invalido")
|
| 72 |
except EmptyPage:
|
| 73 |
return controller_error("sin registros de sessiones")
|
| 74 |
|
| 75 |
+
@staticmethod
|
| 76 |
+
def getSessionByCodePanelTester(code: str):
|
| 77 |
+
try:
|
| 78 |
+
session = SesionSensorial.objects.select_related(
|
| 79 |
+
"tecnica",
|
| 80 |
+
"tecnica__tipo_tecnica",
|
| 81 |
+
"tecnica__id_estilo"
|
| 82 |
+
).only(
|
| 83 |
+
"codigo_sesion",
|
| 84 |
+
"nombre_sesion",
|
| 85 |
+
"tecnica__repecion",
|
| 86 |
+
"tecnica__instrucciones",
|
| 87 |
+
"tecnica__tipo_tecnica__nombre_tecnica",
|
| 88 |
+
"tecnica__id_estilo__nombre_estilo"
|
| 89 |
+
).get(codigo_sesion=code)
|
| 90 |
+
|
| 91 |
+
return session
|
| 92 |
+
except SesionSensorial.DoesNotExist:
|
| 93 |
+
return controller_error("La sesión ya no existe")
|
| 94 |
|
| 95 |
@staticmethod
|
| 96 |
def getNumberSessionsByCreator(user_name: str):
|
| 97 |
try:
|
| 98 |
creator = Presentador.objects.get(nombre_usuario=user_name)
|
|
|
|
|
|
|
| 99 |
|
| 100 |
+
number_sessions = SesionSensorial.objects.filter(
|
| 101 |
+
creadoPor=creator).count()
|
| 102 |
|
| 103 |
+
return number_sessions/9
|
| 104 |
+
except Presentador.DoesNotExist:
|
| 105 |
+
return controller_error("presentador invalido")
|
tecnicas/controllers/tecnica_controller.py
CHANGED
|
@@ -35,6 +35,14 @@ class TecnicaController():
|
|
| 35 |
def deleteTechnique(self):
|
| 36 |
self.technique.delete()
|
| 37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
@staticmethod
|
| 39 |
def getTypesTechnique():
|
| 40 |
showTecnicas = {}
|
|
|
|
| 35 |
def deleteTechnique(self):
|
| 36 |
self.technique.delete()
|
| 37 |
|
| 38 |
+
@staticmethod
|
| 39 |
+
def getTechniqueById(id: int):
|
| 40 |
+
try:
|
| 41 |
+
technique = Tecnica.objects.get(id)
|
| 42 |
+
return technique
|
| 43 |
+
except Tecnica.DoesNotExist:
|
| 44 |
+
return controller_error("Técnica no encontrada")
|
| 45 |
+
|
| 46 |
@staticmethod
|
| 47 |
def getTypesTechnique():
|
| 48 |
showTecnicas = {}
|
tecnicas/middlewares/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
from .login_tester_middleware import LoginTesterMiddleware
|
tecnicas/middlewares/login_tester_middleware.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class LoginTesterMiddleware():
|
| 5 |
+
def __init__(self, get_response):
|
| 6 |
+
self.get_response = get_response
|
| 7 |
+
|
| 8 |
+
def __call__(self, req: HttpRequest):
|
| 9 |
+
url_protected = "/cata/testers/"
|
| 10 |
+
|
| 11 |
+
if req.path.startswith(url_protected):
|
| 12 |
+
if not "cata_username" in req.session:
|
| 13 |
+
from django.shortcuts import redirect
|
| 14 |
+
from django.urls import reverse
|
| 15 |
+
return redirect(reverse("cata_system:catador_login"))
|
| 16 |
+
|
| 17 |
+
response = self.get_response(req)
|
| 18 |
+
|
| 19 |
+
return response
|
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/models/sesion_sensorial.py
CHANGED
|
@@ -17,4 +17,4 @@ class SesionSensorial(models.Model):
|
|
| 17 |
Tecnica, on_delete=models.CASCADE, related_name="sesion_tecnica")
|
| 18 |
|
| 19 |
def __str__(self):
|
| 20 |
-
return self.codigo_sesion
|
|
|
|
| 17 |
Tecnica, on_delete=models.CASCADE, related_name="sesion_tecnica")
|
| 18 |
|
| 19 |
def __str__(self):
|
| 20 |
+
return self.nombre_sesion if self.nombre_sesion else self.codigo_sesion
|
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/static/img/check.svg
ADDED
|
|
tecnicas/static/img/exit.svg
ADDED
|
|
tecnicas/static/img/monitor.svg
ADDED
|
|
tecnicas/static/js/details-session.js
CHANGED
|
@@ -16,7 +16,7 @@ function startRepetition() {
|
|
| 16 |
const inputUser = document.createElement("input");
|
| 17 |
inputUser.type = "hidden";
|
| 18 |
inputUser.name = "username";
|
| 19 |
-
inputUser.value = "
|
| 20 |
|
| 21 |
actionForm.appendChild(inputAction);
|
| 22 |
actionForm.appendChild(inputUser);
|
|
|
|
| 16 |
const inputUser = document.createElement("input");
|
| 17 |
inputUser.type = "hidden";
|
| 18 |
inputUser.name = "username";
|
| 19 |
+
inputUser.value = "aguBido";
|
| 20 |
|
| 21 |
actionForm.appendChild(inputAction);
|
| 22 |
actionForm.appendChild(inputUser);
|
tecnicas/static/js/start-tester-test.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function startTest() {
|
| 2 |
+
const actionForms = document.querySelector(".ct-action-form");
|
| 3 |
+
actionForms.submit();
|
| 4 |
+
}
|
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="
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
<label for="id">
|
| 14 |
-
<input type="text" name="
|
| 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"
|
|
|
|
| 16 |
</label>
|
| 17 |
|
| 18 |
<label for="id">
|
| 19 |
-
<input type="text" name="
|
| 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"
|
|
|
|
| 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 |
-
</
|
| 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 |
+
}, 4000)
|
| 51 |
+
</script>
|
| 52 |
{% endblock %}
|
tecnicas/templates/tecnicas/forms_tester/main_tester.html
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% extends 'tecnicas/layouts/base.html' %}
|
| 2 |
+
{% load static %}
|
| 3 |
+
|
| 4 |
+
{% block title %}Detalles Sesion{% endblock %}
|
| 5 |
+
|
| 6 |
+
{% block content %}
|
| 7 |
+
<article class="w-full flex flex-col justify-center items-center bg-gray-600 mt-10 mb-10">
|
| 8 |
+
<article class="flex flex-col gap-8 bg-gray-400 p-10 rounded-2xl">
|
| 9 |
+
<header class="text-center flex-row w-full flex justify-around items-center flex-wrap gap-10">
|
| 10 |
+
<h1 class="text-white rounded-xl font-bold text-2xl bg-gray-600 p-4 flex-1">
|
| 11 |
+
Panel principal de Catadores
|
| 12 |
+
</h1>
|
| 13 |
+
</header>
|
| 14 |
+
|
| 15 |
+
<article>
|
| 16 |
+
<p class="text-2xl font-medium text-center bg-gray-200 p-4 rounded-lg">
|
| 17 |
+
Información sobre la sesión en la que participa
|
| 18 |
+
</p>
|
| 19 |
+
</article>
|
| 20 |
+
|
| 21 |
+
{% if error %}
|
| 22 |
+
<hr>
|
| 23 |
+
|
| 24 |
+
<article class="bg-red-600 p-4 text-white rounded-xl ct-notification-error">
|
| 25 |
+
<p class="block font-sans text-white text-xl antialiased font-bold uppercase tracking-wider text-center">
|
| 26 |
+
{{ error }}
|
| 27 |
+
</p>
|
| 28 |
+
</article>
|
| 29 |
+
{% endif %}
|
| 30 |
+
|
| 31 |
+
<hr>
|
| 32 |
+
|
| 33 |
+
<article
|
| 34 |
+
class="text-white rounded-xl grid grid-cols-1 gap-3 text-center *:bg-gray-500 *:flex *:flex-wrap *:items-center *:justify-center *:gap-x-2 *:p-4 *:rounded-2xl">
|
| 35 |
+
{% if session %}
|
| 36 |
+
<section>
|
| 37 |
+
<p class="text-xl font-bold">
|
| 38 |
+
Código:
|
| 39 |
+
</p>
|
| 40 |
+
<p class="font-sans text-xl font-normal">
|
| 41 |
+
{{ session.codigo_sesion }}
|
| 42 |
+
</p>
|
| 43 |
+
</section>
|
| 44 |
+
|
| 45 |
+
<section>
|
| 46 |
+
<p class="text-xl font-bold">
|
| 47 |
+
{% if session.nombre_sesion %}
|
| 48 |
+
{{ session.nombre_sesion }}
|
| 49 |
+
{% else %}
|
| 50 |
+
Sin nombre
|
| 51 |
+
{% endif %}
|
| 52 |
+
</p>
|
| 53 |
+
</section>
|
| 54 |
+
|
| 55 |
+
<section>
|
| 56 |
+
<p class="text-xl font-medium">
|
| 57 |
+
Esta sesión usa la técnica <span class="uppercase">{{ session.tecnica.tipo_tecnica }}</span>
|
| 58 |
+
</p>
|
| 59 |
+
</section>
|
| 60 |
+
|
| 61 |
+
<section>
|
| 62 |
+
<p class="text-xl font-medium">
|
| 63 |
+
Esta sesión usa el estilo de palabras
|
| 64 |
+
“<span class="uppercase">{{ session.tecnica.id_estilo }}</span>”
|
| 65 |
+
</p>
|
| 66 |
+
</section>
|
| 67 |
+
|
| 68 |
+
<section>
|
| 69 |
+
<p class="text-xl font-medium">
|
| 70 |
+
Repetición número {{ session.tecnica.repecion }}
|
| 71 |
+
</p>
|
| 72 |
+
</section>
|
| 73 |
+
|
| 74 |
+
<section>
|
| 75 |
+
<p class="text-xl">
|
| 76 |
+
{{ session.tecnica.instrucciones }}
|
| 77 |
+
</p>
|
| 78 |
+
</section>
|
| 79 |
+
{% else %}
|
| 80 |
+
<section>
|
| 81 |
+
<p class="text-xl font-medium">
|
| 82 |
+
Ha ocurrido un error en renderizar esta vista
|
| 83 |
+
</p>
|
| 84 |
+
</section>
|
| 85 |
+
{% endif %}
|
| 86 |
+
</article>
|
| 87 |
+
|
| 88 |
+
<hr>
|
| 89 |
+
|
| 90 |
+
<article class="flex flex-wrap gap-10">
|
| 91 |
+
<button
|
| 92 |
+
class="ct-btn-start-repition flex-1 uppercase text-lg tracking-wider p-4 border-b-2 active:border-b-0 active:border-t-2 active:border-green-500 border-green-800 transition-all rounded-xl bg-green-600 text-white font-bold disabled:bg-amber-600 flex flex-col justify-center items-center gap-2"
|
| 93 |
+
onclick="startTest()">
|
| 94 |
+
Iniciar técnica
|
| 95 |
+
<figure class="w-10">
|
| 96 |
+
<img src="{% static 'img/check.svg' %}" alt="flechas girando" class="invert">
|
| 97 |
+
</figure>
|
| 98 |
+
</button>
|
| 99 |
+
<button
|
| 100 |
+
class="flex-1 uppercase text-lg tracking-wider p-4 border-b-2 active:border-b-0 active:border-t-2 active:border-red-500 border-red-800 transition-all rounded-xl bg-red-600 text-white font-bold disabled:bg-amber-600 flex flex-col justify-center items-center gap-2">
|
| 101 |
+
Salir se la sesión
|
| 102 |
+
<figure class="w-10">
|
| 103 |
+
<img src="{% static 'img/exit.svg' %}" alt="bote de basura" class="invert">
|
| 104 |
+
</figure>
|
| 105 |
+
</button>
|
| 106 |
+
</article>
|
| 107 |
+
|
| 108 |
+
<form action="" method="post" class="hidden ct-action-form">
|
| 109 |
+
{% csrf_token %}
|
| 110 |
+
<input type="hidden" value="pipo" name="action">
|
| 111 |
+
</form>
|
| 112 |
+
</article>
|
| 113 |
+
</article>
|
| 114 |
+
{% endblock %}
|
| 115 |
+
|
| 116 |
+
{% block extra_js %}
|
| 117 |
+
<script src="{% static 'js/start-tester-test.js' %}"></script>
|
| 118 |
+
{% endblock %}
|
tecnicas/templates/tecnicas/manage_sesions/detalles-sesion.html
CHANGED
|
@@ -26,6 +26,14 @@
|
|
| 26 |
</article>
|
| 27 |
{% endif %}
|
| 28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
<p class="font-bold text-2xl border-b-2">
|
| 30 |
Información general
|
| 31 |
</p>
|
|
@@ -149,6 +157,14 @@
|
|
| 149 |
<img src="{% static 'img/giro.svg' %}" alt="flechas girando" class="invert">
|
| 150 |
</figure>
|
| 151 |
</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
{% endif %}
|
| 153 |
|
| 154 |
<button
|
|
|
|
| 26 |
</article>
|
| 27 |
{% endif %}
|
| 28 |
|
| 29 |
+
{% if message %}
|
| 30 |
+
<article class="bg-green-600 p-4 text-white rounded-xl ct-notification-error">
|
| 31 |
+
<p class="block font-sans text-white text-xl antialiased font-bold uppercase tracking-wider text-center">
|
| 32 |
+
{{ message }}
|
| 33 |
+
</p>
|
| 34 |
+
</article>
|
| 35 |
+
{% endif %}
|
| 36 |
+
|
| 37 |
<p class="font-bold text-2xl border-b-2">
|
| 38 |
Información general
|
| 39 |
</p>
|
|
|
|
| 157 |
<img src="{% static 'img/giro.svg' %}" alt="flechas girando" class="invert">
|
| 158 |
</figure>
|
| 159 |
</button>
|
| 160 |
+
{% else %}
|
| 161 |
+
<button
|
| 162 |
+
class="ct-btn-start-repition flex-1 uppercase text-lg tracking-wider p-4 border-b-2 active:border-b-0 active:border-t-2 active:border-orange-500 border-orange-800 transition-all rounded-xl bg-orange-600 text-white font-bold disabled:bg-amber-600 flex flex-col justify-center items-center gap-2">
|
| 163 |
+
Monitorear repetición
|
| 164 |
+
<figure class="w-10">
|
| 165 |
+
<img src="{% static 'img/monitor.svg' %}" alt="flechas girando" class="invert">
|
| 166 |
+
</figure>
|
| 167 |
+
</button>
|
| 168 |
{% endif %}
|
| 169 |
|
| 170 |
<button
|
tecnicas/urls.py
CHANGED
|
@@ -12,10 +12,6 @@ urlpatterns = [
|
|
| 12 |
views.autentication,
|
| 13 |
name="autenticacion"),
|
| 14 |
|
| 15 |
-
path("catador-login",
|
| 16 |
-
views.catadorLogin,
|
| 17 |
-
name="catador_login"),
|
| 18 |
-
|
| 19 |
|
| 20 |
# Gestion de catadores
|
| 21 |
path("panel-catadores",
|
|
@@ -67,6 +63,15 @@ urlpatterns = [
|
|
| 67 |
name="detalles_sesion"),
|
| 68 |
|
| 69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
# APIs
|
| 71 |
path("nueva-etiqueta",
|
| 72 |
views.newTag,
|
|
|
|
| 12 |
views.autentication,
|
| 13 |
name="autenticacion"),
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
# Gestion de catadores
|
| 17 |
path("panel-catadores",
|
|
|
|
| 63 |
name="detalles_sesion"),
|
| 64 |
|
| 65 |
|
| 66 |
+
# Vistas para catadores
|
| 67 |
+
path("catador-login",
|
| 68 |
+
views.testerLogin,
|
| 69 |
+
name="catador_login"),
|
| 70 |
+
|
| 71 |
+
path("testers/catador-main",
|
| 72 |
+
views.mainTesterForm,
|
| 73 |
+
name="catador_main"),
|
| 74 |
+
|
| 75 |
# APIs
|
| 76 |
path("nueva-etiqueta",
|
| 77 |
views.newTag,
|
tecnicas/utils/__init__.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
| 1 |
from .code_generate import generarCodigo
|
| 2 |
from .code_generate import generarCodigos
|
| 3 |
from .personal_errors import general_error, controller_error
|
|
|
|
|
|
| 1 |
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
|
tecnicas/utils/shuffle_arrays.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import random
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def shuffleArray(obj_list: list):
|
| 5 |
+
new_obj_list = obj_list[:]
|
| 6 |
+
random.shuffle(new_obj_list)
|
| 7 |
+
return new_obj_list
|
tecnicas/views/__init__.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
from .autentication import autentication
|
| 2 |
-
from .
|
| 3 |
from .main_panel import mainPanel
|
| 4 |
|
| 5 |
from .sessions_management.sessions_panel import sesionsPanel
|
|
@@ -18,3 +18,5 @@ from .tester_management.tester_search import testerSearch
|
|
| 18 |
|
| 19 |
from .apis.api_tag import newTag
|
| 20 |
from .apis.api_words import words
|
|
|
|
|
|
|
|
|
| 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
|
|
|
|
| 18 |
|
| 19 |
from .apis.api_tag import newTag
|
| 20 |
from .apis.api_words import words
|
| 21 |
+
|
| 22 |
+
from .tester_forms.main_tester_form import mainTesterForm
|
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,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
+
from django.shortcuts import render, redirect
|
| 3 |
+
from django.urls import reverse
|
| 4 |
+
from ..utils import general_error
|
| 5 |
+
from ..controllers import LoginTesterController
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def testerLogin(req: HttpRequest):
|
| 9 |
+
if req.method == "GET":
|
| 10 |
+
return render(req, "tecnicas/cata-login.html")
|
| 11 |
+
elif req.method == "POST":
|
| 12 |
+
tester_user = req.POST.get("user_tester")
|
| 13 |
+
session_code = req.POST.get("code_session")
|
| 14 |
+
if not tester_user or not session_code:
|
| 15 |
+
return general_error("Se esperan credenciales")
|
| 16 |
+
|
| 17 |
+
login_controller = LoginTesterController()
|
| 18 |
+
|
| 19 |
+
existCredentials = login_controller.existCredential(
|
| 20 |
+
tester_user, session_code)
|
| 21 |
+
if isinstance(existCredentials, dict):
|
| 22 |
+
context = {"error": existCredentials["error"]}
|
| 23 |
+
return render(req, "tecnicas/cata-login.html", context)
|
| 24 |
+
|
| 25 |
+
taster_participation = login_controller.validateEntry()
|
| 26 |
+
if isinstance(taster_participation, dict):
|
| 27 |
+
context = {"error": taster_participation["error"]}
|
| 28 |
+
return render(req, "tecnicas/cata-login.html", context)
|
| 29 |
+
|
| 30 |
+
req.session["cata_username"] = tester_user
|
| 31 |
+
req.session["code_session"] = session_code
|
| 32 |
+
|
| 33 |
+
req.session.set_expiry(20*60)
|
| 34 |
+
return redirect(reverse("cata_system:catador_main"))
|
| 35 |
+
else:
|
| 36 |
+
return render(req, "tecnicas/cata-login.html")
|
tecnicas/views/sessions_management/session_details.py
CHANGED
|
@@ -12,12 +12,12 @@ def sessionDetails(req: HttpRequest, session_code: str):
|
|
| 12 |
elif req.method == "POST":
|
| 13 |
if req.POST["action"] == "start_session":
|
| 14 |
response = DetallesSesionController.startRepetition(
|
| 15 |
-
session_code, req.POST
|
| 16 |
if isinstance(response, dict):
|
| 17 |
context["error"] = response["error"]
|
| 18 |
return render(req, "tecnicas/manage_sesions/detalles-sesion.html", context)
|
| 19 |
-
|
| 20 |
-
return
|
| 21 |
elif req.POST.get("action") == "delete_session":
|
| 22 |
pass
|
| 23 |
elif req.POST.get("action") == "monitor_session":
|
|
|
|
| 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":
|
tecnicas/views/tester_forms/main_tester_form.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest, JsonResponse
|
| 2 |
+
from django.shortcuts import render
|
| 3 |
+
from ...controllers import SesionController, MainTesterFormController
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def mainTesterForm(req: HttpRequest):
|
| 7 |
+
session = SesionController.getSessionByCodePanelTester(
|
| 8 |
+
req.session["code_session"])
|
| 9 |
+
|
| 10 |
+
context = {
|
| 11 |
+
"session": session
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
if req.method == "GET":
|
| 15 |
+
return render(req, "tecnicas/forms_tester/main_tester.html", context)
|
| 16 |
+
elif req.method == "POST":
|
| 17 |
+
if req.POST["action"] == "start_posting":
|
| 18 |
+
view_controller = MainTesterFormController(
|
| 19 |
+
req.session["code_session"], req.session["cata_username"])
|
| 20 |
+
|
| 21 |
+
order = view_controller.assignOrder()
|
| 22 |
+
if isinstance(order, dict):
|
| 23 |
+
context["error"] = order["error"]
|
| 24 |
+
return render(req, "tecnicas/forms_tester/main_tester.html", context)
|
| 25 |
+
|
| 26 |
+
return render(req, "tecnicas/forms_tester/main_tester.html", context)
|
| 27 |
+
elif req.POST["action"] == "close_session":
|
| 28 |
+
pass
|
| 29 |
+
else:
|
| 30 |
+
context["error"] = "Acción sin especificar"
|
| 31 |
+
return render(req, "tecnicas/forms_tester/main_tester.html", context)
|
| 32 |
+
else:
|
| 33 |
+
return JsonResponse({"error": "metodo no permitido"})
|