Jarvis/jarvis/core/views.py

381 lines
14 KiB
Python

from datetime import timedelta
from weasyprint import HTML, CSS
import pendulum
from django.db.models import Max
from django.conf import settings
from django.db.models import Q, F, OuterRef, Subquery
from django.shortcuts import render, get_object_or_404
from django.utils import timezone
from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_http_methods
from django.template.loader import render_to_string
from django.urls import reverse
from django.contrib.auth import get_user_model
from jarvis.objective.models import Routine
from jarvis.profiles.models import Profile
from jarvis.followup.models import (
Skill,
Point,
Chrono,
WellBeing,
Intensity,
HeightWeight,
LearnedSkill
)
from jarvis.location.models import Place, Club
from jarvis.people.models import Gymnast
from jarvis.people.views import gymnast_details
from jarvis.planning.models import Event
from jarvis.tools.models import from_date_to_week_number
from jarvis.tools.clean_name import clean_name
from jarvis.tools.models import Season
from .models import Citation
User = get_user_model()
def login(request):
"""Fonction d'authentifictation."""
if request.method == "POST":
username = request.POST["login"]
password = request.POST["password"]
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
auth_login(request, user)
try:
profile = Profile.objects.get(user=user)
request.session["profileid"] = profile.id
request.session["template"] = profile.template_color
request.session["sidebar"] = profile.sidebar_color
request.session["is_sidebar_minified"] = profile.is_sidebar_minified
except Profile.DoesNotExist:
pass
request.session["available_gymnast"] = [x.gymnast.id for x in user.can_view.all()]
return HttpResponseRedirect(reverse("home"))
context = {"message": "Account disabled."}
else:
context = {"message": "Wrong login/password."}
else:
context = {}
return render(request, "login.html", context)
@login_required
@require_http_methods(["GET"])
def logout(request):
"""
Fonction de déconnexion
"""
auth_logout(request)
return HttpResponseRedirect(reverse("login"))
def next_birthdays(request, number_of_birthday):
"""
Renvoie la liste des `number_of_birthday` prochains anniversaires.
"""
birthday_list = sorted(
Gymnast.objects.all(), key=lambda t: t.next_birthday_in_days
)[:number_of_birthday]
return birthday_list
def gymnast_have_birthday(request):
"""
Renvoie la liste des gymnastes qui ont leur anniversaire aujourd'hui.
"""
today = pendulum.now().date()
return Gymnast.objects.filter(birthdate__day=today.day, birthdate__month=today.month).values_list("id")
# @lru_cache()
# def get_last_updated_gymnasts(expiration_date):
# ...
# TODO: liste de mots pour souhaiter la bienvenue
# TODO: véririer si c'est l'anniversaire de la personne qui est connectée.
# TODO: check if gymnast have point
# ---------------------------
# 1. récupérer tous les évènements passés
# 2. pour chaque event, vérifier que tous les gymnastes renseignés
# dans les participants ont des points associés.
# S'il n'y a pas de point, faire une alerte à l'utilisateur qui se connecte.
# TODO: Check if gymnast have update
# -----------------------------
# lister tous les gymnastes qui n'ont pas eu d'update depuis... 2 semaines ?
# peut-être le paramètre (en jour) devrait être stocké en DB.
# S'il n'y a pas d'update, faire une alerte à l'utilisateur qui se connecte.
@login_required
@require_http_methods(["GET"])
def home(request):
"""
Génère la page d'accueil du site basée sur la saison (si celle-ci est connue)
"""
today = timezone.now() # pendulum.now().date()
_, week_number = from_date_to_week_number(today)
context = {
"week_number": week_number,
"quote": Citation.objects.order_by("?").first(),
"event_list": Event.objects.filter(date_begin__gte=today).order_by("date_begin")[:10],
"nb_active_gymnast": Gymnast.objects.filter(is_active=True).count(),
"nb_trainer": User.objects.filter(is_active=True, groups__name="trainer").count(),
"nb_event": Event.objects.all().count(),
"nb_skill": Skill.objects.all().count(),
"nb_routine": Routine.objects.all().count(),
"nb_score": Point.objects.all().count(),
"nb_club": Club.objects.all().count(),
"percentage_week": (week_number / 52) * 100,
"birthday_list": next_birthdays(request, 10),
}
is_trainer = request.user.groups.filter(name="trainer").exists()
if is_trainer:
last_updated_gymnasts = set()
last_updated_gymnasts.update(
Gymnast.objects.filter(wellbeings__created_at__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(height_weight__date__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(intensities__date__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(points__created_at__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(chronos__created_at__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(injuries__created_at__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(known_skills__created_at__gt=request.user.last_login)
)
season = Season()
# Paramètre dans le fichier .env ?
limit_date = today - timedelta(days=7)
waiting_update_gymnast = (
Gymnast.objects.filter(season_informations__season=season)
.exclude(
Q(is_active=False)
| Q(wellbeings__created_at__gte=limit_date)
| Q(points__created_at__gte=limit_date)
| Q(chronos__created_at__gte=limit_date)
| Q(injuries__created_at__gte=limit_date)
| Q(known_skills__created_at__gte=limit_date)
)
.distinct()
)
context["is_trainer"] = is_trainer
context["last_updated_gymnasts"] = last_updated_gymnasts
context["waiting_update_gymnast"] = waiting_update_gymnast
else:
todate = pendulum.now().date()
birthday_list = gymnast_have_birthday(request)
gymnast = get_object_or_404(Gymnast, pk=request.user.gymnast.id)
context["gymnast"] = gymnast
# if birthday_list is not None and gymnast.id in birthday_list:
# print("C'est l'anniversaire du gymnaste !")
# else:
# print("Pas son annif…")
wellbeing_last_record_date = WellBeing.objects.filter(gymnast=gymnast).values_list("date").order_by("-date").first()
if todate.diff(wellbeing_last_record_date[0]).in_days() > 21:
wellbeing_state = "danger bold"
elif todate.diff(wellbeing_last_record_date[0]).in_days() > 14:
wellbeing_state = "danger"
elif todate.diff(wellbeing_last_record_date[0]).in_days() > 7:
wellbeing_state = "warning"
else:
wellbeing_state = None
height_weight_last_record_date = HeightWeight.objects.filter(gymnast=gymnast).values_list("date").order_by("-date").first()
if todate.diff(height_weight_last_record_date[0]).in_days() > 21:
height_weight_state = "danger bold"
elif todate.diff(height_weight_last_record_date[0]).in_days() > 14:
height_weight_state = "danger"
elif todate.diff(height_weight_last_record_date[0]).in_days() > 7:
height_weight_state = "warning"
else:
height_weight_state = None
intensities_last_record_date = Intensity.objects.filter(gymnast=gymnast).values_list("date").order_by("-date").first()
if todate.diff(intensities_last_record_date[0]).in_days() > 21:
intensity_state = "danger bold"
elif todate.diff(intensities_last_record_date[0]).in_days() > 14:
intensity_state = "danger"
elif todate.diff(intensities_last_record_date[0]).in_days() > 7:
intensity_state = "warning"
else:
intensity_state = None
# points_last_update = Gymnast.objects.all().order_by("-date")[:1]
chrono_last_record_date = Chrono.objects.filter(gymnast=gymnast).values_list("date").order_by("-date").first()
if todate.diff(chrono_last_record_date[0]).in_days() > 21:
chrono_state = "danger bold"
elif todate.diff(chrono_last_record_date[0]).in_days() > 14:
chrono_state = "danger"
elif todate.diff(chrono_last_record_date[0]).in_days() > 7:
chrono_state = "warning"
else:
chrono_state = None
known_skills_last_record_date = LearnedSkill.objects.filter(gymnast=gymnast).values_list("date").order_by("-date").first()
if todate.diff(known_skills_last_record_date[0]).in_days() > 21:
known_skills_state = "danger bold"
elif todate.diff(known_skills_last_record_date[0]).in_days() > 14:
known_skills_state = "danger"
elif todate.diff(known_skills_last_record_date[0]).in_days() > 7:
known_skills_state = "warning"
else:
known_skills_state = None
context["wellbeing_last_record_date"] = wellbeing_last_record_date
context["wellbeing_state"] = wellbeing_state
context["height_weight_last_record_date"] = height_weight_last_record_date
context["height_weight_state"] = height_weight_state
context["intensities_last_record_date"] = intensities_last_record_date
context["intensity_state"] = intensity_state
# "points_last_update": points_last_update,
context["chrono_last_record_date"] = chrono_last_record_date
context["chrono_state"] = chrono_state
context["known_skills_last_record_date"] = known_skills_last_record_date
context["known_skills_state"] = known_skills_state
return render(request, "dashboard/dashboard.html", context)
@login_required
@require_http_methods(["GET"])
def search(request):
"""
Recherche globale au travers de toutes les applications.
"""
pattern = request.GET.get("pattern", None)
if pattern:
name = clean_name(pattern)
gymnast_list = Gymnast.objects.filter(
Q(cleaned_last_name__icontains=name) | Q(cleaned_first_name__icontains=name)
)
if gymnast_list.count() == 1:
gymnast = gymnast_list.first()
return gymnast_details(request, gymnast.id)
else:
skill_list = Skill.objects.filter(
Q(long_label__icontains=pattern)
| Q(short_label__icontains=pattern)
| Q(notation__icontains=pattern)
)
event_list = Event.objects.filter(
Q(name__icontains=pattern) | Q(place__name__icontains=pattern)
)
place_list = Place.objects.filter(
Q(name__icontains=pattern) | Q(city__icontains=pattern)
)
club_list = Club.objects.filter(
Q(name__icontains=pattern)
| Q(place__name__icontains=pattern)
| Q(place__city__icontains=pattern)
)
context = {
"gymnast_list": gymnast_list,
"skill_list": skill_list,
"event_list": event_list,
"place_list": place_list,
"club_list": club_list,
"pattern": pattern,
}
else:
context = {}
return render(request, "search/results.html", context)
@login_required
@require_http_methods(["GET"])
def report_listing(request):
"""Liste des rapports disponibles"""
return render(request, "reports/list.html", {})
@login_required
@require_http_methods(["GET"])
def generate_best_straightjump_listing(request):
"""Va chercher le meilleur chrono pour chaque gymnaste et sa date de réalisation pour en générer
un fichier PDF."""
date_begin = pendulum.now().date()
season, week_number = from_date_to_week_number(date_begin)
records_list = (
Gymnast.objects.values("last_name", "first_name")
.annotate(
score=Max("chronos__score"),
date=Subquery(
Chrono.objects.filter(gymnast=OuterRef("pk"))
.order_by(F("score").desc(nulls_last=True))
.values("date")[:1]
),
)
.order_by("-score")
)
context = {
"SITE_TITLE": settings.SITE_TITLE,
"CLUB_NAME": settings.CLUB_NAME,
"ADDRESS": settings.ADDRESS,
"CITY": settings.CITY,
"ZIP": settings.ZIP,
"HEAD_COACH": settings.HEAD_COACH,
"MOBILE_PHONE": settings.MOBILE_PHONE,
"HEAD_COACH_EMAIL": settings.HEAD_COACH_EMAIL,
"week_number": week_number,
"today": date_begin,
"records_list": records_list,
}
# return render(request, "reports/records_10.html", context)
response = HttpResponse(content_type="application/pdf")
response["Content-Disposition"] = "attachment; filename=report-top_straightjump.pdf"
html = render_to_string("reports/records_10.html", context)
# font_config = FontConfiguration()
HTML(string=html, base_url=request.build_absolute_uri()).write_pdf(
response,
stylesheets=[
CSS(settings.STATICFILES_DIRS[0] + "/css/a4_paper.css"),
CSS(settings.STATICFILES_DIRS[0] + "/css/black-dashboard_report.css"),
CSS(settings.STATICFILES_DIRS[0] + "/css/font_awesome_all_5.15.3.css"),
],
) # , font_config=font_config)
return response
@login_required
@require_http_methods(["GET"])
def help_view(request):
""" Appel à la vue d'aide. """
return render(request, "help/help.html", {})