implemented basic teaching session pages

This commit is contained in:
Faraphel 2023-12-11 19:29:02 +01:00
parent cfa65daa19
commit 5f2aaf1a2e
9 changed files with 304 additions and 14 deletions

View file

@ -61,9 +61,9 @@ class AdminAttendance(admin.ModelAdmin):
@admin.register(models.Absence)
class AdminAbsence(admin.ModelAdmin):
list_display = ("id", "message", "student", "department", "start", "end")
search_fields = ("id", "message", "student", "department", "start", "end")
list_filter = ("department", "start", "end")
list_display = ("id", "message", "student", "start", "end")
search_fields = ("id", "message", "student", "start", "end")
list_filter = ("start", "end")
@admin.register(models.AbsenceAttachment)

View file

@ -0,0 +1,166 @@
# 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

@ -63,6 +63,9 @@ class User(AbstractUser, ModelPermissionHelper):
def __repr__(self):
return f"<{self.__class__.__name__} id={str(self.id)[:8]} username={self.username!r}>"
def __str__(self):
return f"{self.first_name} {self.last_name.upper()}"
@staticmethod
def multiple_related_departments(users: Iterable["User"]) -> QuerySet["Department"]:
"""

View file

@ -0,0 +1,5 @@
{% extends "Palto/base.html" %}
{% block body %}
Hello there.
{% endblock %}

View file

@ -1,3 +1,11 @@
{% load static %}
<nav>
Palto
<img src="{% static "Palto/favicon.svg" %}" alt="Palto's icon" width="5%">
<a>Palto</a>
<a href="{% url "Palto:homepage" %}">Home</a>
<a href="{% url "Palto:my_profile" %}">Profile</a>
<a href="{% url "Palto:login" %}">Login</a>
<a href="{% url "Palto:logout" %}">Logout</a>
</nav>

View file

@ -0,0 +1,27 @@
{% extends "Palto/base.html" %}
{% block body %}
{# table of all the sessions #}
<table>
<thead>
<tr>
<th>Identifiant</th>
<th>Début</th>
<th>Durée</th>
<th>Unité d'Enseignement</th>
<th>Enseignant</th>
<th>Groupe</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ session.id }}</td>
<td>{{ session.start }}</td>
<td>{{ session.duration }}</td>
<td>{{ session.unit }}</td>
<td>{{ session.teacher }}</td>
<td>{{ session.group }}</td>
</tr>
</tbody>
</table>
{% endblock %}

View file

@ -0,0 +1,36 @@
{% extends "Palto/base.html" %}
{% block body %}
{# table of all the sessions #}
<table>
<thead>
<tr>
<th>Identifiant</th>
<th>Début</th>
<th>Durée</th>
</tr>
</thead>
<tbody>
{% for session in sessions %}
<tr>
<td><a href="{% url "Palto:teaching_session" session.id %}">{{ session.id }}</a></td>
<td>{{ session.start }}</td>
<td>{{ session.duration }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{# page navigator #}
<div>
{% if sessions.has_previous %}
<a href="?page={{ sessions.previous_page_number }}">Previous</a>
{% endif %}
<a>{{ sessions.number }}</a>
{% if sessions.has_next %}
<a href="?page={{ sessions.next_page_number }}">Next</a>
{% endif %}
</div>
{% endblock %}

View file

@ -16,6 +16,8 @@ urlpatterns = [
# User
path("login/", views.login_view, name="login"),
path("logout/", views.logout_view, name="logout"),
path("profile/", views.profile_view, name="profile"),
path("profile/", views.profile_view, name="my_profile"),
path("profile/<uuid:profile_id>/", views.profile_view, name="profile"),
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"),
]

View file

@ -6,20 +6,24 @@ A view is what control the content of a page, prepare the correct data, react to
import uuid
from django.contrib.auth import login, authenticate, logout
from django.contrib.auth.decorators import login_required
from django.http import HttpRequest, HttpResponse
from django.core.handlers.wsgi import WSGIRequest
from django.core.paginator import Paginator
from django.http import HttpResponseForbidden
from django.shortcuts import render, get_object_or_404, redirect
from Palto.Palto import models
from Palto.Palto.forms import LoginForm
from Palto.Palto.models import User
ELEMENT_PER_PAGE: int = 30
# Create your views here.
def homepage_view(request: HttpRequest):
# TODO: homepage
return HttpResponse("Hello there.")
def homepage_view(request: WSGIRequest):
return render(request, "Palto/homepage.html")
def login_view(request: HttpRequest):
def login_view(request: WSGIRequest):
# create a login form
form_login = LoginForm(request.POST)
@ -51,7 +55,7 @@ def login_view(request: HttpRequest):
@login_required
def logout_view(request: HttpRequest):
def logout_view(request: WSGIRequest):
# disconnect the user from the website
logout(request)
# redirect him to the main page
@ -59,13 +63,13 @@ def logout_view(request: HttpRequest):
@login_required
def profile_view(request: HttpRequest, profile_id: uuid.UUID = None):
def profile_view(request: WSGIRequest, profile_id: uuid.UUID = None):
if profile_id is None:
# if the profile id is not given, redirect to the page of the current user.
return redirect("Palto:profile", request.user.id)
# get the corresponding user from its id.
profile = get_object_or_404(User, id=profile_id)
profile = get_object_or_404(models.User, id=profile_id)
# render the page
return render(
@ -75,3 +79,42 @@ def profile_view(request: HttpRequest, profile_id: uuid.UUID = None):
profile=profile
)
)
@login_required
def teaching_session_list_view(request: WSGIRequest):
# get all the sessions that the user can see, sorted by starting date
raw_sessions = models.TeachingSession.all_visible_by_user(request.user).order_by("start")
# paginate them to avoid having too many elements at the same time
paginator = Paginator(raw_sessions, ELEMENT_PER_PAGE)
# get only the session for the requested page
page = request.GET.get("page", 0)
sessions = paginator.get_page(page)
# render the page
return render(
request,
"Palto/teaching_session_list.html",
context=dict(
sessions=sessions
)
)
@login_required
def teaching_session_view(request: WSGIRequest, session_id: uuid.UUID):
session = get_object_or_404(models.TeachingSession, id=session_id)
if session not in models.TeachingSession.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_session.html",
context=dict(
session=session
)
)