Spaces:
Sleeping
Sleeping
Se implementa la fase 2 de sesiones con PF
Browse files- tecnicas/controllers/api_controller/rating_pf_list_controller.py +82 -32
- tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_pf_controller.py +1 -0
- tecnicas/static/js/lists-words-testers.js +103 -0
- tecnicas/static/js/pf-make-list.js +9 -1
- tecnicas/templates/tecnicas/forms_tester/test_pf_list_words.html +30 -1
- tecnicas/views/apis/api_list_words_pf.py +3 -1
tecnicas/controllers/api_controller/rating_pf_list_controller.py
CHANGED
|
@@ -8,6 +8,57 @@ class RatingPFListController():
|
|
| 8 |
def __init__(self):
|
| 9 |
pass
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
@staticmethod
|
| 12 |
def saveList(request: HttpRequest, words: list, current_phase: int):
|
| 13 |
dic_words = {}
|
|
@@ -39,7 +90,7 @@ class RatingPFListController():
|
|
| 39 |
es_final=True,
|
| 40 |
)
|
| 41 |
|
| 42 |
-
added_words = addWordsToListWordsTester(
|
| 43 |
list_words=words, list_tester=list_words_tester)
|
| 44 |
|
| 45 |
response = JsonResponse({
|
|
@@ -51,43 +102,42 @@ class RatingPFListController():
|
|
| 51 |
|
| 52 |
return response
|
| 53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
# Normalizar
|
| 58 |
-
clean_words = [s.strip() for s in list_words if s.strip()]
|
| 59 |
-
|
| 60 |
-
# Obtener existentes
|
| 61 |
-
all_words = Palabra.objects.filter(nombre_palabra__in=clean_words)
|
| 62 |
|
| 63 |
-
|
| 64 |
-
|
| 65 |
|
| 66 |
-
|
| 67 |
-
|
| 68 |
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
|
| 74 |
-
|
| 75 |
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
|
| 88 |
-
|
| 89 |
-
|
| 90 |
|
| 91 |
-
|
| 92 |
|
| 93 |
-
|
|
|
|
| 8 |
def __init__(self):
|
| 9 |
pass
|
| 10 |
|
| 11 |
+
@staticmethod
|
| 12 |
+
def getListWords(request: HttpRequest):
|
| 13 |
+
participation_current_tester = Participacion.objects.get(
|
| 14 |
+
id=request.session["id_participation"])
|
| 15 |
+
|
| 16 |
+
technique = participation_current_tester.tecnica
|
| 17 |
+
|
| 18 |
+
participations_testers = Participacion.objects.exclude(
|
| 19 |
+
catador=participation_current_tester.catador).filter(tecnica=technique)
|
| 20 |
+
|
| 21 |
+
all_testers = [
|
| 22 |
+
participation.catador for participation in participations_testers]
|
| 23 |
+
|
| 24 |
+
list_words_testers = list(ListaPalabras.objects.filter(
|
| 25 |
+
tecnica=technique, catador__in=all_testers, es_final=True))
|
| 26 |
+
|
| 27 |
+
if not list_words_testers:
|
| 28 |
+
return JsonResponse({"error": "Aun no hay listas finales de Catadores"})
|
| 29 |
+
|
| 30 |
+
result = []
|
| 31 |
+
for list_tester in list_words_testers:
|
| 32 |
+
try:
|
| 33 |
+
username = list_tester.catador.user.username
|
| 34 |
+
except Exception:
|
| 35 |
+
username = None
|
| 36 |
+
|
| 37 |
+
finish = [
|
| 38 |
+
participation.finalizado for participation in participations_testers if participation.catador.user.username == username][0]
|
| 39 |
+
|
| 40 |
+
status = "Lista terminada" if finish else "Lista en proceso"
|
| 41 |
+
|
| 42 |
+
words_qs = list_tester.palabras.all()
|
| 43 |
+
words = []
|
| 44 |
+
for p in words_qs:
|
| 45 |
+
nombre = getattr(p, 'nombre_palabra', None)
|
| 46 |
+
words.append({
|
| 47 |
+
'id': getattr(p, 'id', None),
|
| 48 |
+
'nombre_palabra': nombre
|
| 49 |
+
})
|
| 50 |
+
|
| 51 |
+
result.append({
|
| 52 |
+
'username': username,
|
| 53 |
+
'words': words,
|
| 54 |
+
'status': status
|
| 55 |
+
})
|
| 56 |
+
|
| 57 |
+
return JsonResponse({
|
| 58 |
+
"message": "Listas encontradas",
|
| 59 |
+
"lists_words": result
|
| 60 |
+
})
|
| 61 |
+
|
| 62 |
@staticmethod
|
| 63 |
def saveList(request: HttpRequest, words: list, current_phase: int):
|
| 64 |
dic_words = {}
|
|
|
|
| 90 |
es_final=True,
|
| 91 |
)
|
| 92 |
|
| 93 |
+
added_words = RatingPFListController.addWordsToListWordsTester(
|
| 94 |
list_words=words, list_tester=list_words_tester)
|
| 95 |
|
| 96 |
response = JsonResponse({
|
|
|
|
| 102 |
|
| 103 |
return response
|
| 104 |
|
| 105 |
+
@staticmethod
|
| 106 |
+
def addWordsToListWordsTester(list_words: list[str], list_tester: ListaPalabras):
|
| 107 |
+
# Normalizar
|
| 108 |
+
clean_words = [s.strip() for s in list_words if s.strip()]
|
| 109 |
|
| 110 |
+
# Obtener existentes
|
| 111 |
+
all_words = Palabra.objects.filter(nombre_palabra__in=clean_words)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
|
| 113 |
+
names_words_exist = set(
|
| 114 |
+
all_words.values_list('nombre_palabra', flat=True))
|
| 115 |
|
| 116 |
+
# Ejecutar el query para no sumar palabras repetidas
|
| 117 |
+
all_words = list(all_words)
|
| 118 |
|
| 119 |
+
# Determinar faltantes
|
| 120 |
+
missing_words = [
|
| 121 |
+
nombre for nombre in clean_words if nombre not in names_words_exist]
|
| 122 |
+
print("No save words", missing_words)
|
| 123 |
|
| 124 |
+
created_words = []
|
| 125 |
|
| 126 |
+
# Intentar crear missing_words
|
| 127 |
+
for nombre in missing_words:
|
| 128 |
+
try:
|
| 129 |
+
with transaction.atomic():
|
| 130 |
+
palabra, created = Palabra.objects.get_or_create(
|
| 131 |
+
nombre_palabra=nombre)
|
| 132 |
+
if created:
|
| 133 |
+
created_words.append(palabra)
|
| 134 |
+
except IntegrityError:
|
| 135 |
+
palabra = Palabra.objects.get(nombre_palabra=nombre)
|
| 136 |
+
created_words.append(palabra)
|
| 137 |
|
| 138 |
+
# Combinar todas (all_words + created_words)
|
| 139 |
+
all_new_words = all_words + created_words
|
| 140 |
|
| 141 |
+
list_tester.palabras.set(all_new_words)
|
| 142 |
|
| 143 |
+
return all_new_words
|
tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_pf_controller.py
CHANGED
|
@@ -25,6 +25,7 @@ class TestPFController(GenetalTestController):
|
|
| 25 |
self.current_directory = "tecnicas/forms_tester/test_pf_list_words.html"
|
| 26 |
response = self.getFirstPhase(request)
|
| 27 |
elif rep == 2:
|
|
|
|
| 28 |
response = self.getSecondPhase(request)
|
| 29 |
elif rep >= 3:
|
| 30 |
response = self.getRepetitionPhase(request)
|
|
|
|
| 25 |
self.current_directory = "tecnicas/forms_tester/test_pf_list_words.html"
|
| 26 |
response = self.getFirstPhase(request)
|
| 27 |
elif rep == 2:
|
| 28 |
+
self.current_directory = "tecnicas/forms_tester/test_pf_list_words.html"
|
| 29 |
response = self.getSecondPhase(request)
|
| 30 |
elif rep >= 3:
|
| 31 |
response = self.getRepetitionPhase(request)
|
tecnicas/static/js/lists-words-testers.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
async function getListWordsTesters() {
|
| 2 |
+
const URL = "/cata/testers/api/ratingword/pf/list";
|
| 3 |
+
try {
|
| 4 |
+
const response = await fetch(URL, {
|
| 5 |
+
method: "GET",
|
| 6 |
+
});
|
| 7 |
+
|
| 8 |
+
if (!response.ok) {
|
| 9 |
+
spanNotifaction("Fallo con la respuesta recibida");
|
| 10 |
+
return false;
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
const result = await response.json();
|
| 14 |
+
const messError = result.error;
|
| 15 |
+
if (messError) {
|
| 16 |
+
spanNotifaction(messError);
|
| 17 |
+
const containerWords = document.querySelector(".cts-content-list-words");
|
| 18 |
+
containerWords.innerHTML = `
|
| 19 |
+
<p class="bg-surface-sweet font-bold text-center text-lg px-4 pt-2 pb-3 rounded w-full max-sm:mx-2">
|
| 20 |
+
${messError}
|
| 21 |
+
</p>`;
|
| 22 |
+
return false;
|
| 23 |
+
}
|
| 24 |
+
spanNotifaction(result.message, false);
|
| 25 |
+
const containerWords = document.querySelector(".cts-content-list-words");
|
| 26 |
+
containerWords.innerHTML = "";
|
| 27 |
+
|
| 28 |
+
const listWordsTesters = result.lists_words;
|
| 29 |
+
|
| 30 |
+
listWordsTesters.forEach((listTester) => {
|
| 31 |
+
const username = listTester.username;
|
| 32 |
+
const words = listTester.words;
|
| 33 |
+
const status = listTester.status;
|
| 34 |
+
const listDiv = createListWords(username, words, status);
|
| 35 |
+
containerWords.appendChild(listDiv);
|
| 36 |
+
});
|
| 37 |
+
|
| 38 |
+
return true;
|
| 39 |
+
} catch (error) {
|
| 40 |
+
console.error(error);
|
| 41 |
+
spanNotifaction("Error del servidor con la API");
|
| 42 |
+
return false;
|
| 43 |
+
}
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
function createListWords(username, words, status = "indefinido") {
|
| 47 |
+
const div = document.createElement("div");
|
| 48 |
+
const paragraph = document.createElement("p");
|
| 49 |
+
const paragraphStatus = document.createElement("p");
|
| 50 |
+
const ul = document.createElement("ul");
|
| 51 |
+
|
| 52 |
+
div.classList.add(
|
| 53 |
+
"cts-item-list-tester",
|
| 54 |
+
"bg-surface-sweet",
|
| 55 |
+
"px-4",
|
| 56 |
+
"pt-2",
|
| 57 |
+
"pb-3",
|
| 58 |
+
"rounded",
|
| 59 |
+
"shrink-0",
|
| 60 |
+
"w-64",
|
| 61 |
+
"space-y-2"
|
| 62 |
+
);
|
| 63 |
+
|
| 64 |
+
paragraph.classList.add(
|
| 65 |
+
"bg-surface-card",
|
| 66 |
+
"text-lg",
|
| 67 |
+
"font-semibold",
|
| 68 |
+
"text-center",
|
| 69 |
+
"rounded"
|
| 70 |
+
);
|
| 71 |
+
|
| 72 |
+
paragraphStatus.classList.add(
|
| 73 |
+
"bg-surface-card",
|
| 74 |
+
"text-lg",
|
| 75 |
+
"font-semibold",
|
| 76 |
+
"text-center",
|
| 77 |
+
"rounded"
|
| 78 |
+
);
|
| 79 |
+
|
| 80 |
+
paragraph.textContent = username;
|
| 81 |
+
paragraphStatus.textContent = status;
|
| 82 |
+
|
| 83 |
+
ul.classList.add("text-center", "grid", "grid-cols-2", "gap-2", "w-full");
|
| 84 |
+
|
| 85 |
+
words.forEach((word) => {
|
| 86 |
+
const li = document.createElement("li");
|
| 87 |
+
li.classList.add(
|
| 88 |
+
"bg-surface-ligt",
|
| 89 |
+
"rounded",
|
| 90 |
+
"font-bold",
|
| 91 |
+
"py-1",
|
| 92 |
+
"px-2",
|
| 93 |
+
"truncate"
|
| 94 |
+
);
|
| 95 |
+
li.textContent = word.nombre_palabra;
|
| 96 |
+
ul.appendChild(li);
|
| 97 |
+
});
|
| 98 |
+
|
| 99 |
+
div.appendChild(paragraph);
|
| 100 |
+
div.appendChild(paragraphStatus);
|
| 101 |
+
div.appendChild(ul);
|
| 102 |
+
return div;
|
| 103 |
+
}
|
tecnicas/static/js/pf-make-list.js
CHANGED
|
@@ -213,7 +213,15 @@ async function setUpFormAction() {
|
|
| 213 |
FORM_ACTION.submit();
|
| 214 |
}
|
| 215 |
|
| 216 |
-
window.addEventListener("DOMContentLoaded", () => {
|
| 217 |
initWordsFromBox();
|
| 218 |
setupDescribeFormToAddWord();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 219 |
});
|
|
|
|
| 213 |
FORM_ACTION.submit();
|
| 214 |
}
|
| 215 |
|
| 216 |
+
window.addEventListener("DOMContentLoaded", async () => {
|
| 217 |
initWordsFromBox();
|
| 218 |
setupDescribeFormToAddWord();
|
| 219 |
+
|
| 220 |
+
const currentPhase = parseInt(
|
| 221 |
+
document.querySelector(".cts-phase-pf").dataset.phase
|
| 222 |
+
);
|
| 223 |
+
|
| 224 |
+
if (currentPhase == 2) await sendWordsToSave();
|
| 225 |
+
if (document.querySelector(".cts-content-list-words"))
|
| 226 |
+
await getListWordsTesters();
|
| 227 |
});
|
tecnicas/templates/tecnicas/forms_tester/test_pf_list_words.html
CHANGED
|
@@ -32,6 +32,19 @@
|
|
| 32 |
{% if error %}
|
| 33 |
{% include "../components/error-message.html" with message=error %}
|
| 34 |
{% endif %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
<article class="rounded flex flex-col gap-4">
|
| 37 |
<section class="flex items-center justify-center bg-surface-ligt p-2 rounded-lg">
|
|
@@ -120,7 +133,7 @@
|
|
| 120 |
Guardar y comprobar palabras actuales
|
| 121 |
</button>
|
| 122 |
|
| 123 |
-
<button type="button" class="cts-btn-general
|
| 124 |
onclick="setUpFormAction()">
|
| 125 |
Finalizar la sesión
|
| 126 |
</button>
|
|
@@ -144,6 +157,22 @@
|
|
| 144 |
</div>
|
| 145 |
</div>
|
| 146 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
</article>
|
| 148 |
</article>
|
| 149 |
{% endblock %}
|
|
|
|
| 32 |
{% if error %}
|
| 33 |
{% include "../components/error-message.html" with message=error %}
|
| 34 |
{% endif %}
|
| 35 |
+
{% if not initial_phase %}
|
| 36 |
+
<div role="alert" class="alert alert-info">
|
| 37 |
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
| 38 |
+
class="h-6 w-6 shrink-0 stroke-current">
|
| 39 |
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
| 40 |
+
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
| 41 |
+
</svg>
|
| 42 |
+
<span class="text-lg">
|
| 43 |
+
Para poder compartir tu nueva lista de palabras con los demás Catadores, debes usar el botón de
|
| 44 |
+
<b>“Guardar y comprobar palabras actuales”</b>
|
| 45 |
+
</span>
|
| 46 |
+
</div>
|
| 47 |
+
{% endif %}
|
| 48 |
|
| 49 |
<article class="rounded flex flex-col gap-4">
|
| 50 |
<section class="flex items-center justify-center bg-surface-ligt p-2 rounded-lg">
|
|
|
|
| 133 |
Guardar y comprobar palabras actuales
|
| 134 |
</button>
|
| 135 |
|
| 136 |
+
<button type="button" class="cts-btn-general cts-btn-secondary btn-push py-2 px-4 flex-1"
|
| 137 |
onclick="setUpFormAction()">
|
| 138 |
Finalizar la sesión
|
| 139 |
</button>
|
|
|
|
| 157 |
</div>
|
| 158 |
</div>
|
| 159 |
|
| 160 |
+
{% if not initial_phase %}
|
| 161 |
+
<section class="space-y-4">
|
| 162 |
+
<section class="flex items-center justify-center flex-wrap gap-4 bg-surface-ligt p-2 rounded-lg">
|
| 163 |
+
<h3 class="text-xl font-bold text-center">
|
| 164 |
+
Listas de los demás participantes
|
| 165 |
+
</h3>
|
| 166 |
+
</section>
|
| 167 |
+
<article class="cts-content-list-words bg-surface-card flex gap-4 overflow-x-auto p-2"></article>
|
| 168 |
+
<article class="flex justify-center">
|
| 169 |
+
<button class="cts-btn-general cts-btn-primary btn-push" onclick="getListWordsTesters()">
|
| 170 |
+
Actualizar las listas
|
| 171 |
+
</button>
|
| 172 |
+
</article>
|
| 173 |
+
</section>
|
| 174 |
+
<script src="{% static 'js/lists-words-testers.js' %}"></script>
|
| 175 |
+
{% endif %}
|
| 176 |
</article>
|
| 177 |
</article>
|
| 178 |
{% endblock %}
|
tecnicas/views/apis/api_list_words_pf.py
CHANGED
|
@@ -5,7 +5,9 @@ import json
|
|
| 5 |
|
| 6 |
|
| 7 |
def apiListWordsPF(req: HttpRequest):
|
| 8 |
-
if req.method == "
|
|
|
|
|
|
|
| 9 |
try:
|
| 10 |
data = json.loads(req.body.decode("utf-8"))
|
| 11 |
raw_words = data.get("words", [])
|
|
|
|
| 5 |
|
| 6 |
|
| 7 |
def apiListWordsPF(req: HttpRequest):
|
| 8 |
+
if req.method == "GET":
|
| 9 |
+
return RatingPFListController.getListWords(request=req)
|
| 10 |
+
elif req.method == "POST":
|
| 11 |
try:
|
| 12 |
data = json.loads(req.body.decode("utf-8"))
|
| 13 |
raw_words = data.get("words", [])
|