799 lines
26 KiB
Python
799 lines
26 KiB
Python
from django.contrib.auth.decorators import login_required
|
|
from django.db.models import Q
|
|
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
|
|
from django.shortcuts import render, get_object_or_404
|
|
from django.views.decorators.http import require_http_methods
|
|
from django.urls import reverse
|
|
|
|
from jarvis.people.models import Gymnast
|
|
from jarvis.followup.models import GymnastHasRoutine
|
|
|
|
from .validators import is_valid_routine_type
|
|
from .forms import (
|
|
SkillForm,
|
|
CombinationForm,
|
|
TrainingRoundForm,
|
|
GymnastTrainingForm,
|
|
CombinationSkillForm,
|
|
GymnastTrainingRoundForm,
|
|
)
|
|
from .models import (
|
|
Skill,
|
|
TrainingRound,
|
|
Routine,
|
|
Educative,
|
|
RoutineSkill,
|
|
GymnastTraining,
|
|
GymnastTrainingRound,
|
|
PrerequisiteClosure,
|
|
)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["POST"])
|
|
def educative_lookup(request):
|
|
"""
|
|
Récupère la liste des skill à la volée suivant des caractères de recherche entrés (min 3
|
|
caractères).
|
|
"""
|
|
results = []
|
|
pattern = request.POST.get("pattern", None)
|
|
|
|
# Ignore queries shorter than length 2
|
|
if pattern is not None and len(pattern) > 2:
|
|
model_results = Educative.objects.filter(
|
|
Q(short_label__icontains=pattern) | Q(long_label__icontains=pattern)
|
|
)
|
|
results = [
|
|
{"ID": x.id, "long_label": x.long_label, "short_label": x.short_label}
|
|
for x in model_results
|
|
]
|
|
|
|
return JsonResponse(results, safe=False)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def educative_details(request, educative_id):
|
|
"""Renvoie les détails d'un educatif suivant que ce soit une combination ou un skill"""
|
|
try:
|
|
Routine.objects.get(pk=educative_id)
|
|
return combination_details(request, educative_id)
|
|
except Routine.DoesNotExist:
|
|
return skill_details(request, educative_id)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["POST"])
|
|
def skill_lookup(request):
|
|
"""
|
|
Récupère la liste des skill à la volée suivant des caractères de recherche entrés (min 3
|
|
caractères).
|
|
"""
|
|
results = []
|
|
pattern = request.POST.get("pattern", None)
|
|
|
|
# Ignore queries shorter than length 2
|
|
if pattern is not None and len(pattern) > 2:
|
|
model_results = Skill.objects.filter(
|
|
Q(short_label__icontains=pattern)
|
|
| Q(long_label__icontains=pattern)
|
|
| Q(notation__icontains=pattern)
|
|
)
|
|
results = [
|
|
{"ID": x.id, "Name": str(x), "Notation": x.notation} for x in model_results
|
|
]
|
|
|
|
return JsonResponse(results, safe=False)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def skill_without_prerequisite_listing(request):
|
|
"""
|
|
Récupère la liste des skills n'ayant aucun prérequis.
|
|
"""
|
|
skill_list = Skill.objects.filter(prerequisites=None)
|
|
context = {"skill_list": skill_list}
|
|
return render(request, "skills/list.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def skill_listing(request, field=None, expression=None, value=None, level=None):
|
|
"""
|
|
Récupère la liste des skills suivant un pattern si celui-ci est définit.
|
|
|
|
Args:
|
|
field (str) champ sur lequel doit être effectué la recherche
|
|
expression (str) expression de comparaison : le, leq, ge, geq, …
|
|
value (str) valeur de la recherche
|
|
level (int) niveau requis pour les skills cherchés.
|
|
"""
|
|
|
|
pattern = None
|
|
|
|
if not field or not value or not expression:
|
|
pattern = request.GET.get("pattern", None)
|
|
|
|
if pattern:
|
|
skill_list = Skill.objects.filter(
|
|
Q(long_label__icontains=pattern) | Q(short_label__icontains=pattern)
|
|
)
|
|
elif field and expression and value:
|
|
kwargs = {f"{field}__{expression}": value}
|
|
skill_list = Skill.objects.filter(**kwargs)
|
|
elif level is not None:
|
|
skill_list = Skill.objects.filter(level=level)
|
|
else:
|
|
skill_list = Skill.objects.all()
|
|
|
|
context = {"skill_list": skill_list}
|
|
return render(request, "skills/list.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def skill_tree(request, skill_id):
|
|
"""Récupère tout l'arbre des prérequis pour une saut passé en paramètre
|
|
|
|
Args:
|
|
skill_id (int) identifiant de la classe Skill
|
|
"""
|
|
skill = get_object_or_404(Skill, pk=skill_id)
|
|
node_dict = {}
|
|
skill_closure = PrerequisiteClosure.objects.filter(descendant=skill)
|
|
for closure in skill_closure:
|
|
node_dict[closure.ancestor] = closure.ancestor.prerequisites.all()
|
|
|
|
context = {"skill": skill, "node_dict": node_dict}
|
|
return render(request, "skills/learning_line.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def skill_details(request, skill_id):
|
|
"""Récupère toutes les informations d'un skill.
|
|
|
|
La méthode en profite pour vérifier les champs level, rank, age_boy et age_girl
|
|
par rapport aux pré-requis.
|
|
|
|
Args:
|
|
skill_id (int) identifiant de la classe Skill
|
|
"""
|
|
skill = get_object_or_404(Skill, pk=skill_id)
|
|
|
|
for prerequisite in skill.prerequisites.all():
|
|
skill.level = max(prerequisite.level + 1, skill.level)
|
|
skill.rank = max(prerequisite.rank + 1, skill.rank)
|
|
|
|
skill.age_boy_with_help = max(
|
|
skill.age_boy_with_help, prerequisite.age_boy_with_help
|
|
)
|
|
skill.age_boy_without_help = max(
|
|
skill.age_boy_without_help, prerequisite.age_boy_without_help
|
|
)
|
|
skill.age_boy_chained = max(skill.age_boy_chained, prerequisite.age_boy_chained)
|
|
skill.age_boy_masterised = max(
|
|
skill.age_boy_masterised, prerequisite.age_boy_masterised
|
|
)
|
|
|
|
skill.age_girl_with_help = max(
|
|
skill.age_girl_with_help, prerequisite.age_girl_with_help
|
|
)
|
|
skill.age_girl_without_help = max(
|
|
skill.age_girl_without_help, prerequisite.age_girl_without_help
|
|
)
|
|
skill.age_girl_chained = max(
|
|
skill.age_girl_chained, prerequisite.age_girl_chained
|
|
)
|
|
skill.age_girl_masterised = max(
|
|
skill.age_girl_masterised, prerequisite.age_girl_masterised
|
|
)
|
|
|
|
skill.save()
|
|
|
|
# Je sépare les educatifs de type "skill" et les éducatifs de type "combination" pour mieux
|
|
# gérer l'affichage. Du code bien dégueulasse !
|
|
# QTF : une idée pour faire ca de manière plus propre, plus élégante ?
|
|
combination_dict = {}
|
|
educative_skill = skill.educatives.filter(id__in=Skill.objects.all())
|
|
for educative in skill.educatives.filter(id__in=Routine.objects.all()):
|
|
combination = Routine.objects.get(pk=educative.id)
|
|
combination_dict[combination] = []
|
|
for educ_skill in combination.routine.skill_links.all():
|
|
combination_dict[combination].append(educ_skill)
|
|
|
|
context = {
|
|
"skill": skill,
|
|
"combination_dict": combination_dict,
|
|
"educative_skill": educative_skill,
|
|
}
|
|
return render(request, "skills/details.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET", "POST"])
|
|
def skill_create_or_update(request, skill_id=None):
|
|
"""Création ou modification d'un saut.
|
|
|
|
Args:
|
|
skill_id (int) identifiant d'un object de classe <Skill>.
|
|
"""
|
|
|
|
if skill_id:
|
|
skill = get_object_or_404(Skill, pk=skill_id)
|
|
else:
|
|
skill = None
|
|
|
|
if request.method == "POST":
|
|
form = SkillForm(request.POST, instance=skill)
|
|
|
|
if form.is_valid():
|
|
skill = form.save()
|
|
return HttpResponseRedirect(reverse("skill_details", args=(skill.pk,)))
|
|
return render(request, "skill/create.html", {"form": form})
|
|
|
|
form = SkillForm(instance=skill)
|
|
context = {"form": form, "skill_id": skill_id}
|
|
return render(request, "skills/create.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def competition_routine_listing(request, gymnast_id=None):
|
|
"""Récupère la liste des routines (séries) de compétition suivant un pattern si celui-ci est
|
|
défini.
|
|
|
|
Args:
|
|
gymnast_id (int) identifiant de la classe Gymnast
|
|
"""
|
|
|
|
gymnast = None
|
|
pattern = request.GET.get("pattern", None)
|
|
if pattern is not None and len(pattern) > 2:
|
|
routine_list = Routine.objects.filter(
|
|
is_routine=True, is_competitive=True
|
|
).filter(Q(long_label__icontains=pattern) | Q(short_label__icontains=pattern))
|
|
else:
|
|
if gymnast_id:
|
|
routine_list = Routine.objects.filter(
|
|
is_routine=True, is_competitive=True
|
|
).filter(done_by_gymnast__gymnast=gymnast_id)
|
|
gymnast = Gymnast.objects.get(pk=gymnast_id)
|
|
else:
|
|
routine_list = Routine.objects.filter(is_routine=True, is_competitive=True)
|
|
|
|
context = {
|
|
"title": "Competition Routines",
|
|
"routine_list": routine_list,
|
|
"gymnast_id": gymnast_id,
|
|
"gymnast": gymnast,
|
|
}
|
|
return render(request, "combinations/list.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def routine_listing(request, gymnast_id=None):
|
|
"""Récupère la liste des routines (série) suivant un pattern si celui-ci est défini
|
|
|
|
Args:
|
|
gymnast_id (int) identifiant de la classe Gymnast
|
|
"""
|
|
|
|
gymnast = None
|
|
pattern = request.GET.get("pattern", None)
|
|
base_queryset = Routine.objects.filter(is_routine=True)
|
|
if pattern is not None and len(pattern) > 2:
|
|
routine_list = base_queryset.filter(
|
|
Q(long_label__icontains=pattern) | Q(short_label__icontains=pattern)
|
|
)
|
|
else:
|
|
if gymnast_id:
|
|
routine_list = base_queryset.filter(done_by_gymnast__gymnast=gymnast_id)
|
|
gymnast = Gymnast.objects.get(pk=gymnast_id)
|
|
else:
|
|
routine_list = base_queryset
|
|
|
|
context = {
|
|
"title": "Routines",
|
|
"routine_list": routine_list,
|
|
"gymnast_id": gymnast_id,
|
|
"gymnast": gymnast,
|
|
}
|
|
return render(request, "combinations/list.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def educative_combination_listing(request, gymnast_id=None):
|
|
"""Récupère la liste des educatifs suivant un pattern si celui-ci est défini
|
|
|
|
Args:
|
|
gymnast_id (int) identifiant de la classe Gymnast
|
|
"""
|
|
|
|
gymnast = None
|
|
pattern = request.GET.get("pattern", None)
|
|
base_queryset = Routine.objects.filter(is_routine=False)
|
|
if pattern is not None and len(pattern) > 2:
|
|
routine_list = base_queryset.filter(
|
|
Q(long_label__icontains=pattern) | Q(short_label__icontains=pattern)
|
|
)
|
|
else:
|
|
if gymnast_id:
|
|
routine_list = base_queryset.filter(done_by_gymnast__gymnast=gymnast_id)
|
|
gymnast = Gymnast.objects.get(pk=gymnast_id)
|
|
else:
|
|
routine_list = base_queryset
|
|
|
|
context = {
|
|
"title": "Educative",
|
|
"routine_list": routine_list,
|
|
"gymnast_id": gymnast_id,
|
|
"gymnast": gymnast,
|
|
}
|
|
return render(request, "combinations/list.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def combination_listing(request, gymnast_id=None):
|
|
"""Récupère la liste des combinaisons suivant un pattern si celui-ci est défini
|
|
|
|
Args:
|
|
gymnast_id (int) identifiant de la classe Gymnast
|
|
"""
|
|
|
|
gymnast = None
|
|
pattern = request.GET.get("pattern", None)
|
|
if pattern is not None and len(pattern) > 2:
|
|
routine_list = Routine.objects.filter(
|
|
Q(long_label__icontains=pattern) | Q(short_label__icontains=pattern)
|
|
)
|
|
else:
|
|
if gymnast_id:
|
|
routine_list = Routine.objects.filter(done_by_gymnast__gymnast=gymnast_id)
|
|
gymnast = Gymnast.objects.get(pk=gymnast_id)
|
|
else:
|
|
routine_list = Routine.objects.all()
|
|
|
|
context = {
|
|
"title": "Combinations",
|
|
"routine_list": routine_list,
|
|
"gymnast_id": gymnast_id,
|
|
"gymnast": gymnast,
|
|
}
|
|
return render(request, "combinations/list.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["POST"])
|
|
def combination_lookup(request, search_type=None):
|
|
"""
|
|
Récupère la liste des combinaisons à la volée suivant des caractères de recherche entrés.
|
|
"""
|
|
pattern = request.POST.get("pattern", None)
|
|
|
|
if pattern is not None and len(pattern) > 2:
|
|
results = Routine.objects.filter(
|
|
Q(long_label__icontains=pattern) | Q(short_label__icontains=pattern)
|
|
)
|
|
|
|
if search_type:
|
|
if search_type == "competitive":
|
|
results = results.filter(is_competitive=1)
|
|
elif search_type == "routine":
|
|
results = results.filter(is_routine=1)
|
|
|
|
combination_list = [{"id": x.id, "label": str(x)} for x in results]
|
|
|
|
return JsonResponse(combination_list, safe=False)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def combination_details(request, combination_id):
|
|
"""
|
|
Récupère toutes les informations d'une combinaison.
|
|
|
|
Args:
|
|
combination_id (int) identifiant d'une routine
|
|
"""
|
|
|
|
combination = get_object_or_404(Routine, pk=combination_id)
|
|
combination.compute_informations()
|
|
combination_string = combination.inline_str()
|
|
context = {
|
|
"combination": combination,
|
|
"combination_string": combination_string,
|
|
"skill_link_list": combination.skill_links.all(),
|
|
}
|
|
return render(request, "combinations/details.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET", "POST"])
|
|
def combination_create_or_update(request, combination_id=None):
|
|
"""Création d'une série.
|
|
|
|
Args:
|
|
combination_id (int) identifiant d'un object de classe <routine>.
|
|
"""
|
|
if combination_id:
|
|
combination = get_object_or_404(Routine, pk=combination_id)
|
|
else:
|
|
combination = None
|
|
|
|
if request.method == "POST":
|
|
form = CombinationForm(request.POST, instance=combination)
|
|
|
|
if form.is_valid():
|
|
combination = form.save()
|
|
# ici faire un FOR skill in form_skills_list:
|
|
# record.save() # ca sauve le record dans la table RoutineSkill
|
|
# something like this :
|
|
# http://stackoverflow.com/questions/3074938/django-m2m-form-save-through-table
|
|
# QTF : can you help me ?
|
|
return HttpResponseRedirect(
|
|
reverse("combination_details", args=(combination.pk,))
|
|
)
|
|
|
|
return render(request, "combinations/create.html", {"form": form})
|
|
|
|
form = CombinationForm(instance=combination)
|
|
context = {"form": form, "combination_id": combination_id}
|
|
return render(request, "combinations/create.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def compose_combination(request, combination_id):
|
|
"""
|
|
Récupère une routine et les sauts associés sur base d'un id passé en paramètre.
|
|
|
|
Args:
|
|
combination_id (int) identifiant d'un object de classe <routine>.
|
|
"""
|
|
|
|
routine = get_object_or_404(Routine, pk=combination_id)
|
|
skill_link_list = routine.skill_links.all()
|
|
skill_list = Skill.objects.all()
|
|
context = {
|
|
"routine": routine,
|
|
"skill_link_list": skill_link_list,
|
|
"number_of_skill": skill_link_list.count(),
|
|
"skill_list": skill_list,
|
|
}
|
|
return render(request, "combinations/compose.html", context)
|
|
|
|
|
|
@require_http_methods(["POST"])
|
|
def link_skill_to_combination(request):
|
|
"""
|
|
Recoit dans request trois informations permettant de lier complètement un saut à une routine :
|
|
- combination_id (int) identifiant d'un object de classe <routine>
|
|
- skill_id (int) identifiant d'un object de classe <skill>
|
|
- rank (int) numéro de place du skill dans la routine
|
|
"""
|
|
data = {
|
|
"routine": get_object_or_404(Routine, pk=request.POST.get("combination_id", 0)),
|
|
"skill": get_object_or_404(Skill, pk=request.POST.get("skill_id", 0)),
|
|
"rank": request.POST.get("rank", 0),
|
|
}
|
|
form = CombinationSkillForm(data)
|
|
|
|
if form.is_valid():
|
|
form.save()
|
|
return HttpResponse(200)
|
|
|
|
return HttpResponse(406)
|
|
|
|
|
|
@require_http_methods(["POST"])
|
|
def unlink_skill_from_combination(request):
|
|
"""
|
|
Recoit dans request deux informations permettant d'enlever un skill d'une routine :
|
|
- rank (int) numéro de place du skill dans la routine
|
|
- combination_id (int) identifiant d'un object de classe <routine>
|
|
"""
|
|
rank = request.POST.get("rank", None)
|
|
combination_id = request.POST.get("combination_id", None)
|
|
combination = get_object_or_404(Routine, pk=combination_id)
|
|
try:
|
|
RoutineSkill.objects.get(routine=combination, rank=rank).delete()
|
|
except Exception:
|
|
return HttpResponse(409)
|
|
|
|
return HttpResponse(200)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def traininground_listing(request):
|
|
"""Liste des passages."""
|
|
passe_listing = TrainingRound.objects.all()
|
|
context = {"passe_listing": passe_listing}
|
|
return render(request, "trainingrounds/list.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def traininground_details(request, traininground_id, date=None):
|
|
"""Détails d'un passage."""
|
|
|
|
is_skill = False
|
|
traininground = get_object_or_404(TrainingRound, pk=traininground_id)
|
|
educative_list = traininground.educatives.all()
|
|
|
|
routine = None
|
|
skill_link_list = None
|
|
|
|
traininground.update_traininground()
|
|
|
|
# Decryptage de la regexp
|
|
if traininground.regexp is not None and traininground.regexp != "":
|
|
arguments = traininground.regexp.split(" ")
|
|
if is_valid_routine_type(arguments[0]) and date is not None:
|
|
# get routine_type
|
|
routine_type = 0
|
|
ghr = GymnastHasRoutine.objects.filter(
|
|
gymnast=traininground.gymnast,
|
|
date_begin__lte=date,
|
|
routine_type=routine_type,
|
|
).first()
|
|
|
|
routine = ghr.routine
|
|
skill_link_list = routine.skill_links.all()
|
|
if len(arguments) == 2:
|
|
content = arguments[1].replace("[", "").replace("]", "")
|
|
ranks = content.split("-")
|
|
|
|
if ranks[0] != "":
|
|
skill_link_list = skill_link_list.filter(rank__gte=ranks[0])
|
|
|
|
if ranks[1] != "":
|
|
skill_link_list = skill_link_list.filter(rank__lte=ranks[1])
|
|
|
|
content = False
|
|
if skill_link_list or routine or educative_list:
|
|
content = True
|
|
|
|
context = {
|
|
"is_skill": is_skill,
|
|
"traininground": traininground,
|
|
"educative_list": educative_list,
|
|
"routine": routine,
|
|
"skill_link_list": skill_link_list,
|
|
"content": content,
|
|
"is_wc": traininground.is_regexp_wc
|
|
# "number_of_educative": number_of_educative,
|
|
}
|
|
return render(request, "trainingrounds/details.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET", "POST"])
|
|
def traininground_create_or_update(request, traininground_id=None):
|
|
"""Création d'un passage.
|
|
|
|
Args:
|
|
traininground_id (int) identifiant d'un object de classe <TrainingRound>.
|
|
"""
|
|
if traininground_id:
|
|
traininground = get_object_or_404(TrainingRound, pk=traininground_id)
|
|
else:
|
|
traininground = None
|
|
|
|
if request.method == "POST":
|
|
form = TrainingRoundForm(request.POST, instance=traininground)
|
|
|
|
if form.is_valid():
|
|
traininground = form.save()
|
|
return HttpResponseRedirect(
|
|
reverse("traininground_details", args=(traininground.pk,))
|
|
)
|
|
|
|
return render(request, "trainingrounds/create.html", {"form": form})
|
|
|
|
form = TrainingRoundForm(instance=traininground)
|
|
context = {"form": form, "traininground_id": traininground_id}
|
|
return render(request, "trainingrounds/create.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def gymnast_training_details(request, gymnast_training_id):
|
|
"""Détails d'un entraînement."""
|
|
|
|
gymnast_training = get_object_or_404(GymnastTraining, pk=gymnast_training_id)
|
|
training_rounds = gymnast_training.rounds_links.all()
|
|
|
|
context = {
|
|
"gymnast": gymnast_training.gymnast,
|
|
"gymnast_training": gymnast_training,
|
|
"training_rounds": training_rounds,
|
|
}
|
|
return render(request, "gymnasttrainings/details.html", context)
|
|
|
|
|
|
@require_http_methods(["POST"])
|
|
def switch_traininground(request):
|
|
"""
|
|
Recoit dans request deux identifiants de trainingprogram qu'il faut échanger :
|
|
- tp_id (int) identifiant d'une instance de TraiingProgram
|
|
- direction (str) la direction du changement (0: haut, 1: bas)
|
|
|
|
J'utilise `32767` comme valeur intermédiaire pour le `rank` car c'est la limite supérieure d'un
|
|
PositiveSmallIntegerField.
|
|
|
|
TODO: ramener un rank d'un seul coup.
|
|
"""
|
|
try:
|
|
target_trainingprogram_id = request.POST.get("tpid", None)
|
|
direction = int(request.POST.get("direction", 0))
|
|
|
|
target_trainingpround = get_object_or_404(
|
|
GymnastTrainingRound, pk=target_trainingprogram_id
|
|
)
|
|
|
|
if direction == 0:
|
|
source_traininground = (
|
|
GymnastTrainingRound.objects.filter(rank__lt=target_trainingpround.rank)
|
|
.order_by("-id")
|
|
.first()
|
|
)
|
|
new_rank = (target_trainingpround.rank - source_traininground.rank) - 1
|
|
is_switchable = (source_traininground.rank == new_rank)
|
|
else:
|
|
source_traininground = (
|
|
GymnastTrainingRound.objects.filter(rank__gt=target_trainingpround.rank)
|
|
.order_by("id")
|
|
.first()
|
|
)
|
|
new_rank = (source_traininground.rank - target_trainingpround.rank) - 1
|
|
is_switchable = (source_traininground.rank == new_rank)
|
|
|
|
if is_switchable:
|
|
saved_source_rank = source_traininground.rank
|
|
saved_target_rank = target_trainingpround.rank
|
|
source_traininground.rank = 32767
|
|
source_traininground.save()
|
|
target_trainingpround.rank = saved_source_rank
|
|
target_trainingpround.save()
|
|
source_traininground.rank = saved_target_rank
|
|
source_traininground.save()
|
|
else:
|
|
if direction == 0:
|
|
new_rank = source_traininground.rank + 1
|
|
else:
|
|
new_rank = source_traininground.rank - 1
|
|
target_trainingpround.rank = new_rank
|
|
target_trainingpround.save()
|
|
|
|
return HttpResponse(200)
|
|
except Exception:
|
|
return HttpResponse(409)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET", "POST"])
|
|
def gymnast_training_create_or_update(request, gymnasttraining_id=None, gymnast_id=None):
|
|
"""Création d'une série.
|
|
|
|
Args:
|
|
gymnasttraining_id (int) identifiant d'un objet de la classe <GymnastTraining>
|
|
gymnast_id (int) identifiant d'un objet de la classe <Gymnast>
|
|
"""
|
|
if gymnasttraining_id:
|
|
gymnasttraining = get_object_or_404(GymnastTraining, pk=gymnasttraining_id)
|
|
else:
|
|
gymnasttraining = None
|
|
data = {}
|
|
if gymnast_id is not None:
|
|
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
|
|
data["gymnast"] = gymnast_id
|
|
data["gymnast_related"] = str(gymnast)
|
|
|
|
if request.method == "POST":
|
|
form = GymnastTrainingForm(request.POST, instance=gymnasttraining)
|
|
|
|
if form.is_valid():
|
|
gymnasttraining = form.save()
|
|
return HttpResponseRedirect(
|
|
reverse("gymnast_training_details", args=(gymnasttraining.pk,))
|
|
)
|
|
|
|
return render(request, "gymnasttrainings/create.html", {"form": form})
|
|
|
|
form = GymnastTrainingForm(instance=gymnasttraining, initial=data)
|
|
context = {"form": form, "gymnasttraining_id": gymnasttraining_id}
|
|
return render(request, "gymnasttrainings/create.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def gymnast_training_listing(request, gymnast_id=None):
|
|
"""Liste des entraînements."""
|
|
|
|
if gymnast_id:
|
|
gymnast = Gymnast.objects.get(pk=gymnast_id)
|
|
gymnasttrainings = gymnast.trainings.all()
|
|
else:
|
|
gymnast = None
|
|
gymnasttrainings = GymnastTraining.objects.all()
|
|
|
|
context = {"gymnasttrainings": gymnasttrainings, "gymnast": gymnast}
|
|
return render(request, "gymnasttrainings/list.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def gymnast_training_compose(request, gymnast_training_id):
|
|
"""
|
|
Récupère un entraînement et les sauts associés sur base d'un id passé en paramètre.
|
|
|
|
Args:
|
|
gymnast_training_id (int) identifiant d'un object de classe <GymnastTraining>.
|
|
"""
|
|
|
|
gymnast_training = get_object_or_404(GymnastTraining, pk=gymnast_training_id)
|
|
gtr_list = gymnast_training.rounds_links.all()
|
|
rank = gtr_list.count()
|
|
if not rank:
|
|
print("rank vide")
|
|
rank = 1
|
|
print(rank)
|
|
|
|
context = {
|
|
"gymnast_training": gymnast_training,
|
|
"gtr_list": gtr_list,
|
|
"rank": rank,
|
|
}
|
|
return render(request, "gymnasttrainings/compose.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["POST"])
|
|
def traininground_lookup(request):
|
|
"""
|
|
Récupère la liste des skill à la volée suivant des caractères de recherche entrés (min 3
|
|
caractères).
|
|
"""
|
|
trainingrounds = []
|
|
pattern = request.POST.get("pattern", None)
|
|
|
|
if pattern is not None and len(pattern) > 1:
|
|
traininground_list = TrainingRound.objects.filter(label__icontains=pattern)
|
|
trainingrounds = [
|
|
{"ID": x.id, "Label": str(x)} for x in traininground_list
|
|
]
|
|
|
|
return JsonResponse(trainingrounds, safe=False)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["POST"])
|
|
def link_round_to_training(request):
|
|
"""
|
|
Recoit dans request trois informations permettant de lier complètement un saut à une routine :
|
|
- gymnasttraining_id (int) identifiant d'un object de classe <GymnastTraining>
|
|
- traininground_id (int) identifiant d'un object de classe <TrainingRound>
|
|
- repetition (int) nombre de répétition du round dans l'entraînement
|
|
- rank (int) numéro de place du round dans l'entraînement
|
|
"""
|
|
data = {
|
|
"gymnast_training": get_object_or_404(GymnastTraining, pk=request.POST.get("gymnast_training_id", 0)),
|
|
"training_round": get_object_or_404(TrainingRound, pk=request.POST.get("traininground_id", 0)),
|
|
"repetition": request.POST.get("repetition", 0),
|
|
"rank": request.POST.get("rank", 0),
|
|
}
|
|
form = GymnastTrainingRoundForm(data)
|
|
|
|
if form.is_valid():
|
|
form.save()
|
|
return HttpResponse(200)
|
|
|
|
return HttpResponse(406)
|