275 lines
9.1 KiB
Python
275 lines
9.1 KiB
Python
|
|
from datetime import datetime, timedelta, date
|
|
from functools import reduce
|
|
import operator
|
|
|
|
from django.db.models import Q
|
|
from django.shortcuts import render
|
|
from django.template import RequestContext
|
|
from django.utils import timezone
|
|
from django.utils.html import format_html
|
|
from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout
|
|
from django.http import HttpResponseRedirect
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.views.decorators.http import require_http_methods
|
|
|
|
import pendulum
|
|
|
|
from khana.planning.models import (
|
|
Season,
|
|
Event,
|
|
Unavailability,
|
|
Course,
|
|
get_number_of_weeks_between,
|
|
)
|
|
from khana.people.models import Gymnast, Accident # people model
|
|
from khana.location.models import Club # location model
|
|
from khana.objective.models import Skill, Routine # objective model
|
|
from khana.profile.models import Profile
|
|
from khana.communication.views import get_number_of_unread_message
|
|
|
|
|
|
def login(request):
|
|
"""
|
|
Formulaire d'authentifictation.
|
|
"""
|
|
club_list = Club.objects.all()
|
|
|
|
if request.method == "POST":
|
|
username = request.POST["login"]
|
|
password = request.POST["password"]
|
|
|
|
user = authenticate(username=username, password=password)
|
|
|
|
if user is not None: # Pq pas "if user:" ??
|
|
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 Exception:
|
|
pass
|
|
request.session["clubid"] = request.POST.get("clubid", None)
|
|
return HttpResponseRedirect("/")
|
|
else:
|
|
context = {"message": "Account disabled.", "clubs": club_list}
|
|
else:
|
|
context = {"message": "Wrong login/password.", "clubs": club_list}
|
|
else:
|
|
context = {"clubs": club_list}
|
|
|
|
return render(request, "login.html", context)
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["GET"])
|
|
def logout(request):
|
|
"""
|
|
Fonction de déconnexion
|
|
"""
|
|
auth_logout(request)
|
|
return HttpResponseRedirect("/login/")
|
|
|
|
|
|
@login_required
|
|
def __getEventInfo(request):
|
|
"""
|
|
Fonction 'private' qui renvoie les informations relatives à une liste d'évenements.
|
|
|
|
.. todo:: il refuse mon 'filter' que ce soit avant ou après le 'next(5)'. Une idée ?
|
|
next_event = Event.objects.filter(club__in=(request.session["clubid"], )).next(5)
|
|
"""
|
|
|
|
# rest = 0
|
|
# counted = 0
|
|
# event_list = []
|
|
# today = pendulum.now().date()
|
|
next_event_list = Event.objects.next(5)
|
|
|
|
# for event in next_event:
|
|
# counted = event.get_number_of_occurence_to_event(today)
|
|
# # print('pouf !')
|
|
|
|
# unavailabilities = Unavailability.objects.filter(datebegin__lte=event.datebegin.date(), dateend__gte=today)
|
|
# for unavailable in unavailabilities:
|
|
# counted -= unavailable.get_total_occurence()
|
|
|
|
# event_list.append((event, counted, int((counted/16)*100)))
|
|
|
|
return next_event_list
|
|
|
|
|
|
@login_required
|
|
def __getCourseInfo(request):
|
|
"""
|
|
Fonction `private` qui renvoie les informations relatives à une liste de cours :
|
|
cours, nombre de cours donnés, nombre de cours restant.
|
|
"""
|
|
rest = 0
|
|
counted = 0
|
|
courses = []
|
|
courses_done = 0
|
|
courses_left = 0
|
|
today = timezone.now().date()
|
|
# CourseList = Course.objects.filter(trainers__in=(request.user, ), club__in=(request.session["clubid"], )).order_by('iso_day_number', 'hour_begin')
|
|
CourseList = Course.objects.filter(trainers__in=(request.user,)).order_by(
|
|
"iso_day_number", "hour_begin"
|
|
)
|
|
for course in CourseList:
|
|
|
|
# Nombre de cours total sur la saison.
|
|
counted = course.get_total_occurence()
|
|
|
|
# Nombre de cours restant (à partir d'aujourd'hui)
|
|
rest = course.get_number_of_occurence_inbetween(today, True)
|
|
tmp = course.dateend.date() - today
|
|
if course.dateend.weekday() <= (today.weekday() + ((tmp.days + 1) % 7) % 7):
|
|
rest = int((tmp.days + 1) / 7) + 1
|
|
else:
|
|
rest = int((tmp.days + 1) / 7)
|
|
|
|
# # select tous les unavailables liés au cours
|
|
# unavailabilities = Unavailability.objects.filter(course=course)
|
|
# for unavailable in unavailabilities:
|
|
# tmp = unavailable.get_total_occurence()
|
|
# counted -= tmp
|
|
# rest -= tmp # si un unavailability.date < today, on soustrait quand même de rest ??? Si oui => BUG !!!!
|
|
|
|
courses_left += rest
|
|
courses_done += counted - rest
|
|
|
|
# courses.append((course, counted, (counted - rest)))
|
|
|
|
return courses, courses_done, courses_left
|
|
|
|
|
|
@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)
|
|
.. todo:: vérifier s'il y a des élèves qui devait participer à une compé-
|
|
tition (passée) pour laquelle il n'y a pas de points encodés. Si c'est le
|
|
cas, générer un popup. (le coach doit soit encoder les points soit suppri-
|
|
mer la participation de l'élève à l'event)
|
|
"""
|
|
today = pendulum.today().date()
|
|
try:
|
|
season = Season.objects.get(datebegin__lte=today, dateend__gte=today)
|
|
except Season.DoesNotExist:
|
|
context = {"error": "No season found."}
|
|
return render(request, "index.html", context)
|
|
except Season.MultipleObjectsReturned:
|
|
context = {"error": "Multiple season found."}
|
|
return render(request, "index.html", context)
|
|
|
|
week_number = season.week_number_from_begin(today)
|
|
|
|
# Afficher les 3 prochains cours.
|
|
weekdays_included = (today.weekday(), today.weekday() + 1, today.weekday() + 2)
|
|
courses_list = Course.objects.filter(trainers__in=(request.user,)).order_by(
|
|
"iso_day_number", "hour_begin"
|
|
)
|
|
# enlever les cours s'il sont repris dans des unavalability
|
|
|
|
event_list = __getEventInfo(request)
|
|
unavailable_list = Unavailability.objects.next(5)
|
|
birthday_list = next_birthdays(request, 5)
|
|
number_unreaded_message = get_number_of_unread_message(request)
|
|
courses, courses_done, courses_left = __getCourseInfo(request)
|
|
|
|
context = {
|
|
"week_number": week_number,
|
|
"number_of_courses": len(courses_list),
|
|
"courses_list": courses_list,
|
|
"event_list": event_list,
|
|
"birthday_list": birthday_list,
|
|
"unavailable_list": unavailable_list,
|
|
"courses_left": courses_left,
|
|
"donecourses": courses_done,
|
|
"today": today,
|
|
"number_unreaded_message": number_unreaded_message,
|
|
}
|
|
return render(request, "index.html", context)
|
|
|
|
|
|
@login_required
|
|
def birthdays_within(request, days):
|
|
"""
|
|
Renvoie la liste des gymnastes ayant leur anniversaires dans les `days` prochains jours.
|
|
"""
|
|
|
|
now = datetime.now()
|
|
then = now + timedelta(days)
|
|
|
|
# Build the list of month/day tuples.
|
|
monthdays = [(now.month, now.day)]
|
|
while now <= then:
|
|
monthdays.append((now.month, now.day))
|
|
now += timedelta(days=1)
|
|
|
|
# Tranform each into queryset keyword args.
|
|
monthdays = (
|
|
dict(zip(("birthdate__month", "birthdate__day"), t)) for t in monthdays
|
|
)
|
|
|
|
# Compose the djano.db.models.Q objects together for a single query.
|
|
query = reduce(operator.or_, (Q(**d) for d in monthdays))
|
|
|
|
# Run the query.
|
|
return Gymnast.objects.filter(query).order_by("birthdate")
|
|
|
|
|
|
@login_required
|
|
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
|
|
)[:5]
|
|
return birthday_list
|
|
|
|
|
|
@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:
|
|
event_list = Event.objects.filter(
|
|
name__icontains=pattern
|
|
) # ou gymnaste qui y participe !
|
|
gymnast_list = Gymnast.objects.filter(
|
|
Q(user__last_name__icontains=pattern)
|
|
| Q(user__first_name__icontains=pattern)
|
|
)
|
|
accident_list = Accident.objects.filter(
|
|
Q(gymnast__user__last_name__icontains=pattern)
|
|
| Q(gymnast__user__first_name__icontains=pattern)
|
|
)
|
|
skill_list = Skill.objects.filter(
|
|
Q(longLabel__icontains=pattern) | Q(shortLabel__icontains=pattern)
|
|
)
|
|
routine_list = Routine.objects.filter(
|
|
Q(longLabel__icontains=pattern) | Q(shortLabel__icontains=pattern)
|
|
)
|
|
|
|
context = {
|
|
"event_list": event_list,
|
|
"gymnast_list": gymnast_list,
|
|
"accident_list": accident_list,
|
|
"skill_list": skill_list,
|
|
"routine_list": routine_list,
|
|
}
|
|
else:
|
|
context = {}
|
|
|
|
return render(request, "results.html", context)
|