added create absence page (missing attachments)
This commit is contained in:
parent
acc9ee66e7
commit
8db28b9838
14 changed files with 99 additions and 30 deletions
|
@ -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.
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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:
|
||||||
|
|
11
Palto/Palto/templates/Palto/absence_new.html
Normal file
11
Palto/Palto/templates/Palto/absence_new.html
Normal 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 %}
|
|
@ -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>
|
|
@ -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 %}
|
|
@ -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 %}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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"),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue