implemented teaching unit and absence pages

This commit is contained in:
Faraphel 2023-12-14 20:56:48 +01:00
parent 784d4d4001
commit 16264a86a5
8 changed files with 222 additions and 239 deletions

View file

@ -1,166 +0,0 @@
# Generated by Django 4.2.7 on 2023-12-10 11:31
import Palto.Palto.models
from django.conf import settings
import django.contrib.auth.models
import django.contrib.auth.validators
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import uuid
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
name='Absence',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('message', models.TextField()),
('start', models.DateTimeField()),
('end', models.DateTimeField()),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.CreateModel(
name='Department',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('name', models.CharField(max_length=64, unique=True)),
('email', models.EmailField(max_length=254)),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.CreateModel(
name='StudentGroup',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('name', models.CharField(max_length=128)),
('department', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='student_groups', to='Palto.department')),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.CreateModel(
name='User',
fields=[
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
],
options={
'verbose_name': 'user',
'verbose_name_plural': 'users',
'abstract': False,
},
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
migrations.CreateModel(
name='TeachingUnit',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('name', models.CharField(max_length=64)),
('department', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='teaching_units', to='Palto.department')),
('managers', models.ManyToManyField(blank=True, related_name='managing_units', to=settings.AUTH_USER_MODEL)),
('student_groups', models.ManyToManyField(blank=True, related_name='studying_units', to='Palto.studentgroup')),
('teachers', models.ManyToManyField(blank=True, related_name='teaching_units', to=settings.AUTH_USER_MODEL)),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.CreateModel(
name='TeachingSession',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('start', models.DateTimeField()),
('duration', models.DurationField()),
('note', models.TextField(blank=True)),
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='teaching_sessions', to='Palto.studentgroup')),
('teacher', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='teaching_sessions', to=settings.AUTH_USER_MODEL)),
('unit', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sessions', to='Palto.teachingunit')),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.AddField(
model_name='studentgroup',
name='owner',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='owning_groups', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='studentgroup',
name='students',
field=models.ManyToManyField(blank=True, related_name='student_groups', to=settings.AUTH_USER_MODEL),
),
migrations.CreateModel(
name='StudentCard',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('uid', models.BinaryField(max_length=7)),
('department', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='student_cards', to='Palto.department')),
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='student_cards', to=settings.AUTH_USER_MODEL)),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.AddField(
model_name='department',
name='managers',
field=models.ManyToManyField(blank=True, related_name='managing_departments', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='department',
name='students',
field=models.ManyToManyField(blank=True, related_name='studying_departments', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='department',
name='teachers',
field=models.ManyToManyField(blank=True, related_name='teaching_departments', to=settings.AUTH_USER_MODEL),
),
migrations.CreateModel(
name='Attendance',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('date', models.DateTimeField()),
('session', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attendances', to='Palto.teachingsession')),
('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attended_sessions', to=settings.AUTH_USER_MODEL)),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.CreateModel(
name='AbsenceAttachment',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('content', models.FileField(upload_to='absence/attachment/')),
('absence', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attachments', to='Palto.absence')),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.AddField(
model_name='absence',
name='department',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='absences', to='Palto.department'),
),
migrations.AddField(
model_name='absence',
name='student',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='absences', to=settings.AUTH_USER_MODEL),
),
]

View file

@ -0,0 +1,35 @@
{% extends "Palto/base.html" %}
{% block body %}
{# absence's information #}
<table>
<tr>
<th>Identifiant</th>
<td>{{ absence.id }}</td>
</tr>
<tr>
<th>Département</th>
<td>{{ absence.department }}</td>
</tr>
<tr>
<th>Etudiant</th>
<td>{{ absence.student }}</td>
</tr>
<tr>
<th>Période</th>
<td>{{ absence.start }}<br>{{ absence.end }}</td>
</tr>
</table>
{# absence's message #}
<p>
{{ absence.message }}
</p>
{# absence's attachments #}
<div>
{% for attachment in absence.attachments.all %}
<a href="{{ attachment.content.url }}">{{ attachment.content.name }}</a>
{% endfor %}
</div>
{% endblock %}

View file

@ -2,7 +2,6 @@
{% load dict_tags %} {% load dict_tags %}
{% block body %} {% block body %}
<div>
{{ profile.username }} {{ profile.username }}
{{ profile.email }} {{ profile.email }}
{% if profile.is_superuser %}Administrator{% endif %} {% if profile.is_superuser %}Administrator{% endif %}
@ -30,7 +29,9 @@
<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="{# TODO(Faraphel): redirect to unit #}">{{ managing_unit.name }}</a> <a href="{% url "Palto:teaching_unit" managing_unit.id %}">
{{ managing_unit.name }}
</a>
{% if not forloop.last %}<br/>{% endif %} {% if not forloop.last %}<br/>{% endif %}
{% endfor %} {% endfor %}
</td> </td>
@ -44,7 +45,9 @@
<td>Enseignant</td> <td>Enseignant</td>
<td> <td>
{% for teaching_unit in teaching_units %} {% for teaching_unit in teaching_units %}
<a href="{# TODO(Faraphel): redirect to unit #}">{{ teaching_unit.name }}</a> <a href="{% url "Palto:teaching_unit" teaching_unit.id %}">
{{ teaching_unit.name }}
</a>
{% if not forloop.last %}<br/>{% endif %} {% if not forloop.last %}<br/>{% endif %}
{% endfor %} {% endfor %}
</td> </td>
@ -70,5 +73,4 @@
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
</div>
{% endblock %} {% endblock %}

View file

@ -18,7 +18,7 @@
</tr> </tr>
<tr> <tr>
<th>Unité d'Enseignement</th> <th>Unité d'Enseignement</th>
<td>{{ session.unit }}</td> <td><a href="{% url "Palto:teaching_unit" session.unit.id %}">{{ session.unit }}</a></td>
</tr> </tr>
<tr> <tr>
<th>Enseignant</th> <th>Enseignant</th>
@ -51,9 +51,9 @@
{% endwith %} {% endwith %}
</td> </td>
<td> <td>
{% with absence=session_student_data|dict_get:"attendance" %} {% with absence=session_student_data|dict_get:"absence" %}
{% if absence != None %} {% if absence != None %}
<a href="{# TODO(Raphaël): when absence page added #}">...</a> <a href="{% url "Palto:absence" absence.id %}">Détails</a>
{% endif %} {% endif %}
{% endwith %} {% endwith %}
</td> </td>

View file

@ -17,7 +17,7 @@
{% 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" session.id %}">{{ session.short_id }}</a></td>
<td><a href="{# TODO(Faraphel): add when teaching units #}">{{ session.unit.name }}</a></td> <td><a href="{% url "Palto:teaching_unit" 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

@ -0,0 +1,60 @@
{% extends "Palto/base.html" %}
{% load dict_tags %}
{% block body %}
{# unit's information #}
<table>
<tr>
<th>Identifiant</th>
<td>{{ unit.id }}</td>
</tr>
<tr>
<th>Nom</th>
<td>{{ unit.name }}</td>
</tr>
<tr>
<th>Département</th>
<td href="{# TODO: department url #}">{{ unit.department.name }}</td>
</tr>
<tr>
<th>Mail</th>
<td>{% if unit.email != None %}{{ unit.email }}{% else %} / {% endif %}</td>
</tr>
<tr>
<th>Sessions</th>
<td>{{ unit.sessions.all|length }}</td>
</tr>
</table>
{# unit's managers #}
<table>
<thead>
<tr>
<th>Responsables</th>
</tr>
</thead>
<tbody>
{% for manager in unit.managers.all %}
<tr>
<td><a href="{% url "Palto:profile" manager.id %}">{{ manager }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{# unit's teachers #}
<table>
<thead>
<tr>
<th>Enseignants</th>
</tr>
</thead>
<tbody>
{% for teacher in unit.teachers.all %}
<tr>
<td><a href="{% url "Palto:profile" teacher.id %}">{{ teacher }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View file

@ -18,6 +18,15 @@ urlpatterns = [
path("logout/", views.logout_view, name="logout"), path("logout/", views.logout_view, name="logout"),
path("profile/", views.profile_view, name="my_profile"), path("profile/", views.profile_view, name="my_profile"),
path("profile/<uuid:profile_id>/", views.profile_view, name="profile"), path("profile/<uuid:profile_id>/", views.profile_view, name="profile"),
# Units
path("teaching_units/<uuid:unit_id>/", views.teaching_unit_view, name="teaching_unit"),
# 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/<uuid:session_id>/", views.teaching_session_view, name="teaching_session"),
# Absences
path("absences/<uuid:absence_id>/", views.absence_view, name="absence"),
# TODO: new absence
] ]

View file

@ -71,6 +71,10 @@ def profile_view(request: WSGIRequest, profile_id: uuid.UUID = None):
# get the corresponding user from its id. # get the corresponding user from its id.
profile = get_object_or_404(models.User, id=profile_id) profile = get_object_or_404(models.User, id=profile_id)
# check if the user is allowed to see this specific object
if profile not in models.User.all_visible_by_user(request.user):
return HttpResponseForbidden()
# prepare the data and the "complex" query for the template # prepare the data and the "complex" query for the template
profile_departments_data = { profile_departments_data = {
department: { department: {
@ -115,10 +119,30 @@ def teaching_session_list_view(request: WSGIRequest):
) )
@login_required
def teaching_unit_view(request: WSGIRequest, unit_id: uuid.UUID):
unit = get_object_or_404(models.TeachingUnit, id=unit_id)
# check if the user is allowed to see this specific object
if unit not in models.TeachingUnit.all_visible_by_user(request.user):
# TODO: syntaxic sugar session.visible_by_user(request.user)
return HttpResponseForbidden()
# render the page
return render(
request,
"Palto/teaching_unit.html",
context=dict(
unit=unit,
)
)
@login_required @login_required
def teaching_session_view(request: WSGIRequest, session_id: uuid.UUID): def teaching_session_view(request: WSGIRequest, session_id: uuid.UUID):
session = get_object_or_404(models.TeachingSession, id=session_id) session = get_object_or_404(models.TeachingSession, id=session_id)
# 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: syntaxic sugar session.visible_by_user(request.user)
return HttpResponseForbidden() return HttpResponseForbidden()
@ -134,8 +158,8 @@ def teaching_session_view(request: WSGIRequest, session_id: uuid.UUID):
"absence": get_object_or_none( "absence": get_object_or_none(
models.Absence.objects, models.Absence.objects,
student=student, student=student,
start__gte=session.start, end__lte=session.end start__lte=session.start, end__gte=session.end
), ), # TODO: property ?
} }
for student in session.group.students.all() for student in session.group.students.all()
@ -150,3 +174,22 @@ def teaching_session_view(request: WSGIRequest, session_id: uuid.UUID):
session_students_data=session_students_data, session_students_data=session_students_data,
) )
) )
@login_required
def absence_view(request: WSGIRequest, absence_id: uuid.UUID):
absence = get_object_or_404(models.Absence, id=absence_id)
# check if the user is allowed to see this specific object
if absence not in models.Absence.all_visible_by_user(request.user):
# TODO: syntaxic sugar session.visible_by_user(request.user)
return HttpResponseForbidden()
# render the page
return render(
request,
"Palto/absence.html",
context=dict(
absence=absence,
)
)