Ultron/ultron/people/views.py

511 lines
17 KiB
Python
Raw Normal View History

2022-01-07 18:08:39 +01:00
2021-12-09 16:53:44 +01:00
from django.contrib.auth.decorators import login_required
2022-02-06 15:44:55 +01:00
from django.contrib.auth.models import Group
from django.contrib.auth import get_user_model
User = get_user_model()
from django.db.models import Q, F, Avg
from django.db.models.functions import TruncDay
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
2022-01-07 18:08:39 +01:00
from django.shortcuts import render, get_object_or_404
from django.views.decorators.http import require_http_methods
2022-02-01 11:08:02 +01:00
from django.urls import reverse
2022-01-07 18:08:39 +01:00
2022-02-06 15:44:55 +01:00
2022-01-07 18:08:39 +01:00
import pendulum
from datetime import date
2021-12-09 16:53:44 +01:00
from ultron.followup.models import Event
from ultron.followup.forms import GymnastHasRoutineForm
2021-12-19 09:30:51 +01:00
from ultron.followup.models import (
2022-09-30 10:17:43 +02:00
Note,
2021-12-19 09:30:51 +01:00
Skill,
Point,
2022-09-30 10:17:43 +02:00
Chrono,
2021-12-19 09:30:51 +01:00
Accident,
2022-09-30 10:17:43 +02:00
MindState,
LearnedSkill,
2021-12-19 09:30:51 +01:00
HeightWeight,
NumberOfRoutineDone,
2021-12-19 09:30:51 +01:00
)
2021-12-09 16:53:44 +01:00
from ultron.tools.pdf_generator import GymnastReportDocument
2022-01-07 18:08:39 +01:00
from .models import Gymnast
2022-02-06 15:44:55 +01:00
from .forms import GymnastForm, UserForm
2021-12-09 16:53:44 +01:00
@login_required
2022-02-11 16:06:46 +01:00
@require_http_methods(["POST"])
2021-12-09 16:53:44 +01:00
def gymnast_lookup(request):
"""
Récupère la liste des gymnastes à la volée suivant des caractères de
recherche entrés. (min 3 caractères)
"""
results = []
2022-02-11 16:06:46 +01:00
pattern = request.POST.get("pattern", None)
2021-12-09 16:53:44 +01:00
if pattern is not None and len(pattern) > 3:
model_results = Gymnast.objects.filter(
Q(last_name__icontains=pattern) | Q(first_name__icontains=pattern)
)
results = [{"ID": x.id, "Name": str(x)} for x in model_results]
return JsonResponse(results, safe=False)
2021-12-09 16:53:44 +01:00
@login_required
@require_http_methods(["GET"])
def gymnast_listing(request):
"""
Si la personne connectée est un entraîneur : liste tous les gymnasts connus.
Si la personne connectée est un gymnaste : renvoie sa fiche détaillée.
2021-12-09 16:53:44 +01:00
"""
2022-09-04 16:00:38 +02:00
if request.user.groups.filter(name='trainer').exists():
gymnast_list = Gymnast.objects.all()
context = {"gymnast_list": gymnast_list}
return render(request, "people/gymnasts/list.html", context)
else:
gymnast = Gymnast.objects.get(user=request.user)
return gymnast_details(request, gymnast.id)
2021-12-09 16:53:44 +01:00
@login_required
@require_http_methods(["GET"])
def gymnast_details(request, gymnast_id, tab=None):
2021-12-09 16:53:44 +01:00
"""
Récupère toutes les informations d'un gymnaste si la personne connectée est un "trainer".
Si la personne connectée est un gymnaste : renvoie sa fiche détaillée.
2021-12-09 16:53:44 +01:00
"""
if request.user.groups.filter(name='trainer').exists():
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
else:
gymnast = Gymnast.objects.get(user=request.user)
2021-12-19 09:30:51 +01:00
gymnast_nb_known_skills = gymnast.known_skills.distinct(
"skill"
).count() # devrait disparaitre
2021-12-09 16:53:44 +01:00
nb_skill = Skill.objects.all().count()
2021-12-19 09:30:51 +01:00
nb_known_skill = (
LearnedSkill.objects.filter(gymnast=gymnast_id).distinct("skill").count()
)
2022-01-18 09:35:37 +01:00
if nb_skill != 0:
percentage_known_skill = (nb_known_skill / nb_skill) * 100
else:
percentage_known_skill = 0
2022-02-01 18:39:59 +01:00
# base_queryset = Chrono.objects.filter(gymnast=gymnast_id).order_by("-date")
2021-12-19 09:30:51 +01:00
chronos_list = Chrono.objects.filter(gymnast=gymnast_id).order_by("-date")[:10]
straightjump_score = (
2022-01-07 18:08:39 +01:00
Chrono.objects.filter(gymnast=gymnast_id)
.filter(chrono_type=0)
.order_by("-date")
2021-12-19 09:30:51 +01:00
)
best_straightjump = (
2022-01-07 18:08:39 +01:00
Chrono.objects.filter(gymnast=gymnast_id)
.filter(chrono_type=0)
.order_by("-score")[:1]
2021-12-19 09:30:51 +01:00
)
best_routine = (
2022-01-07 18:08:39 +01:00
Chrono.objects.filter(gymnast=gymnast_id)
.filter(chrono_type=1)
.order_by("-score")[:1]
2021-12-19 09:30:51 +01:00
)
2021-12-13 11:26:44 +01:00
context = {
"gymnast": gymnast,
"gymnast_nb_known_skills": gymnast_nb_known_skills,
"chronos_list": chronos_list,
"straightjump_score": straightjump_score,
"best_routine": best_routine,
"best_straightjump": best_straightjump,
"nb_skill": nb_skill,
"nb_known_skill": nb_known_skill,
"percentage_known_skill": percentage_known_skill,
"tab": tab,
}
2022-09-04 16:42:21 +02:00
context["user_is_trainer"] = request.user.groups.filter(name="trainer").exists() # TODO: utiliser les {{ perms }}
return render(request, "people/gymnasts/details.html", context)
2021-12-09 16:53:44 +01:00
@login_required
@require_http_methods(["GET"])
def preview_gymnast_report(request, gymnast_id):
"""Génère la preview pour le rapport"""
if request.user.groups.filter(name='trainer').exists():
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
else:
gymnast = Gymnast.objects.get(user=request.user)
gymnast_nb_known_skills = gymnast.known_skills.distinct(
"skill"
).count() # devrait disparaitre
nb_skill = Skill.objects.all().count()
nb_known_skill = (
LearnedSkill.objects.filter(gymnast=gymnast_id).distinct("skill").count()
)
if nb_skill != 0:
percentage_known_skill = (nb_known_skill / nb_skill) * 100
else:
percentage_known_skill = 0
# base_queryset = Chrono.objects.filter(gymnast=gymnast_id).order_by("-date")
chronos_list = Chrono.objects.filter(gymnast=gymnast_id).order_by("-date")[:10]
straightjump_score = (
Chrono.objects.filter(gymnast=gymnast_id)
.filter(chrono_type=0)
.order_by("-date")
)
best_straightjump = (
Chrono.objects.filter(gymnast=gymnast_id)
.filter(chrono_type=0)
.order_by("-score")[:1]
)
best_tof_routine_1 = (
Chrono.objects.filter(gymnast=gymnast_id)
.filter(chrono_type=1)
.order_by("-score")[:1]
)
best_tof_routine_2 = (
Chrono.objects.filter(gymnast=gymnast_id)
.filter(chrono_type=2)
.order_by("-score")[:1]
)
context = {
"gymnast": gymnast,
"gymnast_nb_known_skills": gymnast_nb_known_skills,
"chronos_list": chronos_list,
"straightjump_score": straightjump_score,
"best_tof_routine_1": best_tof_routine_1,
"best_tof_routine_2": best_tof_routine_2,
"best_straightjump": best_straightjump,
"nb_skill": nb_skill,
"nb_known_skill": nb_known_skill,
"percentage_known_skill": percentage_known_skill,
}
context["user_is_trainer"] = request.user.groups.filter(name="trainer").exists() # TODO: utiliser les {{ perms }}
return render(request, "people/gymnasts/report.html", context)
@login_required
@require_http_methods(["GET"])
def generate_gymnast_report(request, gymnast_id):
""" Génère un fichier PDF suivant contenant les informations du gymnast
Args:
gymnast_id (int): gymnast
Returns:
???
"""
if request.user.groups.filter(name='trainer').exists():
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
else:
gymnast = Gymnast.objects.get(user=request.user)
response = HttpResponse(content_type="application/pdf")
response["Content-Disposition"] = (
'attachment; filename="report_' + gymnast.first_name + '_' + gymnast.last_name + '.pdf"'
)
document = GymnastReportDocument(response)
document.generate(gymnast_id)
document.download()
return response
2021-12-09 16:53:44 +01:00
@login_required
@require_http_methods(["GET"])
2022-09-30 10:17:43 +02:00
def gymnast_display_events_and_notes(request, gymnast_id):
2021-12-09 16:53:44 +01:00
"""
Renvoie deux listes d'évènements : ceux à venir et ceux passés.
"""
today = pendulum.now().date()
next_event_list = Event.objects.filter(gymnasts=gymnast_id, date_begin__gte=today)
2021-12-19 09:30:51 +01:00
previous_event_list = Event.objects.filter(
gymnasts=gymnast_id, date_begin__lte=today
2021-12-19 09:30:51 +01:00
)
2021-12-09 16:53:44 +01:00
2022-10-07 09:31:56 +02:00
base_queryset = Note.objects.filter(gymnast=gymnast_id)
if not request.user.groups.filter(name='trainer').exists():
notes_list = base_queryset.filter(status=1)
else:
notes_list = base_queryset
notes_list = notes_list.order_by('-created_at')
2022-10-03 15:16:11 +02:00
last_notes_list = notes_list[:5]
2022-10-07 09:31:56 +02:00
latest_published_note = base_queryset.filter(status=1).order_by('-created_at').first()
2022-09-30 10:17:43 +02:00
2021-12-09 16:53:44 +01:00
context = {
"next_event_list": next_event_list,
"previous_event_list": previous_event_list,
2022-09-30 10:17:43 +02:00
"last_notes_list": last_notes_list,
2022-10-07 09:31:56 +02:00
"latest_published_note": latest_published_note,
2022-09-30 10:17:43 +02:00
"gymnast_id": gymnast_id,
2021-12-09 16:53:44 +01:00
}
return render(request, "people/gymnasts/tab_events_and_notes.html", context)
2021-12-09 16:53:44 +01:00
@login_required
@require_http_methods(["GET"])
2021-12-18 22:40:15 +01:00
def gymnast_display_accident(request, gymnast_id):
2021-12-09 16:53:44 +01:00
"""
Renvoie deux listes d'évènements : ceux à venir et ceux passés.
"""
2021-12-18 22:40:15 +01:00
accident_list = Accident.objects.filter(gymnast=gymnast_id)
2021-12-19 09:30:51 +01:00
context = {"accident_list": accident_list, "gymnast_id": gymnast_id}
return render(request, "people/gymnasts/list_accident.html", context)
2021-12-09 16:53:44 +01:00
2021-12-13 15:51:07 +01:00
@login_required
@require_http_methods(["GET"])
def gymnast_display_physiological(request, gymnast_id):
2021-12-13 15:51:07 +01:00
"""
Renvoie les listes des tailles/poids, état d'esprit et accidents.
"""
2021-12-29 14:40:34 +01:00
accident_list = Accident.objects.filter(gymnast=gymnast_id).order_by("date")
mindstate_list = MindState.objects.filter(gymnast=gymnast_id).order_by("date")
2021-12-19 09:30:51 +01:00
height_weight_list = HeightWeight.objects.filter(gymnast=gymnast_id).order_by(
2021-12-29 14:40:34 +01:00
"date"
2021-12-19 09:30:51 +01:00
)
2021-12-13 15:51:07 +01:00
context = {
2021-12-19 09:30:51 +01:00
"accident_list": accident_list,
"mindstate_list": mindstate_list,
"height_weight_list": height_weight_list,
"gymnast_id": gymnast_id,
2021-12-13 15:51:07 +01:00
}
return render(request, "people/gymnasts/tab_physiological.html", context)
2021-12-13 15:51:07 +01:00
2021-12-09 16:53:44 +01:00
@login_required
@require_http_methods(["GET"])
2021-12-18 22:40:15 +01:00
def gymnast_display_scores_chrono(request, gymnast_id):
2021-12-09 16:53:44 +01:00
"""
Selectionne tous les scores réalisés par le gymnaste
Afin de ne pas avoir plusieurs valeurs pour une même date, nous faisons une
moyenne par date.
2021-12-09 16:53:44 +01:00
"""
score_list = Point.objects.filter(gymnast=gymnast_id).order_by("-event__date_begin")
2022-02-01 18:39:59 +01:00
chrono_list = Chrono.objects.filter(gymnast=gymnast_id).order_by("date")
2022-02-22 09:30:39 +01:00
base_queryset = chrono_list.values('date').annotate(score_avg=Avg('tof'))
2021-12-09 16:53:44 +01:00
context = {
2021-12-09 16:53:44 +01:00
"score_list": score_list,
2022-02-01 18:39:59 +01:00
"score_routine1_list": score_list.filter(routine_type=1),
"score_routine2_list": score_list.filter(routine_type=2),
"score_routine3_list": score_list.filter(routine_type=3),
2021-12-09 16:53:44 +01:00
"chrono_list": chrono_list,
2022-02-01 18:39:59 +01:00
"chrono_10c": base_queryset.filter(chrono_type=0),
"chrono_r1": base_queryset.filter(chrono_type=1),
"chrono_r2": base_queryset.filter(chrono_type=2),
"chrono_rf": base_queryset.filter(chrono_type=3),
2021-12-18 22:40:15 +01:00
"gymnast_id": gymnast_id,
2021-12-09 16:53:44 +01:00
}
2022-10-09 20:44:28 +02:00
return render(request, "people/gymnasts/tab_scores_and_chronos.html", context)
2021-12-09 16:53:44 +01:00
@login_required
@require_http_methods(["GET"])
2021-12-18 22:40:15 +01:00
def gymnast_display_mindstate(request, gymnast_id):
2021-12-09 16:53:44 +01:00
"""
Selectionne tous les scores réalisés par le gymnaste
"""
2021-12-18 22:40:15 +01:00
mindstate_list = MindState.objects.filter(gymnast=gymnast_id).order_by("-date")
2021-12-09 16:53:44 +01:00
context = {
"mindstate_list": mindstate_list,
2021-12-18 22:40:15 +01:00
"gymnast_id": gymnast_id,
2021-12-09 16:53:44 +01:00
}
return render(request, "people/gymnasts/list_mindstate.html", context)
2021-12-09 16:53:44 +01:00
@login_required
@require_http_methods(["GET"])
2021-12-18 22:40:15 +01:00
def gymnast_display_routines(request, gymnast_id):
2021-12-09 16:53:44 +01:00
"""
Tag affichant les séries d'un gymnaste.
"""
2021-12-18 22:40:15 +01:00
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
2022-01-07 18:08:39 +01:00
ghr_list = gymnast.has_routine.prefetch_related("routine").filter(
Q(date_end__gte=date.today()) | Q(date_end__isnull=True)
2022-01-07 18:08:39 +01:00
)
has_routine_1 = ghr_list.filter(routine_type=1)
has_routine_2 = ghr_list.filter(routine_type=2)
2022-01-07 18:08:39 +01:00
routine_done_list = NumberOfRoutineDone.objects.filter(gymnast=gymnast_id).order_by(
"-date"
)[:8]
2022-01-07 18:08:39 +01:00
context = {
"ghr_list": ghr_list,
"has_routine_1": has_routine_1,
"has_routine_2": has_routine_2,
2022-01-07 18:08:39 +01:00
"routine_done_list": routine_done_list,
"gymnast_id": gymnast_id,
}
2022-10-09 20:44:28 +02:00
return render(request, "people/gymnasts/tab_routines_and_routine_stats.html", context)
2021-12-09 16:53:44 +01:00
@login_required
@require_http_methods(["GET", "POST"])
2021-12-18 22:40:15 +01:00
def link_routine_to_gymnast(request, gymnast_id=None):
2021-12-19 09:30:51 +01:00
""" """
2021-12-09 16:53:44 +01:00
2021-12-18 22:40:15 +01:00
if gymnast_id:
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
data = {"gymnast": gymnast_id, "gymnast_related": str(gymnast), "date_end": None}
2021-12-09 16:53:44 +01:00
else:
gymnast = None
data = {"date_end": None}
2021-12-09 16:53:44 +01:00
if request.method == "POST":
form = GymnastHasRoutineForm(request.POST)
if form.is_valid():
form.save()
2021-12-18 22:40:15 +01:00
if gymnast_id is not None:
2022-02-01 11:08:02 +01:00
return HttpResponseRedirect(reverse("gymnast_details", args=(gymnast_id,)))
2021-12-09 16:53:44 +01:00
2022-02-01 11:08:02 +01:00
return HttpResponseRedirect(reverse("gymnast_list"))
2021-12-09 16:53:44 +01:00
else:
form = GymnastHasRoutineForm(instance=gymnast, initial=data)
2021-12-18 22:40:15 +01:00
context = {"form": form, "gymnast_id": gymnast_id}
return render(request, "people/gymnasts/link_to_routine.html", context)
2021-12-09 16:53:44 +01:00
@login_required
@require_http_methods(["GET", "POST"])
2021-12-18 22:40:15 +01:00
def gymnast_create_or_update(request, gymnast_id=None):
2021-12-09 16:53:44 +01:00
"""
Formulaire de creation et modification d'un gymnaste.
"""
2021-12-18 22:40:15 +01:00
if gymnast_id:
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
2021-12-19 09:30:51 +01:00
data = {"club_related": gymnast.club}
2021-12-09 16:53:44 +01:00
else:
gymnast = None
data = {}
if request.method == "POST":
gymnast_form = GymnastForm(request.POST, instance=gymnast)
if gymnast_form.is_valid():
gymnast = gymnast_form.save()
2022-02-06 15:44:55 +01:00
form_data = request.POST.dict()
2022-09-07 12:21:22 +02:00
user_data = {}
user_data['first_name'] = form_data['first_name']
user_data['last_name'] = form_data['last_name']
2022-09-07 12:21:22 +02:00
user_data['username'] = form_data['first_name'].lower() + '_' + form_data['last_name'].lower()
user_data['email'] = form_data['email'].lower()
user_data['is_active'] = True
2022-09-07 12:21:22 +02:00
user_form = UserForm(user_data, instance=gymnast.user)
2022-02-06 15:44:55 +01:00
if user_form.is_valid():
user = user_form.save()
gymnast_group, _ = Group.objects.get_or_create(name='gymnast')
user.groups.add(gymnast_group)
gymnast.user = user
gymnast.save()
2022-02-06 15:44:55 +01:00
# if not user.has_usable_password():
# user.set_password(gymnast.last_name.lower() + _ + str(gymnast.birthdate)[-2:])
2022-02-01 11:08:02 +01:00
return HttpResponseRedirect(reverse("gymnast_details", args=(gymnast.pk,)))
else:
return render(request, "people/gymnasts/create.html", {'form':gymnast_form})
2021-12-09 16:53:44 +01:00
form = GymnastForm(instance=gymnast, initial=data)
2021-12-18 22:40:15 +01:00
context = {"form": form, "gymnast_id": gymnast_id}
return render(request, "people/gymnasts/create.html", context)
2021-12-09 16:53:44 +01:00
@login_required
@require_http_methods(["GET"])
2021-12-18 22:40:15 +01:00
def gymnast_display_skill(request, gymnast_id):
2022-01-07 19:28:33 +01:00
"""Tag affichant les statistiques de skill d'un gymnaste
Le nombre de saut qu'il sait faire (total, par niveau, par rank, …), calcule la complétude, …
2021-12-09 16:53:44 +01:00
.. todo:: Générer UNE fois la liste de skill que le gymnaste ne sait pas faire (1 query)
et les counts puis, dans le template on parcourt plusieurs fois cette même liste mais on
affiche conditionnellement (par age, par rank, ...)
2022-10-09 20:44:28 +02:00
Il y a 4 étapes dans l'apprentissage :
- avec aide (tapis, manip, ) "with help" - 1
- sans aide () "without help" - 2
- enchaîné (un saut avec et après) "chained" - 3
- maitrisé (dans n'importe quelle condition) "masterised" - 4
2021-12-09 16:53:44 +01:00
"""
context = {}
2021-12-18 22:40:15 +01:00
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
2021-12-19 09:30:51 +01:00
gymnast_nb_known_skills = gymnast.known_skills.distinct("skill").count()
2022-09-09 13:12:45 +02:00
context = gymnast.get_informations_from_type("level")
context.update(gymnast.get_informations_from_type("rank"))
2021-12-09 16:53:44 +01:00
2021-12-19 09:30:51 +01:00
planified_skill = (
Skill.objects.filter(plan__gymnast=gymnast.id)
.order_by("-plan__date")
.annotate(plan_date=F("plan__date"))
)
2021-12-18 22:40:15 +01:00
context["planified_skill"] = planified_skill
2021-12-09 16:53:44 +01:00
if gymnast.gender:
2021-12-19 09:30:51 +01:00
context["skill_by_age"] = Skill.objects.filter(
2022-01-09 16:08:54 +01:00
age_girl_masterised__lte=gymnast.age
2021-12-19 09:30:51 +01:00
).exclude(known_by__gymnast=gymnast.id)
2021-12-09 16:53:44 +01:00
else:
2021-12-19 09:30:51 +01:00
context["skill_by_age"] = Skill.objects.filter(
2022-01-09 16:08:54 +01:00
age_boy_masterised__lte=gymnast.age
2021-12-19 09:30:51 +01:00
).exclude(known_by__gymnast=gymnast.id)
skill_whith_help = (
2022-10-12 17:21:27 +02:00
Skill.objects.filter(known_by__gymnast=gymnast_id, known_by__learning_step=1)
.exclude(known_by__gymnast=gymnast.id, known_by__learning_step__gte=2)
2021-12-19 09:30:51 +01:00
.distinct()
)
2022-10-09 20:44:28 +02:00
skill_without_help = (
2022-10-12 17:21:27 +02:00
Skill.objects.filter(known_by__gymnast=gymnast_id, known_by__learning_step=2)
.exclude(known_by__gymnast=gymnast.id, known_by__learning_step=3)
2022-10-09 20:44:28 +02:00
.distinct()
)
2021-12-19 09:30:51 +01:00
skill_not_chained = (
2022-10-12 17:21:27 +02:00
Skill.objects.filter(known_by__gymnast=gymnast_id, known_by__learning_step=2)
.exclude(known_by__gymnast=gymnast.id, known_by__learning_step=3)
2021-12-19 09:30:51 +01:00
.distinct()
)
2021-12-09 16:53:44 +01:00
2022-10-09 20:44:28 +02:00
skill_chained = (
2022-10-12 17:21:27 +02:00
Skill.objects.filter(known_by__gymnast=gymnast_id, known_by__learning_step=3)
.exclude(known_by__gymnast=gymnast.id, known_by__learning_step=4)
2022-10-09 20:44:28 +02:00
.distinct()
)
2021-12-09 16:53:44 +01:00
context["gymnast"] = gymnast
context["skill_whith_help"] = skill_whith_help
context["skill_not_chained"] = skill_not_chained
2022-10-09 20:44:28 +02:00
context["skill_without_help"] = skill_without_help
context["skill_chained"] = skill_chained
2021-12-09 16:53:44 +01:00
context["gymnast_nb_known_skills"] = gymnast_nb_known_skills
2022-09-04 16:42:21 +02:00
context["user_is_trainer"] = request.user.groups.filter(name="trainer").exists() # TODO: utiliser les {{ perms }}
return render(request, "people/gymnasts/tab_skill.html", context)