Merge branch 'master' of grimbox.be:Sulley/khana
This commit is contained in:
commit
787ba706aa
49
.pylintrc
49
.pylintrc
|
@ -3,17 +3,22 @@
|
||||||
# A comma-separated list of package or module names from where C extensions may
|
# A comma-separated list of package or module names from where C extensions may
|
||||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||||
# run arbitrary code.
|
# run arbitrary code.
|
||||||
|
extension-pkg-allow-list=
|
||||||
|
|
||||||
|
# A comma-separated list of package or module names from where C extensions may
|
||||||
|
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||||
|
# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
|
||||||
|
# for backward compatibility.)
|
||||||
extension-pkg-whitelist=
|
extension-pkg-whitelist=
|
||||||
|
|
||||||
# Specify a score threshold to be exceeded before program exits with error.
|
# Specify a score threshold to be exceeded before program exits with error.
|
||||||
fail-under=10.0
|
fail-under=10.0
|
||||||
|
|
||||||
# Add files or directories to the blacklist. They should be base names, not
|
# Files or directories to be skipped. They should be base names, not paths.
|
||||||
# paths.
|
|
||||||
ignore=CVS
|
ignore=CVS
|
||||||
|
|
||||||
# Add files or directories matching the regex patterns to the blacklist. The
|
# Files or directories matching the regex patterns are skipped. The regex
|
||||||
# regex matches against base names, not paths.
|
# matches against base names, not paths.
|
||||||
ignore-patterns=
|
ignore-patterns=
|
||||||
|
|
||||||
# Python code to execute, usually for sys.path manipulation such as
|
# Python code to execute, usually for sys.path manipulation such as
|
||||||
|
@ -181,7 +186,7 @@ max-nested-blocks=5
|
||||||
# inconsistent-return-statements if a never returning function is called then
|
# inconsistent-return-statements if a never returning function is called then
|
||||||
# it will be considered as an explicit return statement and no message will be
|
# it will be considered as an explicit return statement and no message will be
|
||||||
# printed.
|
# printed.
|
||||||
never-returning-functions=sys.exit
|
never-returning-functions=sys.exit,argparse.parse_error
|
||||||
|
|
||||||
|
|
||||||
[STRING]
|
[STRING]
|
||||||
|
@ -227,6 +232,8 @@ single-line-if-stmt=no
|
||||||
|
|
||||||
[VARIABLES]
|
[VARIABLES]
|
||||||
|
|
||||||
|
django-settings-module=khana.settings
|
||||||
|
|
||||||
# List of additional names supposed to be defined in builtins. Remember that
|
# List of additional names supposed to be defined in builtins. Remember that
|
||||||
# you should avoid defining new builtins when possible.
|
# you should avoid defining new builtins when possible.
|
||||||
additional-builtins=
|
additional-builtins=
|
||||||
|
@ -234,6 +241,9 @@ additional-builtins=
|
||||||
# Tells whether unused global variables should be treated as a violation.
|
# Tells whether unused global variables should be treated as a violation.
|
||||||
allow-global-unused-variables=yes
|
allow-global-unused-variables=yes
|
||||||
|
|
||||||
|
# List of names allowed to shadow builtins
|
||||||
|
allowed-redefined-builtins=
|
||||||
|
|
||||||
# List of strings which can identify a callback function by name. A callback
|
# List of strings which can identify a callback function by name. A callback
|
||||||
# name must start or end with one of those strings.
|
# name must start or end with one of those strings.
|
||||||
callbacks=cb_,
|
callbacks=cb_,
|
||||||
|
@ -367,6 +377,13 @@ class-attribute-naming-style=any
|
||||||
# attribute-naming-style.
|
# attribute-naming-style.
|
||||||
#class-attribute-rgx=
|
#class-attribute-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct class constant names.
|
||||||
|
class-const-naming-style=UPPER_CASE
|
||||||
|
|
||||||
|
# Regular expression matching correct class constant names. Overrides class-
|
||||||
|
# const-naming-style.
|
||||||
|
#class-const-rgx=
|
||||||
|
|
||||||
# Naming style matching correct class names.
|
# Naming style matching correct class names.
|
||||||
class-naming-style=PascalCase
|
class-naming-style=PascalCase
|
||||||
|
|
||||||
|
@ -455,9 +472,13 @@ variable-naming-style=snake_case
|
||||||
max-spelling-suggestions=4
|
max-spelling-suggestions=4
|
||||||
|
|
||||||
# Spelling dictionary name. Available dictionaries: none. To make it work,
|
# Spelling dictionary name. Available dictionaries: none. To make it work,
|
||||||
# install the python-enchant package.
|
# install the 'python-enchant' package.
|
||||||
spelling-dict=
|
spelling-dict=
|
||||||
|
|
||||||
|
# List of comma separated words that should be considered directives if they
|
||||||
|
# appear and the beginning of a comment and should not be checked.
|
||||||
|
spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
|
||||||
|
|
||||||
# List of comma separated words that should not be checked.
|
# List of comma separated words that should not be checked.
|
||||||
spelling-ignore-words=
|
spelling-ignore-words=
|
||||||
|
|
||||||
|
@ -519,6 +540,9 @@ min-public-methods=2
|
||||||
|
|
||||||
[CLASSES]
|
[CLASSES]
|
||||||
|
|
||||||
|
# Warn about protected attribute access inside special methods
|
||||||
|
check-protected-access-in-special-methods=no
|
||||||
|
|
||||||
# List of method names used to declare (i.e. assign) instance attributes.
|
# List of method names used to declare (i.e. assign) instance attributes.
|
||||||
defining-attr-methods=__init__,
|
defining-attr-methods=__init__,
|
||||||
__new__,
|
__new__,
|
||||||
|
@ -557,16 +581,17 @@ analyse-fallback-blocks=no
|
||||||
# Deprecated modules which should not be used, separated by a comma.
|
# Deprecated modules which should not be used, separated by a comma.
|
||||||
deprecated-modules=optparse,tkinter.tix
|
deprecated-modules=optparse,tkinter.tix
|
||||||
|
|
||||||
# Create a graph of external dependencies in the given file (report RP0402 must
|
# Output a graph (.gv or any supported image format) of external dependencies
|
||||||
# not be disabled).
|
# to the given file (report RP0402 must not be disabled).
|
||||||
ext-import-graph=
|
ext-import-graph=
|
||||||
|
|
||||||
# Create a graph of every (i.e. internal and external) dependencies in the
|
# Output a graph (.gv or any supported image format) of all (i.e. internal and
|
||||||
# given file (report RP0402 must not be disabled).
|
# external) dependencies to the given file (report RP0402 must not be
|
||||||
|
# disabled).
|
||||||
import-graph=
|
import-graph=
|
||||||
|
|
||||||
# Create a graph of internal dependencies in the given file (report RP0402 must
|
# Output a graph (.gv or any supported image format) of internal dependencies
|
||||||
# not be disabled).
|
# to the given file (report RP0402 must not be disabled).
|
||||||
int-import-graph=
|
int-import-graph=
|
||||||
|
|
||||||
# Force import order to recognize a module as part of the standard
|
# Force import order to recognize a module as part of the standard
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
black==19.10b0
|
black==19.10b0
|
||||||
coverage==5.5
|
coverage==5.5
|
||||||
flake8==3.9.1
|
flake8==3.9.1
|
||||||
|
pylint==2.8.2
|
||||||
|
pylint-django==2.4.4
|
||||||
django-spaghetti-and-meatballs==0.4.2
|
django-spaghetti-and-meatballs==0.4.2
|
||||||
docutils==0.16
|
docutils==0.16
|
||||||
pytest==6.2.4
|
pytest==6.2.4
|
||||||
|
|
|
@ -11,6 +11,6 @@ class TestMarkdownizable(TestCase):
|
||||||
|
|
||||||
def test_to_markdown(self):
|
def test_to_markdown(self):
|
||||||
"""Vérifie qu'un contenu Markdown est correctement convertit en HTML."""
|
"""Vérifie qu'un contenu Markdown est correctement convertit en HTML."""
|
||||||
m = Markdownizable(information="# Title")
|
markdown_content = Markdownizable(information="# Title")
|
||||||
|
|
||||||
self.assertEqual(m.to_markdown(), "<h1>Title</h1>")
|
self.assertEqual(markdown_content.to_markdown(), "<h1>Title</h1>")
|
||||||
|
|
|
@ -7,6 +7,8 @@ from .models import Message
|
||||||
|
|
||||||
@admin.register(Message)
|
@admin.register(Message)
|
||||||
class MessageAdmin(admin.ModelAdmin):
|
class MessageAdmin(admin.ModelAdmin):
|
||||||
|
"""La classe `MessageAdmin` contrôle la gestion des messages
|
||||||
|
"""
|
||||||
list_display = ("sender", "recipient", "written_at", "is_read", "read_at")
|
list_display = ("sender", "recipient", "written_at", "is_read", "read_at")
|
||||||
ordering = ("written_at", "sender")
|
ordering = ("written_at", "sender")
|
||||||
search_fields = ("sender", "recipient", "message_title")
|
search_fields = ("sender", "recipient", "message_title")
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
"""Configuration et représentation des forms liés aux messages."""
|
"""Configuration et représentation des forms liés aux messages."""
|
||||||
|
|
||||||
from datetime import date
|
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from people.models import Gymnast
|
|
||||||
from .models import Message
|
from .models import Message
|
||||||
|
|
||||||
|
|
||||||
class MessageForm(forms.ModelForm):
|
class MessageForm(forms.ModelForm):
|
||||||
|
"""Formulaire de base pour la création et la modification de messages
|
||||||
|
"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Message
|
model = Message
|
||||||
fields = (
|
fields = (
|
||||||
|
|
|
@ -1,10 +1,23 @@
|
||||||
|
"""Modelisation de tout ce qui touche à la communication entre utilisateurs.
|
||||||
|
|
||||||
|
Cette application gère:
|
||||||
|
|
||||||
|
* Les messages
|
||||||
|
* Ah, c'est tout en fait :-)
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
from base.models import Markdownizable
|
from base.models import Markdownizable
|
||||||
|
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class Message(Markdownizable):
|
class Message(Markdownizable):
|
||||||
"""Représente un message échangé entre deux utilisateurs.
|
"""Représente un message échangé entre deux utilisateurs.
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
# coding=UTF-8
|
"""Tests liés au modèle de l'application Communication"""
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from .models import Message
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
def test_message_tostring():
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
|
from .models import Message
|
||||||
|
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
def test_message_to_string():
|
||||||
|
"""Vérifie la représentation textuelle d'un message
|
||||||
|
"""
|
||||||
timing = datetime.now()
|
timing = datetime.now()
|
||||||
u = User(username='fred', password='fredpassword')
|
user = User(username='fred', password='fredpassword')
|
||||||
m = Message(sender=u, written_at=timing, title="test")
|
message = Message(sender=user, written_at=timing, title="test")
|
||||||
assert str(m) == "fred - " + str(timing) + " : test"
|
assert str(message) == "fred - " + str(timing) + " : test"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Définition des routes d'actions permettant de contrôler les messages et la communication."""
|
"""Définition des routes d'actions permettant de contrôler les messages et la communication."""
|
||||||
|
|
||||||
from django.urls import path, re_path
|
from django.urls import path
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
"""Vues et fonctions pour tout ce qui touche à la communication entre plusieurs utilisateurs."""
|
"""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.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.http import HttpResponse, HttpResponseRedirect
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
from django.shortcuts import render, get_object_or_404
|
from django.shortcuts import render, get_object_or_404
|
||||||
from django.views.decorators.http import require_http_methods
|
from django.views.decorators.http import require_http_methods
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from .forms import MessageForm
|
from .forms import MessageForm
|
||||||
from .models import Message
|
from .models import Message
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def get_number_of_unread_message(request):
|
def get_number_of_unread_message(request):
|
||||||
"""Récupère le nombre de messages non lus associés à l'utilisateur en session.
|
"""Récupère le nombre de messages non lus associés à l'utilisateur en session.
|
||||||
|
@ -103,7 +104,7 @@ def compose_message(request):
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
return HttpResponseRedirect(reverse("sent_messages"))
|
return HttpResponseRedirect(reverse("sent_messages"))
|
||||||
else:
|
|
||||||
print("Invalid form")
|
print("Invalid form")
|
||||||
else:
|
else:
|
||||||
form = MessageForm()
|
form = MessageForm()
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
# Application `Planning`
|
# Application `Planning`
|
||||||
|
|
||||||
## Saison
|
## Saison
|
||||||
|
|
||||||
Une saison est déinie par :
|
Une saison est déinie par :
|
||||||
|
|
||||||
- un id,
|
- un id,
|
||||||
- un label,
|
- un label,
|
||||||
- une date de début et
|
- une date de début et
|
||||||
|
@ -11,9 +13,12 @@ La date de début est très souvent le : 01/09/xxxx
|
||||||
La date de fin est très souvent le : 31/08/xxxy
|
La date de fin est très souvent le : 31/08/xxxy
|
||||||
Exemple : 1/9/2015 - 31/8/2016
|
Exemple : 1/9/2015 - 31/8/2016
|
||||||
|
|
||||||
|
NOTE: Le fait que la date de début soit **très souvent** le 01 septembre indique sans doute une date par défaut (modifiable) au niveau du modèle. Idem pour la date de fin.
|
||||||
|
|
||||||
|
NOTE: je ne comprends pas la méthode `week_number_from_begin`. Si cela fait référence à la date de début, alors il faut le mentionner dans le nom de la fonction.
|
||||||
|
|
||||||
## Course
|
## Course
|
||||||
|
|
||||||
Un cours est un ensemble d'entraînements (`training`) (récurrents ?) défini par :
|
Un cours est un ensemble d'entraînements (`training`) (récurrents ?) défini par :
|
||||||
- une heure de début et une heure de fin,
|
- une heure de début et une heure de fin,
|
||||||
- une date de début et une date de fin
|
- une date de début et une date de fin
|
||||||
|
@ -26,16 +31,32 @@ Réflexions/questions :
|
||||||
- les cours devraient-ils être liés à une saison ?
|
- les cours devraient-ils être liés à une saison ?
|
||||||
- un cours est considéré comme donné hebdomadairement entre la date de début et la date de fin (hérite de la classe `Temporizable`), mais est-ce une bonne idée ? Est-ce une bonne manière de faire ?
|
- un cours est considéré comme donné hebdomadairement entre la date de début et la date de fin (hérite de la classe `Temporizable`), mais est-ce une bonne idée ? Est-ce une bonne manière de faire ?
|
||||||
|
|
||||||
|
NOTE: Je dirais que oui. D'un côté, tu n'aurais pas de possibilité de déduction entre un cours et le moment où il y a réellement lieu - de ce que je comprends, le *cours* correspond en fait à quelque chose qui est prévu selon une récurrence donnée - eg. "tous les mardis (deuxième jour de la semaine), entre 10h et 12h, avec Machin, Chose et Brol".
|
||||||
|
La *saison* va juste indiquer la date de début et de fin des cours qui y sont liés.
|
||||||
|
|
||||||
|
Même s'il y a moyen de le représenter différement, je pense surtout que le concept de saison parle à beaucoup de monde.
|
||||||
|
|
||||||
|
NOTE: la réflexion va surtout être "est-ce qu'un cours est différent entre deux saison ?" A priori, oui, puisque Bidule peut devenir entraineur pour la saison 2020-2021.
|
||||||
|
|
||||||
|
L'avantage, c'est que Machin pourrait se connecter sur son profil et dire "ah ouais, cette année, je donne cours le jeudi et le samedi."
|
||||||
|
|
||||||
## Training
|
## Training
|
||||||
|
|
||||||
Un entraînement est une occurence d'un cours pendant lequel des gmnastes sont présents.
|
Un entraînement est une occurence d'un cours pendant lequel des gmnastes sont présents.
|
||||||
|
|
||||||
Un objet de cette classe lie donc :
|
Un objet de cette classe lie donc :
|
||||||
|
|
||||||
- un cours,
|
- un cours,
|
||||||
- gymnaste et
|
- des gymnastes présents et
|
||||||
- une date.
|
- une date.
|
||||||
|
|
||||||
|
NOTE: Techniquement, tu peux ici mettre une contrainte ou un avertissement si l'entrainement est situé à une date différente de ce que la saison devrait autoriser.
|
||||||
|
|
||||||
|
NOTE: dans la classe Training, il est question d'une `ForeignKey` vers Gymnast, mais ce devrait être un ManyToManyField.
|
||||||
|
|
||||||
|
NOTE: De la même manière, je reprendrais aussi l'heure de début et de fin. Entre ce qui est prévu (le cours) et la réalité (l'entraintement), il pourrait y avoir des différences.
|
||||||
|
|
||||||
|
Cela permettrait aussi de planifier les cours - dire en gros que, en début d'année, tu (l'appli) planifies les jours fériés, et *projette* les entrainements pour la saison, sur base de ce qui est prévu.
|
||||||
|
|
||||||
|
|
||||||
## Round
|
## Round
|
||||||
|
@ -43,6 +64,10 @@ Un objet de cette classe lie donc :
|
||||||
Classe représentant les passages des élèves lors d'un entrainement.
|
Classe représentant les passages des élèves lors d'un entrainement.
|
||||||
Chaque record représente un passage. Il est donc lié à un record de la classe `Training`.
|
Chaque record représente un passage. Il est donc lié à un record de la classe `Training`.
|
||||||
|
|
||||||
|
NOTE: Est-ce qu'il est important de savoir qui est l'entraineur qui a donné une évaluation ?
|
||||||
|
|
||||||
|
NOTE: au niveau du round, il y a un ensemble d'informations chronologiques: `nb_of_realisations` (au pluriel...), `nb_of_success`, ... mais c'est incohérent avec le `round_number`, puisque je suppose qu'il pourrait faire un tour de A, puis B, puis revenir à A.
|
||||||
|
Cette partie-ci me semble très complexe - sans oublier qu'il va falloir la remplir: si tes entraineurs chipotent sur une tablette ou sur un écran pour chaque action que réalise un gymnaste, ça va pas être sympa pour eux.
|
||||||
|
|
||||||
|
|
||||||
## Group
|
## Group
|
||||||
|
@ -50,6 +75,11 @@ Chaque record représente un passage. Il est donc lié à un record de la classe
|
||||||
Classe représentant les groupes (Loisir, D1, D2, A, B, …).
|
Classe représentant les groupes (Loisir, D1, D2, A, B, …).
|
||||||
Un groupe appartient à un club.
|
Un groupe appartient à un club.
|
||||||
|
|
||||||
|
NOTE: pourquoi garder un champ `active` ? Il y a un risque qu'un groupe soit désactivé ? Si oui, ne vaut-il pas mieux garder le moment où il l'a été ?
|
||||||
|
|
||||||
|
NOTE: est-ce que le champ `name` n'est pas un dictionnaire fini ? Loisir, D1, D2, ... ?
|
||||||
|
|
||||||
|
NOTE: est-ce que tu n'as pas une contrainte sur le nom, le club et la saison ?
|
||||||
|
|
||||||
|
|
||||||
## Subgroup
|
## Subgroup
|
||||||
|
@ -61,28 +91,33 @@ Un sous-groupe appartient à un groupe (pour rappel, lui-même lié à un club).
|
||||||
De cette manière, quand un gymnaste est mis dans un sous-groupe, en remontant via le groupe,
|
De cette manière, quand un gymnaste est mis dans un sous-groupe, en remontant via le groupe,
|
||||||
nous pouvons connaître le(s) club(s) du gymnaste pour chaque saison.
|
nous pouvons connaître le(s) club(s) du gymnaste pour chaque saison.
|
||||||
|
|
||||||
|
NOTE: re-question sur le `name`. A mon avis, si le nom du groupe est fini, tu peux te passer d'une des classes `Group` ou `Subgroup`, et cela simplifierait pas mal la gestion du club.
|
||||||
|
|
||||||
## Unavailability
|
## Unavailability
|
||||||
|
|
||||||
Classe représentant les indisponibilités.
|
Classe représentant les indisponibilités.
|
||||||
|
|
||||||
|
NOTE: avec la réflexion ci-dessous, cela pourrait ne plus être utile. Les *Courses* correspondent à la modélisation tandis que les entrainements représentent le planifié/réalisé. Du coup, il suffit qu'un entrainenemnts n'existe pas pour qu'il ne soit pas planifié.
|
||||||
|
|
||||||
|
|
||||||
## PlanningLine
|
## PlanningLine
|
||||||
|
|
||||||
Classe représentant les passages prévisionnels (incubating idea).
|
Classe représentant les passages prévisionnels (incubating idea).
|
||||||
|
|
||||||
|
NOTE: en gros, tu veux proposer un entrainement personnalisé pour chaque gymnaste ;) Je ne vois pas la valeur ajoutée. Le mieux serait d'avoir une forme de proposition au niveau des Rounds et des Trainings, quitte à la modifier pendant l'entrainement. Sinon, je ne vois pas trop l'idée.
|
||||||
|
|
||||||
|
|
||||||
## EventType
|
## EventType
|
||||||
|
|
||||||
Classe représentant les types d'évènements.
|
Classe représentant les types d'évènements.
|
||||||
|
|
||||||
C'est un dictionnaire fini :
|
C'est un dictionnaire fini :
|
||||||
- compétiton qualificative,
|
- compétiton qualificative,
|
||||||
- compétition finale,
|
- compétition finale,
|
||||||
- démonstration,
|
- démonstration,
|
||||||
- …
|
- …
|
||||||
|
|
||||||
|
NOTE: tu peux utiliser un champ de type Choice, si le dictionnaire est fini. Cela te fera gagner une jointure. Si le dictionnaire a ***une*** chance d'avoir une nouvelle valeur, garde la table.
|
||||||
|
|
||||||
|
|
||||||
## Event
|
## Event
|
||||||
|
@ -97,6 +132,8 @@ Un évènement est caractérisé par :
|
||||||
|
|
||||||
Je ne me rapelle plus à quoi sert le club.
|
Je ne me rapelle plus à quoi sert le club.
|
||||||
|
|
||||||
|
NOTE: alors, retire le club :-p
|
||||||
|
|
||||||
## Event_Participation
|
## Event_Participation
|
||||||
|
|
||||||
|
NOTE: Dans Event, tu as déjà un lien avec des gymnastes, que tu reprends dans la classe EventParticipation (pas de "*_*"). Autant ne garder qu'une seule liaison entre un évènement et des gymnastes, et compléter ces enregistrements après (ou pendant) pour dire si Choupidou étant bien placé ou pas (quitte à laisser le `rank` vide si Choupidou n'est finalement pas venu ou s'il a sauté comme une bouse - oui, ça arrive).
|
||||||
|
|
|
@ -7,5 +7,5 @@ from . import views
|
||||||
|
|
||||||
profile_urlpatterns = [
|
profile_urlpatterns = [
|
||||||
path(r"lookup/", views.user_lookup, name="user_lookup"),
|
path(r"lookup/", views.user_lookup, name="user_lookup"),
|
||||||
path(r"edit/<int:profileid>/", views.profile_update, name="profile_update"),
|
path(r"edit/", views.profile_update, name="profile_update"),
|
||||||
]
|
]
|
||||||
|
|
|
@ -60,17 +60,12 @@ def user_lookup(request):
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@require_http_methods(["GET", "POST"])
|
@require_http_methods(["GET", "POST"])
|
||||||
def profile_update(request, profileid):
|
def profile_update(request):
|
||||||
"""Modification d'un profil utilisateur.
|
"""Modification du profil de l'utilisateur connecté
|
||||||
|
|
||||||
Args:
|
|
||||||
profileid (int): L'identifiant du profil utilisateur à modifier.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
profile = get_object_or_404(Profile, pk=profileid)
|
profile = request.user.profile
|
||||||
|
|
||||||
if profile.user != request.user:
|
|
||||||
raise PermissionDenied("Permission denied : you don't have the permission to update this profile.")
|
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = ProfileForm(request.POST, instance=profile)
|
form = ProfileForm(request.POST, instance=profile)
|
||||||
|
@ -78,7 +73,6 @@ def profile_update(request, profileid):
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
|
|
||||||
request.session["profileid"] = profileid
|
|
||||||
request.session["template"] = profile.template_color
|
request.session["template"] = profile.template_color
|
||||||
request.session["sidebar"] = profile.sidebar_color
|
request.session["sidebar"] = profile.sidebar_color
|
||||||
request.session["is_sidebar_minified"] = profile.is_sidebar_minified
|
request.session["is_sidebar_minified"] = profile.is_sidebar_minified
|
||||||
|
@ -88,5 +82,5 @@ def profile_update(request, profileid):
|
||||||
else:
|
else:
|
||||||
form = ProfileForm(instance=profile)
|
form = ProfileForm(instance=profile)
|
||||||
|
|
||||||
context = {"form": form, "profileid": profileid}
|
context = {"form": form,}
|
||||||
return render(request, "profile_create.html", context)
|
return render(request, "profile_create.html", context)
|
||||||
|
|
|
@ -159,7 +159,7 @@
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu dropdown-navbar">
|
<ul class="dropdown-menu dropdown-navbar">
|
||||||
<li class="nav-link">
|
<li class="nav-link">
|
||||||
<a href="{% url 'profile_update' request.session.profileid %}" class="nav-item dropdown-item">Profile</a>
|
<a href="{% url 'profile_update' %}" class="nav-item dropdown-item">Profile</a>
|
||||||
</li>
|
</li>
|
||||||
<!-- <li class="nav-link"> -->
|
<!-- <li class="nav-link"> -->
|
||||||
<!-- <a href="javascript:void(0)" class="nav-item dropdown-item">Settings</a> -->
|
<!-- <a href="javascript:void(0)" class="nav-item dropdown-item">Settings</a> -->
|
||||||
|
@ -301,26 +301,22 @@
|
||||||
$full_page = $('.full-page');
|
$full_page = $('.full-page');
|
||||||
$sidebar_responsive = $('body > .navbar-collapse');
|
$sidebar_responsive = $('body > .navbar-collapse');
|
||||||
|
|
||||||
{% if request.session.is_sidebar_minified %}sidebar_mini_active = true;
|
{% if request.session.is_sidebar_minified %}
|
||||||
{% else %}sidebar_mini_active = false;{% endif %}
|
sidebar_mini_active = true; {% else %}
|
||||||
|
sidebar_mini_active = false; {% endif %}
|
||||||
|
{% if request.session.template == 0 %}
|
||||||
{% if request.session.template == 0%}white_color = false;
|
white_color = false; {% else %}
|
||||||
{% else %}white_color = true;{% endif %}
|
white_color = true; {% endif %}
|
||||||
|
|
||||||
window_width = $(window).width();
|
window_width = $(window).width();
|
||||||
|
|
||||||
fixed_plugin_open = $('.sidebar .sidebar-wrapper .nav li.active a p').html();
|
fixed_plugin_open = $('.sidebar .sidebar-wrapper .nav li.active a p').html();
|
||||||
|
|
||||||
{% if request.session.sidebar == 1 %}
|
{% if request.session.sidebar == 1 %}
|
||||||
color = "blue";
|
color = "blue"; {% elif request.session.sidebar == 2 %}
|
||||||
{% elif request.session.sidebar == 2 %}
|
color = "green"; {% elif request.session.sidebar == 3 %}
|
||||||
color = "green";
|
color = "orange"; {% elif request.session.sidebar == 4 %}
|
||||||
{% elif request.session.sidebar == 3 %}
|
color = "red"; {% endif %}
|
||||||
color = "orange";
|
|
||||||
{% elif request.session.sidebar == 4 %}
|
|
||||||
color = "red";
|
|
||||||
{% endif %}
|
|
||||||
$sidebar.attr('data', color);
|
$sidebar.attr('data', color);
|
||||||
$main_panel.attr('data', color);
|
$main_panel.attr('data', color);
|
||||||
$full_page.attr('filter-color', color);
|
$full_page.attr('filter-color', color);
|
||||||
|
@ -417,5 +413,6 @@
|
||||||
|
|
||||||
{% block footerscript %}{% endblock %}
|
{% block footerscript %}{% endblock %}
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -12,7 +12,7 @@
|
||||||
<h4 class="card-title">Edit User Profile</h4>
|
<h4 class="card-title">Edit User Profile</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form action="{% url 'profile_update' profileid %}" method="post" class="form-horizontal" id="formulaire" name="formulaire">
|
<form action="{% url 'profile_update' %}" method="post" class="form-horizontal" id="formulaire" name="formulaire">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label for="id_birthdate" class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 col-form-label">Birthdate</label>
|
<label for="id_birthdate" class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 col-form-label">Birthdate</label>
|
||||||
|
@ -59,8 +59,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript" >
|
<script type="text/javascript">
|
||||||
$(function(){
|
$(function() {
|
||||||
blackDashboard.initDateTimePicker();
|
blackDashboard.initDateTimePicker();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in New Issue