Here we go again...

This commit is contained in:
Fred Pauchet 2021-10-04 21:39:37 +02:00
parent fa6c6d531a
commit e56660e626
354 changed files with 1744 additions and 1908 deletions

View File

@ -232,7 +232,7 @@ single-line-if-stmt=no
[VARIABLES]
django-settings-module=khana.settings
django-settings-module=config.settings
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid defining new builtins when possible.

14
Makefile Normal file
View File

@ -0,0 +1,14 @@
# Makefile for khana
ifeq ($(shell which coverage >/dev/null 2>&1; echo $$?), 1)
$(error The 'coverage' command was not found. Make sure you have coverage installed)
endif
.PHONY: help coverage
help:
@echo " coverage to run coverage check of the source files."
coverage:
coverage run --source='.' manage.py test; coverage report; coverage html;
@echo "Testing of coverage in the sources finished."

View File

@ -16,19 +16,17 @@ import environ
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
env = environ.Env(
DEBUG=(bool, False)
)
env = environ.Env(DEBUG=(bool, False))
environ.Env.read_env()
DEBUG = env('DEBUG', default=True)
DEBUG = env("DEBUG", default=True)
SECRET_KEY = env('SECRET_KEY', default="6@9p0g-5ebcttbt$^*s4rda5!piezt6b7wj35g(+$mgz52k#d=")
SECRET_KEY = env(
"SECRET_KEY", default="6@9p0g-5ebcttbt$^*s4rda5!piezt6b7wj35g(+$mgz52k#d="
)
DATABASES = {
'default': env.db('DATABASE_URL', default='sqlite:///db.sqlite3')
}
DATABASES = {"default": env.db("DATABASE_URL", default="sqlite:///db.sqlite3")}
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
@ -45,14 +43,14 @@ INSTALLED_APPS = (
"django.contrib.messages",
"django.contrib.staticfiles",
"django_extensions",
"people",
"location",
"planning",
"objective",
"competition",
"profile",
"tools",
"communication",
"khana.people",
"khana.location",
"khana.planning",
"khana.objective",
"khana.competition",
"khana.profile",
"khana.tools",
"khana.communication",
"rest_framework",
)
@ -66,7 +64,7 @@ MIDDLEWARE = [
#'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = "khana.urls"
ROOT_URLCONF = "config.urls"
TEMPLATES = [
{
@ -122,4 +120,4 @@ DEBUG_TOOLBAR_CONFIG = {
"JQUERY_URL": STATIC_URL + "js/jquery-2.1.4.min.js",
}
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"

View File

@ -246,7 +246,8 @@ def search(request):
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)
Q(user__last_name__icontains=pattern)
| Q(user__first_name__icontains=pattern)
)
accident_list = Accident.objects.filter(
Q(gymnast__user__last_name__icontains=pattern)

View File

@ -9,6 +9,7 @@ from .models import Message
class MessageAdmin(admin.ModelAdmin):
"""La classe `MessageAdmin` contrôle la gestion des messages
"""
list_display = ("sender", "recipient", "written_at", "is_read", "read_at")
ordering = ("written_at", "sender")
search_fields = ("sender", "recipient", "message_title")

View File

@ -2,4 +2,4 @@ from django.apps import AppConfig
class CommunicationConfig(AppConfig):
name = "communication"
name = "khana.communication"

View File

@ -8,6 +8,7 @@ from .models import Message
class MessageForm(forms.ModelForm):
"""Formulaire de base pour la création et la modification de messages
"""
class Meta:
model = Message
fields = (

View File

@ -0,0 +1,63 @@
# Generated by Django 3.2.2 on 2021-05-13 10:58
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("communication", "0002_auto_20190413_1028"),
]
operations = [
migrations.RenameField(
model_name="message", old_name="message_body", new_name="body",
),
migrations.RenameField(
model_name="message", old_name="date_of_reading", new_name="read_at",
),
migrations.RenameField(
model_name="message", old_name="message_title", new_name="title",
),
migrations.RenameField(
model_name="message", old_name="date_of_writing", new_name="written_at",
),
migrations.RemoveField(model_name="message", name="is_read",),
migrations.RemoveField(model_name="message", name="reader",),
migrations.RemoveField(model_name="message", name="writer",),
migrations.AddField(
model_name="message",
name="content",
field=models.TextField(
blank=True,
help_text="Seul le MarkDown simple est accepté",
null=True,
verbose_name="Comments",
),
),
migrations.AddField(
model_name="message",
name="recipient",
field=models.ForeignKey(
default=1,
on_delete=django.db.models.deletion.CASCADE,
related_name="received_messages",
to="auth.user",
),
preserve_default=False,
),
migrations.AddField(
model_name="message",
name="sender",
field=models.ForeignKey(
default=1,
on_delete=django.db.models.deletion.CASCADE,
related_name="sent_messages",
to="auth.user",
),
preserve_default=False,
),
]

View File

@ -12,7 +12,7 @@ from datetime import datetime
from django.db import models
from django.contrib.auth import get_user_model
from base.models import Markdownizable
from khana.base.models import Markdownizable
User = get_user_model()
@ -33,13 +33,11 @@ class Message(Markdownizable):
sender = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="sent_messages"
)
written_at = models.DateTimeField(
auto_now_add=True, verbose_name="Date of writing"
)
recipient = models.ForeignKey(User, on_delete=models.CASCADE, related_name="received_messages")
read_at = models.DateTimeField(
auto_now=True, verbose_name="Date of reading"
written_at = models.DateTimeField(auto_now_add=True, verbose_name="Date of writing")
recipient = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="received_messages"
)
read_at = models.DateTimeField(auto_now=True, verbose_name="Date of reading")
title = models.CharField(max_length=255, verbose_name="Title")
body = models.TextField(null=True, blank=True, verbose_name="Message")

View File

@ -14,6 +14,6 @@ def test_message_to_string():
"""Vérifie la représentation textuelle d'un message
"""
timing = datetime.now()
user = User(username='fred', password='fredpassword')
user = User(username="fred", password="fredpassword")
message = Message(sender=user, written_at=timing, title="test")
assert str(message) == "fred - " + str(timing) + " : test"

View File

@ -0,0 +1,92 @@
"""Vues et fonctions pour tout ce qui touche à la communication entre plusieurs utilisateurs."""
from datetime import datetime
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.views.decorators.http import require_http_methods
from django.urls import reverse
from .forms import MessageForm
from .models import Message
@login_required
def get_number_of_unread_message(request):
"""Récupère le nombre de messages non lus associés à l'utilisateur en session.
"""
return (
Message.objects.filter(recipient=request.user)
.filter(read_at__isnull=True)
.count()
)
@login_required
@require_http_methods(["GET"])
def get_received_messages(request):
"""Récupère des messages recus pour l'utilisateur connecté.
"""
return request.user.received_messages.all()
@login_required
@require_http_methods(["GET"])
def get_sent_messages(request):
"""Récupère des messages envoyés par l'utilisateur connecté.
"""
return request.user.sent_messages.all()
@login_required
@require_http_methods(["GET"])
def get_message_details(request, messageid):
"""Récupère les détails (l'affichage ?) d'un message.
"""
message = get_object_or_404(Message, pk=messageid)
if not message.read_at and message.recipient == request.user.id:
message.read_at = datetime.now()
message.save()
context = {"message": message, "type": None}
return render(request, "message_details.html", context)
@login_required
@require_http_methods(["POST"])
def delete_message(request, messageid):
"""Supprime le message dont la clé est passée en paramètre.
"""
try:
message = Message.objects.get(pk=messageid)
if message.sender == request.user or message.recipient == request.user:
message.delete()
else:
return HttpResponse(401)
except:
return HttpResponse(400)
return HttpResponse(200)
@login_required
@require_http_methods(["GET", "POST"])
def compose_message(request):
"""Permet à l'utilisateur connecté de rédiger un nouveau message.
"""
if request.method == "POST":
form = MessageForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse("sent_messages"))
print("Invalid form")
else:
form = MessageForm()
context = {"form": form, "writer": request.user.id}
return render(request, "message_create.html", context)

