added create absence page (missing attachments)

This commit is contained in:
Faraphel 2023-12-14 22:56:22 +01:00
parent acc9ee66e7
commit 8db28b9838
14 changed files with 99 additions and 30 deletions

View file

@ -9,7 +9,7 @@ from django.contrib import admin
from . import models from . import models
# TODO: plus de list_filter sur "department" ? # TODO(Faraphel): plus de list_filter sur "department" ?
# Register your models here. # Register your models here.

View file

@ -12,7 +12,7 @@ from rest_framework.exceptions import PermissionDenied
from Palto.Palto import models from Palto.Palto import models
# TODO: voir les relations inversées ? # TODO(Faraphel): voir les relations inversées ?
class ModelSerializerContrains(serializers.ModelSerializer): class ModelSerializerContrains(serializers.ModelSerializer):

View file

@ -1,6 +1,26 @@
from django import forms from django import forms
from Palto.Palto import models
# Users
class LoginForm(forms.Form): class LoginForm(forms.Form):
username = forms.CharField() username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput) password = forms.CharField(widget=forms.PasswordInput)
# Objects
class NewAbsenceForm(forms.Form):
department = forms.ModelChoiceField(queryset=None)
start = forms.DateTimeField(widget=forms.TextInput(attrs=dict(type='datetime-local')))
end = forms.DateTimeField(widget=forms.TextInput(attrs=dict(type='datetime-local')))
message = forms.CharField(widget=forms.Textarea)
def __init__(self, student: models.User, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["department"].queryset = student.studying_departments.all()

View file

@ -15,7 +15,7 @@ from django.db import models
from django.db.models import QuerySet, Q, F from django.db.models import QuerySet, Q, F
# TODO(Raphaël): split permissions from models for readability # TODO(Faraphel): split permissions from models for readability
class ModelPermissionHelper: class ModelPermissionHelper:

View file

@ -0,0 +1,11 @@
{% extends "Palto/base.html" %}
{% block body %}
<form method="POST">
{% csrf_token %}
<table>
{{ form_new_absence.as_table }}
</table>
<input type="submit" value="Créer">
</form>
{% endblock %}

View file

@ -9,11 +9,11 @@
</tr> </tr>
<tr> <tr>
<th>Département</th> <th>Département</th>
<td>{{ absence.department }}</td> <td><a href="{# TODO(Faraphel): departement #}">{{ absence.department }}</a></td>
</tr> </tr>
<tr> <tr>
<th>Etudiant</th> <th>Étudiant</th>
<td>{{ absence.student }}</td> <td><a href="{% url "Palto:profile" absence.student.id %}">{{ absence.student }}</a></td>
</tr> </tr>
<tr> <tr>
<th>Période</th> <th>Période</th>

View file

@ -3,7 +3,9 @@
{% block body %} {% block body %}
<form method="POST"> <form method="POST">
{% csrf_token %} {% csrf_token %}
{{ form_login }} <table>
<input type="submit" value="Log in"> {{ form_login.as_table }}
</table>
<input type="submit" value="Se connecter">
</form> </form>
{% endblock %} {% endblock %}

View file

@ -29,7 +29,7 @@
<td>Responsable d'UE</td> <td>Responsable d'UE</td>
<td> <td>
{% for managing_unit in managing_units %} {% for managing_unit in managing_units %}
<a href="{% url "Palto:teaching_unit" managing_unit.id %}"> <a href="{% url "Palto:teaching_unit_view" managing_unit.id %}">
{{ managing_unit.name }} {{ managing_unit.name }}
</a> </a>
{% if not forloop.last %}<br/>{% endif %} {% if not forloop.last %}<br/>{% endif %}
@ -45,7 +45,7 @@
<td>Enseignant</td> <td>Enseignant</td>
<td> <td>
{% for teaching_unit in teaching_units %} {% for teaching_unit in teaching_units %}
<a href="{% url "Palto:teaching_unit" teaching_unit.id %}"> <a href="{% url "Palto:teaching_unit_view" teaching_unit.id %}">
{{ teaching_unit.name }} {{ teaching_unit.name }}
</a> </a>
{% if not forloop.last %}<br/>{% endif %} {% if not forloop.last %}<br/>{% endif %}

View file

@ -16,8 +16,8 @@
{# show the information for every session #} {# show the information for every session #}
{% for session in sessions %} {% for session in sessions %}
<tr> <tr>
<td><a href="{% url "Palto:teaching_session" session.id %}">{{ session.short_id }}</a></td> <td><a href="{% url "Palto:teaching_session_view" session.id %}">{{ session.short_id }}</a></td>
<td><a href="{% url "Palto:teaching_unit" session.unit.id %}">{{ session.unit.name }}</a></td> <td><a href="{% url "Palto:teaching_unit_view" session.unit.id %}">{{ session.unit.name }}</a></td>
<td>{{ session.start }}<br>{{ session.end }}</td> <td>{{ session.start }}<br>{{ session.end }}</td>
<td><a href="{% url "Palto:profile" session.teacher.id %}">{{ session.teacher }}</a></td> <td><a href="{% url "Palto:profile" session.teacher.id %}">{{ session.teacher }}</a></td>
<td>{{ session.attendances.all|length }} / {{ session.group.students.all|length }}</td> <td>{{ session.attendances.all|length }} / {{ session.group.students.all|length }}</td>

View file

@ -18,7 +18,7 @@
</tr> </tr>
<tr> <tr>
<th>Unité d'Enseignement</th> <th>Unité d'Enseignement</th>
<td><a href="{% url "Palto:teaching_unit" session.unit.id %}">{{ session.unit }}</a></td> <td><a href="{% url "Palto:teaching_unit_view" session.unit.id %}">{{ session.unit }}</a></td>
</tr> </tr>
<tr> <tr>
<th>Enseignant</th> <th>Enseignant</th>
@ -53,7 +53,7 @@
<td> <td>
{% with absence=session_student_data|dict_get:"absence" %} {% with absence=session_student_data|dict_get:"absence" %}
{% if absence != None %} {% if absence != None %}
<a href="{% url "Palto:absence" absence.id %}">Détails</a> <a href="{% url "Palto:absence_view" absence.id %}">Détails</a>
{% endif %} {% endif %}
{% endwith %} {% endwith %}
</td> </td>

View file

@ -14,7 +14,7 @@
</tr> </tr>
<tr> <tr>
<th>Département</th> <th>Département</th>
<td href="{# TODO: department url #}">{{ unit.department.name }}</td> <td href="{# TODO(Faraphel): department url #}">{{ unit.department.name }}</td>
</tr> </tr>
<tr> <tr>
<th>Mail</th> <th>Mail</th>

View file

@ -20,13 +20,13 @@ urlpatterns = [
path("profile/<uuid:profile_id>/", views.profile_view, name="profile"), path("profile/<uuid:profile_id>/", views.profile_view, name="profile"),
# Units # Units
path("teaching_units/<uuid:unit_id>/", views.teaching_unit_view, name="teaching_unit"), path("teaching_units/view/<uuid:unit_id>/", views.teaching_unit_view, name="teaching_unit_view"),
# Sessions # Sessions
path("teaching_sessions/", views.teaching_session_list_view, name="teaching_session_list"), path("teaching_sessions/", views.teaching_session_list_view, name="teaching_session_list"),
path("teaching_sessions/<uuid:session_id>/", views.teaching_session_view, name="teaching_session"), path("teaching_sessions/view/<uuid:session_id>/", views.teaching_session_view, name="teaching_session_view"),
# Absences # Absences
path("absences/<uuid:absence_id>/", views.absence_view, name="absence"), path("absences/view/<uuid:absence_id>/", views.absence_view, name="absence_view"),
# TODO: new absence path("absences/new/", views.new_absence_view, name="absence_new"),
] ]

View file

@ -8,11 +8,11 @@ from django.contrib.auth import login, authenticate, logout
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.core.handlers.wsgi import WSGIRequest from django.core.handlers.wsgi import WSGIRequest
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.db import IntegrityError
from django.http import HttpResponseForbidden from django.http import HttpResponseForbidden
from django.shortcuts import render, get_object_or_404, redirect from django.shortcuts import render, get_object_or_404, redirect
from Palto.Palto import models from Palto.Palto import models, forms
from Palto.Palto.forms import LoginForm
from Palto.Palto.utils import get_object_or_none from Palto.Palto.utils import get_object_or_none
ELEMENT_PER_PAGE: int = 30 ELEMENT_PER_PAGE: int = 30
@ -25,7 +25,7 @@ def homepage_view(request: WSGIRequest):
def login_view(request: WSGIRequest): def login_view(request: WSGIRequest):
# create a login form # create a login form
form_login = LoginForm(request.POST) form_login = forms.LoginForm(request.POST)
if form_login.is_valid(): if form_login.is_valid():
# try to authenticate this user with the credentials # try to authenticate this user with the credentials
@ -125,13 +125,13 @@ def teaching_unit_view(request: WSGIRequest, unit_id: uuid.UUID):
# check if the user is allowed to see this specific object # check if the user is allowed to see this specific object
if unit not in models.TeachingUnit.all_visible_by_user(request.user): if unit not in models.TeachingUnit.all_visible_by_user(request.user):
# TODO: syntaxic sugar session.visible_by_user(request.user) # TODO(Faraphel): syntaxic sugar session.visible_by_user(request.user)
return HttpResponseForbidden() return HttpResponseForbidden()
# render the page # render the page
return render( return render(
request, request,
"Palto/teaching_unit.html", "Palto/teaching_unit_view.html",
context=dict( context=dict(
unit=unit, unit=unit,
) )
@ -144,7 +144,7 @@ def teaching_session_view(request: WSGIRequest, session_id: uuid.UUID):
# check if the user is allowed to see this specific object # check if the user is allowed to see this specific object
if session not in models.TeachingSession.all_visible_by_user(request.user): if session not in models.TeachingSession.all_visible_by_user(request.user):
# TODO: syntaxic sugar session.visible_by_user(request.user) # TODO(Faraphel): syntaxic sugar session.visible_by_user(request.user)
return HttpResponseForbidden() return HttpResponseForbidden()
# prepare the data and the "complex" query for the template # prepare the data and the "complex" query for the template
@ -159,7 +159,7 @@ def teaching_session_view(request: WSGIRequest, session_id: uuid.UUID):
models.Absence.objects, models.Absence.objects,
student=student, student=student,
start__lte=session.start, end__gte=session.end start__lte=session.start, end__gte=session.end
), # TODO: property ? ), # TODO(Faraphel): property ?
} }
for student in session.group.students.all() for student in session.group.students.all()
@ -168,7 +168,7 @@ def teaching_session_view(request: WSGIRequest, session_id: uuid.UUID):
# render the page # render the page
return render( return render(
request, request,
"Palto/teaching_session.html", "Palto/teaching_session_view.html",
context=dict( context=dict(
session=session, session=session,
session_students_data=session_students_data, session_students_data=session_students_data,
@ -182,14 +182,50 @@ def absence_view(request: WSGIRequest, absence_id: uuid.UUID):
# check if the user is allowed to see this specific object # check if the user is allowed to see this specific object
if absence not in models.Absence.all_visible_by_user(request.user): if absence not in models.Absence.all_visible_by_user(request.user):
# TODO: syntaxic sugar session.visible_by_user(request.user) # TODO(Faraphel): syntaxic sugar session.visible_by_user(request.user)
return HttpResponseForbidden() return HttpResponseForbidden()
# render the page # render the page
return render( return render(
request, request,
"Palto/absence.html", "Palto/absence_view.html",
context=dict( context=dict(
absence=absence, absence=absence,
) )
) )
@login_required
def new_absence_view(request: WSGIRequest):
# check if the user can create an absence
if not models.Absence.can_user_create(request.user):
return HttpResponseForbidden()
# create a form for the new absence
form_new_absence = forms.NewAbsenceForm(request.user, request.POST)
if form_new_absence.is_valid():
try:
models.Absence.objects.create(
student=request.user,
start=form_new_absence.cleaned_data["start"],
end=form_new_absence.cleaned_data["end"],
department=form_new_absence.cleaned_data["department"],
message=form_new_absence.cleaned_data["message"],
)
except IntegrityError:
form_new_absence.add_error(None, "This absence already exists.")
else:
return redirect("Palto:homepage") # TODO(Faraphel): redirect to absence list
# TODO(Faraphel): add attachments to the forms
# render the page
return render(
request,
"Palto/absence_new.html",
context=dict(
form_new_absence=form_new_absence,
)
)

View file

@ -191,7 +191,7 @@ AUTH_USER_MODEL = "Palto.User"
# CORS settings # CORS settings
# TODO(Raphaël): Only in debug ! # TODO(Faraphel): Only in debug !
CORS_ORIGIN_ALLOW_ALL = True CORS_ORIGIN_ALLOW_ALL = True