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)