View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class CompetitionConfig(AppConfig):
name = "khana.competition"

View File

@ -1,12 +1,7 @@
# coding=UTF-8
import pytest
from .models import (
Point,
Competition,
Division,
Level
)
from .models import Point, Competition, Division, Level
# class TestModelCompetition(TestCase):
@ -14,6 +9,7 @@ from .models import (
# Tests relatifs à la classe `Compétition`.
# """
def test_competition_str_():
""" Vérifie la représentation textuelle de la classe. """
competition = Competition(name="Belgian Open Trampoline", acronym="BOT")
@ -25,6 +21,7 @@ def test_competition_str_():
# Tests relatifs à la classe `Division`.
# """
def test_division_str_():
""" Vérifie la représentation textuelle de la classe. """
competition = Competition(name="Belgian Open Trampoline", acronym="BOT")
@ -37,6 +34,7 @@ def test_division_str_():
# Tests relatifs à la classe `Level`.
# """
def test_level_str_():
""" Vérifie la représentation textuelle de la classe. """
competition = Competition(name="Belgian Open Trampoline", acronym="BOT")

5
khana/location/apps.py Normal file
View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class LocationConfig(AppConfig):
name = "khana.location"

View File

@ -8,10 +8,7 @@ from ..models import Club, Country, Place
class TestCountry(TestCase):
def test_str_should_contain_name_and_iso2(self):
country = Country.objects.create(
nameus="Belgium",
namefr="Belgique",
isonum=56,
iso2="BE"
nameus="Belgium", namefr="Belgique", isonum=56, iso2="BE"
)
self.assertEqual(str(country), "Belgique (BE)")
@ -23,11 +20,8 @@ class TestPlace(TestCase):
name="Heaven",
postal=1080,
country=Country.objects.create(
nameus="Belgium",
namefr="Belgique",
isonum=56,
iso2="BE"
)
nameus="Belgium", namefr="Belgique", isonum=56, iso2="BE"
),
)
self.assertEqual(str(place), "Heaven (?)")
@ -41,12 +35,9 @@ class TestClub(TestCase):
name="Heaven",
postal=1080,
country=Country.objects.create(
nameus="Belgium",
namefr="Belgique",
isonum=56,
iso2="BE"
)
)
nameus="Belgium", namefr="Belgique", isonum=56, iso2="BE"
),
),
)
self.assertEqual(str(club), "RSCA (à ?)")
self.assertEqual(str(club), "RSCA (à ?)")

