This commit is contained in:
Valentin Moguérou 2024-04-19 21:20:33 +02:00
parent 25b2d30ddc
commit 70e6b42abb
20 changed files with 259 additions and 59 deletions

View File

@ -13,4 +13,4 @@ admin.site.register(Colleur)
admin.site.register(Creneau) admin.site.register(Creneau)
admin.site.register(Rotation) admin.site.register(Rotation)
admin.site.register(Amendement) admin.site.register(Amendement)
admin.site.register(Utilisateur) admin.site.register(Profil)

View File

@ -0,0 +1,28 @@
# Generated by Django 5.0.4 on 2024-04-19 17:07
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('colloscope', '0006_remove_rotation_semaine_rotation_date'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Profil',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('colleur', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='colloscope.colleur')),
('etudiant', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='colloscope.etudiant')),
('utilisateur', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, unique=True)),
],
),
migrations.DeleteModel(
name='Utilisateur',
),
]

View File

@ -2,6 +2,8 @@ from datetime import date, datetime, timedelta
from django.db import models from django.db import models
from django.db.models import F, Q from django.db.models import F, Q
from django.contrib.auth.models import User
calendrier = { calendrier = {
"C" : [ "C" : [
@ -123,6 +125,10 @@ class Periode(models.Model):
""" """
return range(self.classe.no_semaine(self.debut), self.classe.no_semaine(self.fin)+1) return range(self.classe.no_semaine(self.debut), self.classe.no_semaine(self.fin)+1)
def query_rotations(self):
return Rotation.objects.filter(creneau__periode=self)
def __str__(self): def __str__(self):
return self.libelle return self.libelle
@ -318,9 +324,10 @@ class Amendement(models.Model):
etudiant = models.ForeignKey(Etudiant, on_delete=models.CASCADE) etudiant = models.ForeignKey(Etudiant, on_delete=models.CASCADE)
class Utilisateur(models.Model): class Profil(models.Model):
username = models.CharField(max_length=100) utilisateur = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
password = models.CharField(max_length=300) etudiant = models.ForeignKey(Etudiant, null=True, on_delete=models.SET_NULL)
timestamp = models.DateTimeField(auto_now_add=True) colleur = models.ForeignKey(Colleur, null=True, on_delete=models.SET_NULL)
etudiant = models.ForeignKey(Etudiant, on_delete=models.SET_NULL, null=True)
colleur = models.ForeignKey(Colleur, on_delete=models.SET_NULL, null=True) def __str__(self):
return f"Profil {self.utilisateur} : {self.etudiant} ; {self.colleur}"

View File

@ -106,8 +106,6 @@ def generate(periode):
pdf.y += 3 pdf.y += 3
pdf.table_colloscope(periode, heading=False, est_colle=False) pdf.table_colloscope(periode, heading=False, est_colle=False)
pdf.output("test.pdf")
return pdf return pdf
def main(): def main():

View File

@ -1,26 +0,0 @@
{% load static %}
<!DOCTYPE html>
<html lang="fr-fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}{% endblock title %}</title>
<link href="{% static 'main.css' %}" rel="stylesheet" type="text/css">
{% block head %}{% endblock head %}
</head>
<body>
<header>
{% if request.session.overseer is not None %}
<div class="oversee">
Vous voyez ce site en tant que... Désactiver
</div>
{% endif %}
{% block header %}{% endblock header %}
</header>
<main>
{% block main %}{% endblock main %}
</main>
<footer>
{% block footer %}&copy; UKS 2024{% endblock footer %}
</footer>
</body>

View File

@ -8,18 +8,10 @@
{% block main %} {% block main %}
{% if user.etudiant is not None and user.colleur is not None %}
Vous êtes connecté. Votre compte correspond à deux profils : Vous êtes connecté. Votre compte correspond à deux profils :
<ul> <ul>
<li>en tant que colleur : {{ user.colleur }}&nbsp;; Classes : {{ user.colleur.get_classes|join:"; " }}</li> <li>en tant que colleur : {{ profil.colleur }}&nbsp;; Classes : {{ profil.colleur.get_classes|join:"; " }}</li>
<li>en tant qu'étudiant : {{ user.etudiant }} classe : {{ user.etudiant.classe }}.</li> <li>en tant qu'étudiant : {{ profil.etudiant }} classe : {{ profil.etudiant.classe }}.</li>
</ul> </ul>
{% elif user.colleur is not None and user.etudiant is None %}
Connection en tant que {{ user.colleur }}... classes : {{ user.colleur.get_classes }}
{% elif user.etudiant is not None and user.colleur is None %}
Connection en tant que {{ user.etudiant }} : classe {{ user.etudiant.classe }}
{% else %}
Vous êtes connecté, mais votre compte n'est associé à aucun profil. Veuillez contacter le webmestre à l'adresse <a href="mailto:valentin@mp2i-vms.fr">valentin@mp2i-vms.fr</a>.
{% endif %}
{% endblock main %} {% endblock main %}

View File

@ -22,6 +22,7 @@
<h2>Colloscope : {{ periode.libelle }}</h2> <h2>Colloscope : {{ periode.libelle }}</h2>
<div class="table-wrapper">
<table> <table>
<colgroup> <colgroup>
@ -78,6 +79,7 @@
{% endfor %} {% endfor %}
</table> </table>
</div>
<h2>Par groupes</h2> <h2>Par groupes</h2>

View File

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% block title %}Sélection du profil{% endblock title %}
{% block header %}
<h1>Sélection du profil</h1>
{% endblock header %}
{% block main %}
Vous êtes connecté, mais votre compte n'est associé à aucun profil. Veuillez contacter le webmestre à l'adresse <a href="mailto:valentin@mp2i-vms.fr">valentin@mp2i-vms.fr</a>.
{% endblock main %}

View File

@ -0,0 +1,4 @@
{% extends "base.html" %}
{% block header %}
{% endblock header %}

Binary file not shown.

View File

@ -2,7 +2,8 @@ from django.urls import path
from . import views from . import views
urlpatterns = [ urlpatterns = [
path("", views.colloscope, name="colloscope"), path("", views.home_redirect, name="colloscope.home"),
path("export", views.export, name="export"), path("table.html", views.colloscope, name="colloscope.table"),
path("choix_profil", views.choix_profil, name="choix_profil") path("export.pdf", views.export, name="colloscope.export"),
path("choix_profil", views.choix_profil, name="colloscope.choix_profil"),
] ]

View File

@ -1,7 +1,10 @@
from datetime import timedelta from datetime import timedelta
from django.shortcuts import redirect
from django.http import HttpResponse from django.http import HttpResponse
from django.template import loader from django.template import loader
from django.contrib.auth.decorators import login_required
from colloscope.models import * from colloscope.models import *
from colloscope.table import table_colloscope from colloscope.table import table_colloscope
from colloscope.pdfexport import main # /!\ temporaire from colloscope.pdfexport import main # /!\ temporaire
@ -14,18 +17,59 @@ def handler404(request):
return HttpResponse(template.render(context)) return HttpResponse(template.render(context))
def home_redirect(request):
return redirect("/colloscope/table.html")
@login_required
def choix_profil(request): def choix_profil(request):
template = loader.get_template("choix_profil.html") user = request.user
session = request.session
utilisateur = Utilisateur.objects.get(id=1) if not Profil.objects.filter(utilisateur=user).exists():
profil = Profil(utilisateur=user)
context = { profil.save()
"user": utilisateur, else:
} profil = Profil.objects.get(utilisateur=user)
return HttpResponse(template.render(context))
if profil.etudiant is not None and profil.colleur is None:
session["profil"] = "etudiant"
return redirect("/colloscope/")
elif profil.colleur is not None and profil.etudiant is None:
session["profil"] = "colleur"
return redirect("/colloscope/")
else:
if profil.etudiant is not None:
template = loader.get_template("choix_profil.html")
else:
template = loader.get_template("profil_non_associe.html")
context = {
"profil": profil,
}
return HttpResponse(template.render(context))
@login_required
def colloscope(request): def colloscope(request):
user = request.user
session = request.session
match session.get("profil"):
case "etudiant":
profil = Profil.objects \
.select_related("etudiant__classe") \
.prefetch_related("etudiant__classe__periode_set") \
.get(utilisateur=user)
etudiant = profil.etudiant
case "colleur":
return HttpResponse("pas (encore) supporté")
case _:
return redirect("/colloscope/choix_profil")
"""
periode_str = request.GET.get("periode", "") periode_str = request.GET.get("periode", "")
if periode_str=="": if periode_str=="":
periode = Periode.objects.get(id=3) periode = Periode.objects.get(id=3)
@ -38,8 +82,14 @@ def colloscope(request):
response = HttpResponse(template.render(context, request)) response = HttpResponse(template.render(context, request))
response.status_code = 404 response.status_code = 404
return response return response
"""
periode = etudiant.classe.periode_set.order_by("-debut").first()
creneaux = Creneau.objects \
.filter(periode=periode, est_colle=True) \
.prefetch_related("rotation_set")
creneaux = Creneau.objects.filter(periode=periode, est_colle=True)
semaines = periode.range_semaines() semaines = periode.range_semaines()
rotations = [ (c, []) for c in creneaux ] rotations = [ (c, []) for c in creneaux ]
for c, l in rotations: for c, l in rotations:
@ -77,6 +127,7 @@ def colloscope(request):
return HttpResponse(template.render(context, request)) return HttpResponse(template.render(context, request))
def export(request): def export(request):
return HttpResponse(bytes(main().output()), content_type="application/pdf") return HttpResponse(bytes(main().output()), content_type="application/pdf")

View File

@ -55,7 +55,7 @@ ROOT_URLCONF = 'kholles_web.urls'
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', 'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [], 'DIRS': [ BASE_DIR / "templates" ],
'APP_DIRS': True, 'APP_DIRS': True,
'OPTIONS': { 'OPTIONS': {
'context_processors': [ 'context_processors': [
@ -131,3 +131,7 @@ STATICFILES_FINDERS = [
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGIN_URL = "/comptes/login"
LOGIN_REDIRECT_URL = "home"
LOGOUT_REDIRECT_URL = "home"

View File

@ -14,10 +14,14 @@ Including another URLconf
1. Import the include() function: from django.urls import include, path 1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
""" """
from django.contrib import admin from django.contrib import admin, auth
from django.urls import include, path from django.urls import include, path
from colloscope.views import home_redirect
urlpatterns = [ urlpatterns = [
path('', home_redirect, name="home"),
path('colloscope/', include('colloscope.urls')), path('colloscope/', include('colloscope.urls')),
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('comptes/', include("django.contrib.auth.urls")),
] ]

View File

@ -1,10 +1,46 @@
* {
box-sizing: border-box;
}
body { body {
font-family: sans-serif; font-family: sans-serif;
background-color: #fafafa;
margin: 0; margin: 0;
} }
header .bandeau {
display: block;
background-color: #333;
color: white;
padding: 10px;
}
header .bandeau form {
display: inline;
}
header .bandeau button {
border: none;
background-color: gold;
color: black;
padding: 5px 10px;
margin: 0 5px;
border-radius: 3px;
}
header .bandeau button:hover {
background-color: goldenrod;
}
header .bandeau button:active {
background-color: darkgoldenrod;
}
main { main {
margin: 5px; margin: auto;
width: clamp(350px, 60%, 1200px);
background-color: white;
padding: 10px;
} }
h1 { h1 {

View File

@ -1,3 +1,7 @@
.table-wrapper {
overflow-x: auto;
}
table { table {
border: 1px solid #eee; border: 1px solid #eee;
border-collapse: collapse; border-collapse: collapse;

38
templates/base.html Normal file
View File

@ -0,0 +1,38 @@
{% load static %}
<!DOCTYPE html>
<html lang="fr-fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}{% endblock title %}</title>
<link href="{% static 'main.css' %}" rel="stylesheet" type="text/css">
{% block head %}{% endblock head %}
</head>
<body>
<header>
{% if request.user.is_authenticated %}
<div class="bandeau">
Vous êtes connecté avec le compte <b>{{ user.username }}</b>.
{% if request.session.profil == "etudiant" %}
Profil actuel : étudiant.
{% elif request.session.profil == "colleur" %}
Profil actuel : colleur.
{% else %}
Pas de profil.
{% endif %}
<form action="{% url 'logout' %}" method="post">
{% csrf_token %}
<button type="submit">Se déconnecter</button>
</form>
</div>
{% endif %}
{% block header %}{% endblock header %}
</header>
<main>
{% block main %}{% endblock main %}
</main>
<footer>
{% block footer %}&copy; UKS 2024{% endblock footer %}
</footer>
</body>

View File

@ -0,0 +1,44 @@
{% extends "base.html" %}
{% block title %}Se connecter{% endblock title %}
{% block main %}
<h1>Se connecter</h1>
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p>Your account doesn't have access to this page. To proceed,
please login with an account that has access.</p>
{% else %}
<p>Please login to see this page.</p>
{% endif %}
{% endif %}
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</tr>
<tr>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
</tr>
</table>
<input type="submit" value="Se connecter">
<input type="hidden" name="next" value="{{ next }}">
</form>
{# Assumes you set up the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Mot de passe oublié&nbsp;?</a></p>
{% endblock main %}

BIN
test.pdf

Binary file not shown.