View File

@ -1,10 +1,6 @@
# coding=UTF-8
from .models import (
Club,
Place,
Country
)
from .models import Club, Place, Country
import pytest
# class GymnastTestCase():
@ -12,11 +8,13 @@ def test_country_tostring():
c = Country(namefr="Belgique", iso2="56")
assert str(c) == "Belgique (56)"
def test_place_tostring():
p = Place(name="FATC", city="Lillois")
assert str(p) == "FATC (Lillois)"
def test_club_tostring():
p = Place(name="FATC", city="Lillois")
club = Club(place=p, name="FATC2")
assert str(club) == "FATC2 (à Lillois)"
assert str(club) == "FATC2 (à Lillois)"

5
khana/objective/apps.py Normal file
View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class ObjectiveConfig(AppConfig):
name = "khana.objective"

View File

@ -6,13 +6,11 @@ from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('objective', '0015_auto_20190524_1211'),
("objective", "0015_auto_20190524_1211"),
]
operations = [
migrations.RenameField(
model_name='educative',
old_name='information',
new_name='content',
model_name="educative", old_name="information", new_name="content",
),
]

View File

@ -0,0 +1,75 @@
# Generated by Django 3.2.2 on 2021-06-20 16:18
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("objective", "0016_rename_information_educative_content"),
]
operations = [
migrations.RenameModel(old_name="Routine_Skill", new_name="RoutineSkill",),
migrations.AlterModelOptions(
name="educative",
options={
"ordering": ["label", "short_label"],
"verbose_name": "Educatif",
"verbose_name_plural": "Educatifs",
},
),
migrations.AlterModelOptions(
name="touchposition",
options={
"ordering": [
"label",
"short_label",
"is_default",
"allowed_in_competition",
],
"verbose_name": "Landing",
"verbose_name_plural": "Landings",
},
),
migrations.RenameField(
model_name="educative", old_name="ageBoy", new_name="age_boy",
),
migrations.RenameField(
model_name="educative", old_name="ageGirl", new_name="age_girl",
),
migrations.RenameField(
model_name="educative", old_name="educative", new_name="educatives",
),
migrations.RenameField(
model_name="educative", old_name="longLabel", new_name="label",
),
migrations.RenameField(
model_name="educative", old_name="prerequisite", new_name="prerequisites",
),
migrations.RenameField(
model_name="educative", old_name="shortLabel", new_name="short_label",
),
migrations.RenameField(
model_name="skill", old_name="rotationType", new_name="rotation_type",
),
migrations.RenameField(
model_name="skill",
old_name="simplyNotation",
new_name="simplified_notation",
),
migrations.RenameField(
model_name="touchposition",
old_name="competition",
new_name="allowed_in_competition",
),
migrations.RenameField(
model_name="touchposition", old_name="default", new_name="is_default",
),
migrations.RenameField(
model_name="touchposition", old_name="longLabel", new_name="label",
),
migrations.RenameField(
model_name="touchposition", old_name="shortLabel", new_name="short_label",
),
]

View File

@ -3,7 +3,7 @@
from datetime import date
from django.db import models
from django.db.models import Q
from base.models import Markdownizable
from khana.base.models import Markdownizable
from django.contrib.auth.models import User
@ -17,24 +17,24 @@ class Educative(Markdownizable):
verbose_name_plural = "Educatifs"
ordering = ["label", "short_label"] # 'level',
label = models.CharField(max_length = 255, verbose_name = "Long Name")
short_label = models.CharField(max_length = 255, verbose_name = "Short Name")
label = models.CharField(max_length=255, verbose_name="Long Name")
short_label = models.CharField(max_length=255, verbose_name="Short Name")
difficulty = models.DecimalField(
max_digits = 3, decimal_places = 1, verbose_name = "Difficulty"
max_digits=3, decimal_places=1, verbose_name="Difficulty"
)
level = models.PositiveSmallIntegerField(verbose_name = "Level", default = 0)
rank = models.PositiveSmallIntegerField(verbose_name = "Rank", default = 0)
level = models.PositiveSmallIntegerField(verbose_name="Level", default=0)
rank = models.PositiveSmallIntegerField(verbose_name="Rank", default=0)
educatives = models.ManyToManyField(
"self", related_name = "educativeOf", blank = True, symmetrical = False
"self", related_name="educativeOf", blank=True, symmetrical=False
)
prerequisites = models.ManyToManyField(
"self", related_name = "prerequisiteOf", blank = True, symmetrical = False
"self", related_name="prerequisiteOf", blank=True, symmetrical=False
)
age_boy = models.PositiveSmallIntegerField(
blank = True, null = True, verbose_name = "Boy's age"
blank=True, null=True, verbose_name="Boy's age"
)
age_girl = models.PositiveSmallIntegerField(
blank = True, null = True, verbose_name = "Girl's age"
blank=True, null=True, verbose_name="Girl's age"
)
def __str__(self):
@ -56,10 +56,10 @@ class TouchPosition(models.Model):
verbose_name_plural = "Landings"
ordering = ["label", "short_label", "is_default", "allowed_in_competition"]
label = models.CharField(max_length = 30, verbose_name = "Nom long")
short_label = models.CharField(max_length = 15, verbose_name = "Nom court")
allowed_in_competition = models.BooleanField(verbose_name = "Compétition")
is_default = models.BooleanField(verbose_name = "Défaut")
label = models.CharField(max_length=30, verbose_name="Nom long")
short_label = models.CharField(max_length=15, verbose_name="Nom court")
allowed_in_competition = models.BooleanField(verbose_name="Compétition")
is_default = models.BooleanField(verbose_name="Défaut")
def __str__(self):
return "%s" % (self.longLabel)
@ -104,29 +104,31 @@ class Skill(Educative):
(2, "Backward"),
)
position = models.CharField(max_length = 2, choices = POSITION_CHOICES)
position = models.CharField(max_length=2, choices=POSITION_CHOICES)
departure = models.ForeignKey(
TouchPosition,
related_name = "depart_of",
default = get_default_position,
verbose_name = "Take-off position",
on_delete = models.CASCADE,
related_name="depart_of",
default=get_default_position,
verbose_name="Take-off position",
on_delete=models.CASCADE,
)
landing = models.ForeignKey(
TouchPosition,
related_name = "landing_of",
default = get_default_position,
verbose_name = "Landing position",
on_delete = models.CASCADE,
related_name="landing_of",
default=get_default_position,
verbose_name="Landing position",
on_delete=models.CASCADE,
)
rotation_type = models.PositiveSmallIntegerField(
choices = ROTATION_CHOICES, verbose_name = "Type de rotation"
choices=ROTATION_CHOICES, verbose_name="Type de rotation"
)
rotation = models.PositiveSmallIntegerField(verbose_name = "1/4 de rotation")
twist = models.PositiveSmallIntegerField(verbose_name = "1/2 Vrille")
notation = models.CharField(max_length = 25)
simplified_notation = models.CharField(max_length = 25, verbose_name = "Notation simplifiée")
is_competitive = models.BooleanField(default = False)
rotation = models.PositiveSmallIntegerField(verbose_name="1/4 de rotation")
twist = models.PositiveSmallIntegerField(verbose_name="1/2 Vrille")
notation = models.CharField(max_length=25)
simplified_notation = models.CharField(
max_length=25, verbose_name="Notation simplifiée"
)
is_competitive = models.BooleanField(default=False)
# importance = models.PositiveSmallIntegerField(default = 1)
def __str__(self):
@ -144,9 +146,9 @@ class Routine(Educative):
active = models.BooleanField()
jumps = models.ManyToManyField(
Skill, through = "RoutineSkill", verbose_name = "routine"
Skill, through="RoutineSkill", verbose_name="routine"
) # ceci n'est pas un vrai champ
is_competitive = models.BooleanField(default = False)
is_competitive = models.BooleanField(default=False)
def __str__(self):
return "%s (%s)" % (self.label, self.short_label)
@ -216,10 +218,10 @@ class RoutineSkill(models.Model):
ordering = ("rank",)
routine = models.ForeignKey(
Routine, on_delete = models.CASCADE, default = None, related_name = "skill_links"
Routine, on_delete=models.CASCADE, default=None, related_name="skill_links"
)
skill = models.ForeignKey(
Skill, on_delete = models.CASCADE, default = None, related_name = "routine_links"
Skill, on_delete=models.CASCADE, default=None, related_name="routine_links"
)
rank = models.PositiveSmallIntegerField()
@ -247,13 +249,13 @@ class Chrono(models.Model):
(99, "Other"),
)
routine = models.ForeignKey(Routine, on_delete = models.CASCADE, default = None)
routine_type = models.PositiveSmallIntegerField(choices = ROUTINETYPE_CHOICE)
routine = models.ForeignKey(Routine, on_delete=models.CASCADE, default=None)
routine_type = models.PositiveSmallIntegerField(choices=ROUTINETYPE_CHOICE)
gymnast = models.ForeignKey(
"people.gymnast", on_delete = models.CASCADE, default = None
"people.gymnast", on_delete=models.CASCADE, default=None
)
date = models.DateField(default = date.today, verbose_name = "Date")
score = models.DecimalField(max_digits = 5, decimal_places = 2)
date = models.DateField(default=date.today, verbose_name="Date")
score = models.DecimalField(max_digits=5, decimal_places=2)
def __str__(self):
return "%s le %s : %s pour %s" % (
@ -278,13 +280,13 @@ class Evaluation(models.Model):
Classe permettant l'évaluation des éducatifs.
"""
date = models.DateField(default = date.today, verbose_name = "Date")
value = models.PositiveSmallIntegerField(default = 0)
date = models.DateField(default=date.today, verbose_name="Date")
value = models.PositiveSmallIntegerField(default=0)
educative = models.ForeignKey(
Educative,
related_name = "depart_of",
verbose_name = "Take-off position",
on_delete = models.CASCADE,
related_name="depart_of",
verbose_name="Take-off position",
on_delete=models.CASCADE,
)
type_of_evaluator = models.BooleanField(default = 0)
evaluator = models.ForeignKey(User, null = True, on_delete = models.SET_NULL)
type_of_evaluator = models.BooleanField(default=0)
evaluator = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)

View File

@ -42,11 +42,7 @@ routine_urlpatterns = [
views.delete_skill_from_routine,
name="delete_skill_from_routine",
),
path(
r"suggest/",
views.suggest_routine,
name="suggest_routine",
)
path(r"suggest/", views.suggest_routine, name="suggest_routine",),
]
# Chrono

View File

@ -338,7 +338,9 @@ def random_skill(request, skill_quantity=20, is_competitive=True):
number_of_skill = skillid_list.count()
selected_skillid_list = [
skillid_list[x]["id"]
for x in [random.randrange(0, number_of_skill, 1) for i in range(skill_quantity)]
for x in [
random.randrange(0, number_of_skill, 1) for i in range(skill_quantity)
]
]
skill_list = Skill.objects.filter(id__in=selected_skillid_list)
@ -387,12 +389,14 @@ def __construct_routine(
if current_routine:
skill_list = Skill.objects.filter(
departure = current_routine[-1].landing
) # , difficulty__lte = total_difficulty_score
departure=current_routine[-1].landing
) # , difficulty__lte = total_difficulty_score
if len(current_routine) == (max_routine_length - 1):
skill_list = skill_list.filter(landing__longLabel="Debout")
if logic and current_routine[-1].landing.longLabel == "Debout":
skill_list = skill_list.exclude(rotationType = current_routine[-1].rotationType)
skill_list = skill_list.exclude(
rotationType=current_routine[-1].rotationType
)
else:
skill_list = Skill.objects.filter(departure__longLabel="Debout")
@ -404,23 +408,31 @@ def __construct_routine(
min_diff_skill = total_difficulty_score
max_diff_skill = total_difficulty_score + 3
else:
if math.ceil(total_difficulty_score / max_routine_length) <= max_skill_difficulty:
min_diff_skill = math.ceil(max((total_difficulty_score / max_routine_length) - 5, 0))
if (
math.ceil(total_difficulty_score / max_routine_length)
<= max_skill_difficulty
):
min_diff_skill = math.ceil(
max((total_difficulty_score / max_routine_length) - 5, 0)
)
else:
return
if (math.ceil(total_difficulty_score / max_routine_length) + 2) <= max_skill_difficulty:
max_diff_skill = math.ceil(total_difficulty_score / max_routine_length) + 2
if (
math.ceil(total_difficulty_score / max_routine_length) + 2
) <= max_skill_difficulty:
max_diff_skill = (
math.ceil(total_difficulty_score / max_routine_length) + 2
)
else:
return
skill_list = skill_list.filter(
difficulty__gte = (min_diff_skill / 10),
difficulty__lte = (max_diff_skill / 10)
difficulty__gte=(min_diff_skill / 10), difficulty__lte=(max_diff_skill / 10)
)
if gymnast:
skill_list = skill_list.filter(cando__gymnast = gymnast)
skill_list = skill_list.filter(cando__gymnast=gymnast)
for skill in skill_list:
current_routine.append(skill)
@ -429,7 +441,9 @@ def __construct_routine(
current_routine,
max_routine_length,
max_skill_difficulty,
total_difficulty_score - (skill.difficulty * 10) if total_difficulty_score is not None else None,
total_difficulty_score - (skill.difficulty * 10)
if total_difficulty_score is not None
else None,
competition,
logic,
gymnast,
@ -442,7 +456,7 @@ def __construct_routine(
def suggest_routine(
request,
max_routine_length = 2,
max_routine_length=2,
total_difficulty_score=None,
competition=True,
logic=True,
@ -471,24 +485,32 @@ def suggest_routine(
total_difficulty_score = 26
if gymnast:
max_skill_difficulty = Educative.objects.values('difficulty').filter(cando__gymnast=gymnast).order_by(
"-difficulty"
)[:1][0]["difficulty"] * 10
max_skill_difficulty = (
Educative.objects.values("difficulty")
.filter(cando__gymnast=gymnast)
.order_by("-difficulty")[:1][0]["difficulty"]
* 10
)
else:
max_skill_difficulty = Skill.objects.values('difficulty').order_by("-difficulty")[:1][0]["difficulty"] * 10
max_skill_difficulty = (
Skill.objects.values("difficulty").order_by("-difficulty")[:1][0][
"difficulty"
]
* 10
)
# difficulty_scores = range(5, 45, 5)
# for total_difficulty_score in difficulty_scores:
# print("===============================================================================================")
__construct_routine(
routine,
max_routine_length,
max_skill_difficulty,
total_difficulty_score,
competition,
logic,
gymnast,
)
routine,
max_routine_length,
max_skill_difficulty,
total_difficulty_score,
competition,
logic,
gymnast,
)
# print(routines)

127
khana/people/admin.py Normal file
View File

@ -0,0 +1,127 @@
"""Administration des gymnastes et des personnes.
Remarks:
* Je ne pense pas qu'il faille encore passer par `ForeignKeyAutocompleteAdmin`.
https://docs.djangoproject.com/fr/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.autocomplete_fields
"""
from django.contrib import admin
from django_extensions.admin import ForeignKeyAutocompleteAdmin
from .models import (
Gymnast,
Accident,
CanDoRelation,
ToDoRelation,
GymnastHasRoutine,
)
class CanDoRelationAdmin(ForeignKeyAutocompleteAdmin):
model = CanDoRelation
list_display = ("date", "gymnast", "educative")
list_filter = ("gymnast",)
search_fields = ("gymnast", "educative")
autocomplete_fields = ("gymnast",)
# related_search_fields = {
# 'gymnast': ('lastname', 'firstname'),
# }
class InlineCanDoRelation(admin.TabularInline):
model = CanDoRelation
class ToDoRelationAdmin(ForeignKeyAutocompleteAdmin):
model = ToDoRelation
list_display = ("date", "gymnast", "educative")
list_filter = ("gymnast",)
search_fields = ("gymnast", "educative")
autocomplete_fields = ("gymnast",)
# related_search_fields = {
# 'gymnast': ('lastname', 'firstname'),
# # 'educative': ('longLabel', 'shortLabel'), # TO_FRED : Pq ca marche pas ca ?
# }
class GymnastHasRoutineAdmin(ForeignKeyAutocompleteAdmin):
model = GymnastHasRoutine
list_display = ("gymnast", "routine", "routine_type", "datebegin", "dateend")
list_filter = ("gymnast", "routine_type")
search_fields = ("gymnast", "routine")
autocomplete_fields = ("gymnast", "routine")
class InlineToDoRelation(admin.TabularInline):
model = ToDoRelation
class GymnastAdmin(admin.ModelAdmin):
model = Gymnast
def lastname(self, obj):
return obj.user.last_name
def firstname(self, obj):
return obj.user.first_name
def email(self, obj):
return obj.user.email
def is_active(self, obj):
return obj.user.is_active
fields = (
# "lastname",
# "firstname",
"birthdate",
"gender",
"club",
"niss",
"address",
"postal",
"city",
"phone",
"gsm",
# "user__email",
"fedid",
"year_of_practice",
"gsm_mother",
"email_mother",
"gsm_father",
"email_father",
# "user.is_active",
"orientation",
"trainer",
"picture",
"content",
)
list_display = ("lastname", "firstname", "birthdate", "age", "is_active")
list_filter = ("gender", "user__is_active")
search_fields = ("lastname", "firstname", "email")
inlines = [InlineToDoRelation, InlineCanDoRelation]
autocomplete_fields = ("club",)
class AccidentAdmin(admin.ModelAdmin):
model = Accident
fields = ("date", "gymnast", "educative", "information")
list_display = ("date", "gymnast", "educative")
list_filter = ("date",)
search_fields = ("date", "gymnast", "educative")
autocomplete_fields = ["gymnast", "educative"]
admin.site.register(Gymnast, GymnastAdmin)
admin.site.register(Accident, AccidentAdmin)
admin.site.register(CanDoRelation, CanDoRelationAdmin)
admin.site.register(ToDoRelation, ToDoRelationAdmin)
admin.site.register(GymnastHasRoutine, GymnastHasRoutineAdmin)

5
khana/people/apps.py Normal file
View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class PeopleConfig(AppConfig):
name = "khana.people"

174
khana/people/forms.py Normal file
View File

@ -0,0 +1,174 @@
"""Formulaires de gestion des données entrantes pour les gymnastes et accidents."""
from django import forms
from .models import (
Accident,
Gymnast,
GymnastHasRoutine,
)
from django.contrib.auth.models import User
class AccidentForm(forms.ModelForm):
class Meta:
model = Accident
fields = ("gymnast", "educative", "date", "content")
widgets = {
"date": forms.DateInput(
attrs={
"class": "form-control datepicker",
# "value": date.today().strftime("%Y-%m-%d"),
}
),
"gymnast": forms.HiddenInput(),
"educative": forms.HiddenInput(),
"content": forms.Textarea(
attrs={
"class": "form-control",
"placeholder": "Informations about accident: context (why, where, …), consequencies, …",
}
),
}
gymnast_related = forms.CharField(
widget=forms.TextInput(
attrs={
"class": "form-control",
"placeholder": "Searching gymnast…",
"data-ref": "#id_gymnast",
}
)
)
educative_related = forms.CharField(
widget=forms.TextInput(
attrs={
"class": "form-control",
"placeholder": "Searching skill…",
"data-ref": "#id_educative",
}
)
)
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = (
"last_name",
"first_name",
"email",
"is_active",
"username",
)
class GymnastForm(forms.ModelForm):
lastname = forms.CharField(
widget=forms.TextInput(
attrs={"class": "form-control", "placeholder": "Lastname"}
)
)
firstname = forms.CharField(
widget=forms.TextInput(
attrs={"class": "form-control", "placeholder": "Firstname"}
)
)
email = forms.EmailField()
# is_active = forms.CheckboxInput()
class Meta:
model = Gymnast
fields = (
"id",
"birthdate",
"gender",
"address",
"postal",
"city",
"phone",
"gsm",
"gsm_main_responsible",
"email_main_responsible",
"gsm_second_responsible",
"email_second_responsible",
"orientation",
"picture",
"content",
)
widgets = {
"id": forms.HiddenInput(),
"lastname": forms.TextInput(
attrs={"class": "form-control", "placeholder": "Lastname"}
),
"firstname": forms.TextInput(
attrs={"class": "form-control", "placeholder": "Firstname"}
),
"birthdate": forms.DateInput(attrs={"class": "form-control datepicker"}),
"gender": forms.Select(attrs={"class": "form-control"}),
"address": forms.TextInput(attrs={"class": "form-control"}),
"postal": forms.TextInput(attrs={"class": "form-control"}),
"city": forms.TextInput(attrs={"class": "form-control"}),
"phone": forms.TextInput(attrs={"class": "form-control"}),
"gsm": forms.TextInput(attrs={"class": "form-control"}),
"email": forms.EmailInput(attrs={"class": "form-control"}),
"gsm_main_responsible": forms.TextInput(attrs={"class": "form-control"}),
"email_main_responsible": forms.EmailInput(attrs={"class": "form-control"}),
"gsm_second_responsible": forms.TextInput(attrs={"class": "form-control"}),
"email_second_responsible": forms.EmailInput(
attrs={"class": "form-control"}
),
# "is_active": forms.CheckboxInput(
# attrs={
# "class": "bootstrap-switch mt-0",
# "data-on-label": "<i class='tim-icons icon-check-2 text-success'></i>",
# "data-off-label": "<i class='tim-icons icon-simple-remove text-danger'></i>",
# }
# ),
"orientation": forms.Select(attrs={"class": "form-control"}),
"picture": forms.Select(attrs={"class": "form-control"}),
"content": forms.Textarea(
attrs={
"class": "form-control",
"placeholder": "Informations about the gymnast.",
}
),
}
class GymnastHasRoutineForm(forms.ModelForm):
"""
"""
class Meta:
model = GymnastHasRoutine
fields = ("gymnast", "routine", "routine_type", "datebegin", "dateend")
widgets = {
"gymnast": forms.HiddenInput(),
"routine": forms.HiddenInput(),
"routine_type": forms.Select(attrs={"class": "form-control"}),
"datebegin": forms.DateInput(attrs={"class": "form-control datepicker",}),
"dateend": forms.DateInput(attrs={"class": "form-control datepicker",}),
}
gymnast_related = forms.CharField(
widget=forms.TextInput(
attrs={
"class": "form-control",
"placeholder": "Searching gymnast…",
"data-ref": "#id_gymnast",
}
)
)
routine_related = forms.CharField(
widget=forms.TextInput(
attrs={
"class": "form-control",
"placeholder": "Searching routine…",
"data-ref": "#id_routine",
}
)
)

Some files were not shown because too many files have changed in this diff Show More