From 2f2332766e5074dbe30f041cab302755f2a9c085 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Sun, 17 Dec 2023 00:20:54 +0100 Subject: [PATCH 01/17] added additional pages (department, absence list, student groups) --- Palto/Palto/admin.py | 21 +++-- Palto/Palto/models.py | 25 ++++++ Palto/Palto/templates/Palto/absence_list.html | 42 ++++++++++ Palto/Palto/templates/Palto/absence_view.html | 2 +- .../templates/Palto/department_view.html | 53 ++++++++++++ Palto/Palto/templates/Palto/homepage.html | 6 +- Palto/Palto/templates/Palto/profile.html | 4 +- .../Palto/templates/Palto/student_group.html | 39 +++++++++ .../Palto/teaching_session_view.html | 2 +- .../templates/Palto/teaching_unit_view.html | 2 +- Palto/Palto/urls.py | 7 ++ Palto/Palto/utils.py | 4 +- Palto/Palto/views.py | 80 ++++++++++++++----- 13 files changed, 255 insertions(+), 32 deletions(-) create mode 100644 Palto/Palto/templates/Palto/absence_list.html create mode 100644 Palto/Palto/templates/Palto/department_view.html create mode 100644 Palto/Palto/templates/Palto/student_group.html diff --git a/Palto/Palto/admin.py b/Palto/Palto/admin.py index 67d2e10..ba604c8 100644 --- a/Palto/Palto/admin.py +++ b/Palto/Palto/admin.py @@ -24,38 +24,45 @@ class AdminUser(admin.ModelAdmin): class AdminDepartment(admin.ModelAdmin): list_display = ("id", "name", "email") search_fields = ("id", "name", "email") + readonly_fields = ("id",) @admin.register(models.StudentGroup) class AdminStudentGroup(admin.ModelAdmin): list_display = ("id", "name", "owner", "department") search_fields = ("id", "name", "owner", "department") + list_filter = ("department",) + readonly_fields = ("id",) @admin.register(models.TeachingUnit) class AdminTeachingUnit(admin.ModelAdmin): list_display = ("id", "name", "email") search_fields = ("id", "name", "email") + readonly_fields = ("id",) @admin.register(models.StudentCard) class AdminStudentCard(admin.ModelAdmin): - list_display = ("id", "uid", "owner") - search_fields = ("id", "uid", "owner") - readonly_fields = ("uid",) + list_display = ("id", "uid", "department", "owner") + search_fields = ("id", "uid", "department", "owner") + readonly_fields = ("id", "uid",) + list_filter = ("department",) @admin.register(models.TeachingSession) class AdminTeachingSession(admin.ModelAdmin): - list_display = ("id", "start", "end", "duration", "teacher") - search_fields = ("id", "start", "end", "duration", "teacher") - list_filter = ("start", "duration") + list_display = ("id", "start", "end", "unit", "duration", "teacher") + search_fields = ("id", "start", "end", "unit", "duration", "teacher") + readonly_fields = ("id",) + list_filter = ("unit",) @admin.register(models.Attendance) class AdminAttendance(admin.ModelAdmin): list_display = ("id", "date", "student") search_fields = ("id", "date", "student") + readonly_fields = ("id",) list_filter = ("date",) @@ -63,6 +70,7 @@ class AdminAttendance(admin.ModelAdmin): class AdminAbsence(admin.ModelAdmin): list_display = ("id", "message", "student", "start", "end") search_fields = ("id", "message", "student", "start", "end") + readonly_fields = ("id",) list_filter = ("start", "end") @@ -70,3 +78,4 @@ class AdminAbsence(admin.ModelAdmin): class AdminAbsenceAttachment(admin.ModelAdmin): list_display = ("id", "content", "absence") search_fields = ("id", "content", "absence") + readonly_fields = ("id",) diff --git a/Palto/Palto/models.py b/Palto/Palto/models.py index 28ad2f6..d695988 100644 --- a/Palto/Palto/models.py +++ b/Palto/Palto/models.py @@ -39,17 +39,31 @@ def user_fields_contraints(cls, user: "User") -> dict[str, Callable[[dict], Quer @classmethod @abstractmethod def all_editable_by_user(cls, user: "User") -> QuerySet: + """ + Return the list of object that the user can edit + """ + + def is_editable_by_user(self, user: "User") -> bool: """ Return True if the user can edit this object """ + return self in self.all_editable_by_user(user) + @classmethod @abstractmethod def all_visible_by_user(cls, user: "User") -> QuerySet: + """ + Return the list of object that the user can see + """ + + def is_visible_by_user(self, user: "User") -> bool: """ Return True if the user can see this object """ + return self in self.all_visible_by_user(user) + class User(AbstractUser, ModelPermissionHelper): """ @@ -522,6 +536,17 @@ def short_id(self) -> str: def end(self) -> datetime: return self.start + self.duration + @property + def related_absences(self) -> QuerySet["Absence"]: + """ + Return the sessions that match the user absence + """ + + return Absence.objects.filter( + student__in=self.group.students, + start__lte=self.start, end__gte=self.end + ).distinct() + # validations def clean(self): diff --git a/Palto/Palto/templates/Palto/absence_list.html b/Palto/Palto/templates/Palto/absence_list.html new file mode 100644 index 0000000..9e16e6a --- /dev/null +++ b/Palto/Palto/templates/Palto/absence_list.html @@ -0,0 +1,42 @@ +{% extends "Palto/base.html" %} + +{% block body %} + {# table of all the absences #} + + + + + + + + + + + {# show the information for every session #} + {% for absence in absences %} + + + + + + + {% endfor %} + +
IdentifiantDépartementÉtudiantPériode
{{ absence.short_id }}{{ absence.department }}{{ absence.student }}{{ absence.start }}
{{ absence.end }}
+ + {# page navigator #} + {# TODO(Faraphel): page navigator as template ? #} + {# TODO(Faraphel): new absence button #} + +
+ {% if sessions.has_previous %} + Previous + {% endif %} + + {{ sessions.number }} + + {% if sessions.has_next %} + Next + {% endif %} +
+{% endblock %} diff --git a/Palto/Palto/templates/Palto/absence_view.html b/Palto/Palto/templates/Palto/absence_view.html index 91f8e29..03e1c27 100644 --- a/Palto/Palto/templates/Palto/absence_view.html +++ b/Palto/Palto/templates/Palto/absence_view.html @@ -9,7 +9,7 @@ Département - {{ absence.department }} + {{ absence.department }} Étudiant diff --git a/Palto/Palto/templates/Palto/department_view.html b/Palto/Palto/templates/Palto/department_view.html new file mode 100644 index 0000000..906a22f --- /dev/null +++ b/Palto/Palto/templates/Palto/department_view.html @@ -0,0 +1,53 @@ +{% extends "Palto/base.html" %} +{% load dict_tags %} + + +{% block body %} + {# department's information #} + + + + + + + + + + + + + +
Identifiant{{ department.id }}
Nom{{ department.name }}
Mail{% if department.email != None %}{{ department.email }}{% else %} / {% endif %}
+ + {# department's managers #} + + + + + + + + {% for manager in department.managers.all %} + + + + {% endfor %} + +
Responsables
{{ manager }}
+ + {# department's teachers #} + + + + + + + + {% for teacher in department.teachers.all %} + + + + {% endfor %} + +
Enseignants
{{ teacher }}
+{% endblock %} diff --git a/Palto/Palto/templates/Palto/homepage.html b/Palto/Palto/templates/Palto/homepage.html index bade8c3..0795085 100644 --- a/Palto/Palto/templates/Palto/homepage.html +++ b/Palto/Palto/templates/Palto/homepage.html @@ -1,5 +1,9 @@ {% extends "Palto/base.html" %} {% block body %} - Hello there. +

Palto

+ +

+ Palto est un outil de gestion des présences d'élèves dans vos établissements scolaires. +

{% endblock %} diff --git a/Palto/Palto/templates/Palto/profile.html b/Palto/Palto/templates/Palto/profile.html index d2b55a3..e879b97 100644 --- a/Palto/Palto/templates/Palto/profile.html +++ b/Palto/Palto/templates/Palto/profile.html @@ -11,7 +11,7 @@ {% for department, profile_department_data in profile_departments_data.items %} {# department name #} - {{ department.name }} + {{ department.name }} {# relation information #} @@ -61,7 +61,7 @@ diff --git a/Palto/Palto/templates/Palto/student_group.html b/Palto/Palto/templates/Palto/student_group.html new file mode 100644 index 0000000..56de3b0 --- /dev/null +++ b/Palto/Palto/templates/Palto/student_group.html @@ -0,0 +1,39 @@ +{% extends "Palto/base.html" %} + +{% block body %} + {# group's information #} +
Groupe Étudiant {% for student_group in student_groups %} - {{ student_group.name }} + {{ student_group.name }} {% if not forloop.last %}
{% endif %} {% endfor %}
+ + + + + + + + + + + + + + + + +
Identifiant{{ group.id }}
Nom{{ group.name }}
Département{{ group.department }}
Propriétaire{{ group.owner }}
+ + {# group's students information #} + + + + + + + + {% for student in group.students.all %} + + + + {% endfor %} + +
Étudiants
{{ student }}
+{% endblock %} diff --git a/Palto/Palto/templates/Palto/teaching_session_view.html b/Palto/Palto/templates/Palto/teaching_session_view.html index 3a26783..ada42aa 100644 --- a/Palto/Palto/templates/Palto/teaching_session_view.html +++ b/Palto/Palto/templates/Palto/teaching_session_view.html @@ -26,7 +26,7 @@ Groupe - {{ session.group }} + {{ session.group }} diff --git a/Palto/Palto/templates/Palto/teaching_unit_view.html b/Palto/Palto/templates/Palto/teaching_unit_view.html index 084b84e..956aa5c 100644 --- a/Palto/Palto/templates/Palto/teaching_unit_view.html +++ b/Palto/Palto/templates/Palto/teaching_unit_view.html @@ -14,7 +14,7 @@ Département - {{ unit.department.name }} + {{ unit.department.name }} Mail diff --git a/Palto/Palto/urls.py b/Palto/Palto/urls.py index 513d372..c664492 100644 --- a/Palto/Palto/urls.py +++ b/Palto/Palto/urls.py @@ -19,6 +19,12 @@ path("profile/", views.profile_view, name="my_profile"), path("profile//", views.profile_view, name="profile"), + # Student groups + path("student_groups/view//", views.student_group_view, name="student_group_view"), + + # Departments + path("departments/view//", views.department_view, name="department_view"), + # Units path("teaching_units/view//", views.teaching_unit_view, name="teaching_unit_view"), @@ -27,6 +33,7 @@ path("teaching_sessions/view//", views.teaching_session_view, name="teaching_session_view"), # Absences + path("absences/", views.absence_list_view, name="absence_list"), path("absences/view//", views.absence_view, name="absence_view"), path("absences/new/", views.new_absence_view, name="absence_new"), ] diff --git a/Palto/Palto/utils.py b/Palto/Palto/utils.py index 06a968a..b7b1624 100644 --- a/Palto/Palto/utils.py +++ b/Palto/Palto/utils.py @@ -1,10 +1,10 @@ from typing import Optional from django.core.exceptions import ObjectDoesNotExist -from django.db.models import Model, Manager +from django.db.models import Model, QuerySet -def get_object_or_none(manager: Manager, *args, **kwargs) -> Optional[Model]: +def get_object_or_none(manager: QuerySet, *args, **kwargs) -> Optional[Model]: """ Similar to the Manager.get method, but return None instead of raising an error. """ diff --git a/Palto/Palto/views.py b/Palto/Palto/views.py index ca4eabe..85d67e1 100644 --- a/Palto/Palto/views.py +++ b/Palto/Palto/views.py @@ -8,7 +8,6 @@ from django.contrib.auth.decorators import login_required from django.core.handlers.wsgi import WSGIRequest from django.core.paginator import Paginator -from django.db import IntegrityError from django.http import HttpResponseForbidden from django.shortcuts import render, get_object_or_404, redirect @@ -72,7 +71,7 @@ def profile_view(request: WSGIRequest, profile_id: uuid.UUID = None): 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): + if not profile.is_visible_by_user(request.user): return HttpResponseForbidden() # prepare the data and the "complex" query for the template @@ -124,8 +123,7 @@ 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(Faraphel): syntaxic sugar session.visible_by_user(request.user) + if not unit.is_visible_by_user(request.user): return HttpResponseForbidden() # render the page @@ -143,23 +141,14 @@ def teaching_session_view(request: WSGIRequest, session_id: uuid.UUID): 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): - # TODO(Faraphel): syntaxic sugar session.visible_by_user(request.user) + if not session.is_visible_by_user(request.user): return HttpResponseForbidden() # prepare the data and the "complex" query for the template session_students_data = { student: { - "attendance": get_object_or_none( - models.Attendance.objects, - session=session, - student=student - ), - "absence": get_object_or_none( - models.Absence.objects, - student=student, - start__lte=session.start, end__gte=session.end - ), # TODO(Faraphel): property ? + "attendance": get_object_or_none(models.Attendance.objects, session=session, student=student), + "absence": get_object_or_none(session.related_absences, student=student) } for student in session.group.students.all() @@ -181,8 +170,7 @@ 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(Faraphel): syntaxic sugar session.visible_by_user(request.user) + if not absence.is_visible_by_user(request.user): return HttpResponseForbidden() # render the page @@ -236,3 +224,59 @@ def new_absence_view(request: WSGIRequest): form_new_absence=form_new_absence, ) ) + + +def absence_list_view(request): + # get all the absences that the user can see, sorted by starting date + raw_absences = models.Absence.all_visible_by_user(request.user).order_by("start") + # paginate them to avoid having too many elements at the same time + paginator = Paginator(raw_absences, ELEMENT_PER_PAGE) + + # get only the session for the requested page + page = request.GET.get("page", 0) + absences = paginator.get_page(page) + + # render the page + return render( + request, + "Palto/absence_list.html", + context=dict( + absences=absences + ) + ) + + +@login_required +def department_view(request: WSGIRequest, department_id: uuid.UUID): + department = get_object_or_404(models.Department, id=department_id) + + # check if the user is allowed to see this specific object + if not department.is_visible_by_user(request.user): + return HttpResponseForbidden() + + # render the page + return render( + request, + "Palto/department_view.html", + context=dict( + department=department, + ) + ) + + +@login_required +def student_group_view(request: WSGIRequest, group_id: uuid.UUID): + group = get_object_or_404(models.StudentGroup, id=group_id) + + # check if the user is allowed to see this specific object + if not group.is_visible_by_user(request.user): + return HttpResponseForbidden() + + # render the page + return render( + request, + "Palto/student_group.html", + context=dict( + group=group, + ) + ) From a1b325b653019f8902867bfdf9703c23e3c2556b Mon Sep 17 00:00:00 2001 From: Faraphel Date: Thu, 4 Jan 2024 00:18:52 +0100 Subject: [PATCH 02/17] simplified environment variables management --- .gitignore | 7 +++++++ Palto/asgi.py | 7 ++++--- Palto/wsgi.py | 6 ++++-- README.md | 16 +++++++++++++++- manage.py | 9 +++++++-- requirements.txt | 1 + utils/__init__.py | 0 utils/env.py | 23 +++++++++++++++++++++++ 8 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 utils/__init__.py create mode 100644 utils/env.py diff --git a/.gitignore b/.gitignore index f910067..39766e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,12 @@ +# IDE .idea + +# Virtual Environment venv +.venv + +# Django media static-collected db.sqlite3 +.env diff --git a/Palto/asgi.py b/Palto/asgi.py index 972e6b9..e81ba04 100644 --- a/Palto/asgi.py +++ b/Palto/asgi.py @@ -7,10 +7,11 @@ https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ """ -import os - +import dotenv from django.core.asgi import get_asgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Palto.settings') +from utils import env + +dotenv.load_dotenv(env.create_dotenv()) application = get_asgi_application() diff --git a/Palto/wsgi.py b/Palto/wsgi.py index 9133ba7..1d5c335 100644 --- a/Palto/wsgi.py +++ b/Palto/wsgi.py @@ -7,10 +7,12 @@ https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ """ -import os +import dotenv from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Palto.settings') +from utils import env + +dotenv.load_dotenv(env.create_dotenv()) application = get_wsgi_application() diff --git a/README.md b/README.md index d72fb01..507f27a 100644 --- a/README.md +++ b/README.md @@ -1 +1,15 @@ -# M1-Projet-Serveur \ No newline at end of file +# Palto-Server + +(This is a project realised for our University, it will not be maintained after and it should not be used outside of testing) + +Palto is a project to check students attendances at their school classes. +It allows teachers to create sessions containing students that should be present. +They can then scan their student card with the NFC technology and they will be automatically marked as present to +this session. + +# Installation + +1. Install `python >= 3.11` +2. Create a virtual environment with `python -m venv ./.venv/`. The next steps will be inside it. +3. Install the dependencies with `python -m pip install -r ./requirements.txt`. +4. Run the program by with `python ./manage.py runserver`. diff --git a/manage.py b/manage.py index 6203449..3dae112 100644 --- a/manage.py +++ b/manage.py @@ -1,12 +1,17 @@ #!/usr/bin/env python """Django's command-line utility for administrative tasks.""" -import os + import sys +import dotenv + +from utils import env + def main(): """Run administrative tasks.""" - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Palto.settings') + dotenv.load_dotenv(env.create_dotenv()) + try: from django.core.management import execute_from_command_line except ImportError as exc: diff --git a/requirements.txt b/requirements.txt index 7207d04..0e80e38 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,3 +13,4 @@ factory_boy # Other librairies markdown +python-dotenv diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/env.py b/utils/env.py new file mode 100644 index 0000000..de4c4af --- /dev/null +++ b/utils/env.py @@ -0,0 +1,23 @@ +from pathlib import Path + +from django.core.management.utils import get_random_secret_key + + +path_dotenv = Path("./.env") + + +def create_dotenv(force: bool = False) -> Path: + # if not forced and the file already exist, ignore + if not force and path_dotenv.exists(): + return path_dotenv + + # otherwise create the file + path_dotenv.write_text( + ( + f"DJANGO_SETTINGS_MODULE='Palto.settings'\n" + f"DJANGO_SECRET={get_random_secret_key()!r}\n" + ), + encoding="utf-8" + ) + + return path_dotenv From 19427d3e347e62c8f702cbc34a66b2d48530d277 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Thu, 4 Jan 2024 19:40:37 +0100 Subject: [PATCH 03/17] added css for the navigation page --- Palto/Palto/static/Palto/css/base.css | 15 ++++++++++ Palto/Palto/static/Palto/css/navigation.css | 28 ++++++++++++++++++ .../Palto/static/Palto/font/CenturyGothic.ttf | Bin 0 -> 55128 bytes Palto/Palto/templates/Palto/base.html | 13 +++++++- Palto/Palto/templates/Palto/navigation.html | 20 ++++++++----- 5 files changed, 68 insertions(+), 8 deletions(-) create mode 100644 Palto/Palto/static/Palto/css/base.css create mode 100644 Palto/Palto/static/Palto/css/navigation.css create mode 100644 Palto/Palto/static/Palto/font/CenturyGothic.ttf diff --git a/Palto/Palto/static/Palto/css/base.css b/Palto/Palto/static/Palto/css/base.css new file mode 100644 index 0000000..9830d27 --- /dev/null +++ b/Palto/Palto/static/Palto/css/base.css @@ -0,0 +1,15 @@ +/* tweaks */ +body { + margin: 0; +} + +/* font */ +* { + font-family: "Century Gothic", sans-serif; +} + +/* links */ +*:link, *:visited { + color: blue; /* TODO: should be palette based color */ + text-decoration: none; +} diff --git a/Palto/Palto/static/Palto/css/navigation.css b/Palto/Palto/static/Palto/css/navigation.css new file mode 100644 index 0000000..225b277 --- /dev/null +++ b/Palto/Palto/static/Palto/css/navigation.css @@ -0,0 +1,28 @@ +nav { + display: flex; + align-items: center; + margin: 4px 16px; +} + +#navigation-header { + display: flex; + margin-right: auto; + align-items: center; + gap: 10px; +} + +#navigation-title { + font-size: 150%; +} + +#navigation-icon { + width: 20%; +} + +#navigation-buttons { + display: flex; + margin-left: auto; + align-items: center; + gap: 10px; +} + diff --git a/Palto/Palto/static/Palto/font/CenturyGothic.ttf b/Palto/Palto/static/Palto/font/CenturyGothic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..93faeb3d41ba3ad302114ccab0d20b124ddb6eb9 GIT binary patch literal 55128 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 F{vW2%b^8DS literal 0 HcmV?d00001 diff --git a/Palto/Palto/templates/Palto/base.html b/Palto/Palto/templates/Palto/base.html index f6d2f27..c389599 100644 --- a/Palto/Palto/templates/Palto/base.html +++ b/Palto/Palto/templates/Palto/base.html @@ -3,11 +3,22 @@ + {# base meta #} - + {% block title %}Palto{% endblock %} + + {# base style #} + + {# navigation #} diff --git a/Palto/Palto/templates/Palto/navigation.html b/Palto/Palto/templates/Palto/navigation.html index 074a3bf..7207012 100644 --- a/Palto/Palto/templates/Palto/navigation.html +++ b/Palto/Palto/templates/Palto/navigation.html @@ -1,11 +1,17 @@ {% load static %} From e9b67b11d8c95b911832d9ec22b22ba93653478e Mon Sep 17 00:00:00 2001 From: Faraphel Date: Thu, 4 Jan 2024 21:55:57 +0100 Subject: [PATCH 04/17] login, logout and profile buttons now depend on the user authentification --- Palto/Palto/templates/Palto/navigation.html | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Palto/Palto/templates/Palto/navigation.html b/Palto/Palto/templates/Palto/navigation.html index 7207012..eb1e697 100644 --- a/Palto/Palto/templates/Palto/navigation.html +++ b/Palto/Palto/templates/Palto/navigation.html @@ -10,8 +10,11 @@ From 39f4abe263e8d761e26bef2871785d042dbed388 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Thu, 4 Jan 2024 22:46:48 +0100 Subject: [PATCH 05/17] reorganised the templates inheritances --- Palto/Palto/templates/Palto/absence_list.html | 4 ++- Palto/Palto/templates/Palto/absence_new.html | 4 ++- Palto/Palto/templates/Palto/absence_view.html | 4 ++- .../templates/Palto/base/base-features.html | 27 +++++++++++++++++++ .../templates/Palto/{ => base}/base.html | 21 +++++++-------- .../templates/Palto/department_view.html | 4 ++- Palto/Palto/templates/Palto/homepage.html | 8 +++--- Palto/Palto/templates/Palto/login.html | 14 +++++++--- Palto/Palto/templates/Palto/navigation.html | 20 -------------- Palto/Palto/templates/Palto/profile.html | 4 ++- .../Palto/templates/Palto/student_group.html | 4 ++- .../Palto/teaching_session_list.html | 4 ++- .../Palto/teaching_session_view.html | 4 ++- .../templates/Palto/teaching_unit_view.html | 4 ++- 14 files changed, 79 insertions(+), 47 deletions(-) create mode 100644 Palto/Palto/templates/Palto/base/base-features.html rename Palto/Palto/templates/Palto/{ => base}/base.html (56%) delete mode 100644 Palto/Palto/templates/Palto/navigation.html diff --git a/Palto/Palto/templates/Palto/absence_list.html b/Palto/Palto/templates/Palto/absence_list.html index 9e16e6a..ec63067 100644 --- a/Palto/Palto/templates/Palto/absence_list.html +++ b/Palto/Palto/templates/Palto/absence_list.html @@ -1,6 +1,8 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% block body %} + {{ block.super }} + {# table of all the absences #} diff --git a/Palto/Palto/templates/Palto/absence_new.html b/Palto/Palto/templates/Palto/absence_new.html index e73e87c..19ebbf9 100644 --- a/Palto/Palto/templates/Palto/absence_new.html +++ b/Palto/Palto/templates/Palto/absence_new.html @@ -1,6 +1,8 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% block body %} + {{ block.super }} + {% csrf_token %}
diff --git a/Palto/Palto/templates/Palto/absence_view.html b/Palto/Palto/templates/Palto/absence_view.html index 03e1c27..ce057ef 100644 --- a/Palto/Palto/templates/Palto/absence_view.html +++ b/Palto/Palto/templates/Palto/absence_view.html @@ -1,6 +1,8 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% block body %} + {{ block.super }} + {# absence's information #}
diff --git a/Palto/Palto/templates/Palto/base/base-features.html b/Palto/Palto/templates/Palto/base/base-features.html new file mode 100644 index 0000000..f4c4b5e --- /dev/null +++ b/Palto/Palto/templates/Palto/base/base-features.html @@ -0,0 +1,27 @@ +{% extends "Palto/base/base.html" %} +{% load static %} + +{% block style %} + {{ block.super }} + +{% endblock %} + +{% block body %} + {{ block.super }} + + +{% endblock %} \ No newline at end of file diff --git a/Palto/Palto/templates/Palto/base.html b/Palto/Palto/templates/Palto/base/base.html similarity index 56% rename from Palto/Palto/templates/Palto/base.html rename to Palto/Palto/templates/Palto/base/base.html index c389599..9893034 100644 --- a/Palto/Palto/templates/Palto/base.html +++ b/Palto/Palto/templates/Palto/base/base.html @@ -7,23 +7,22 @@ - {% block title %}Palto{% endblock %} {# base style #} - + {% block style %} + + + {% endblock %} - {# navigation #} - {% include "Palto/navigation.html" %} - {# body #} {% block body %} {% endblock %} diff --git a/Palto/Palto/templates/Palto/department_view.html b/Palto/Palto/templates/Palto/department_view.html index 906a22f..0199784 100644 --- a/Palto/Palto/templates/Palto/department_view.html +++ b/Palto/Palto/templates/Palto/department_view.html @@ -1,8 +1,10 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% load dict_tags %} {% block body %} + {{ block.super }} + {# department's information #}
diff --git a/Palto/Palto/templates/Palto/homepage.html b/Palto/Palto/templates/Palto/homepage.html index 0795085..7c1b5f6 100644 --- a/Palto/Palto/templates/Palto/homepage.html +++ b/Palto/Palto/templates/Palto/homepage.html @@ -1,9 +1,9 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-navigation.html" %} {% block body %} + {{ block.super }} +

Palto

-

- Palto est un outil de gestion des présences d'élèves dans vos établissements scolaires. -

+

Palto est un outil de gestion des présences d'élèves dans vos établissements scolaires.

{% endblock %} diff --git a/Palto/Palto/templates/Palto/login.html b/Palto/Palto/templates/Palto/login.html index d14cca1..251fb42 100644 --- a/Palto/Palto/templates/Palto/login.html +++ b/Palto/Palto/templates/Palto/login.html @@ -1,11 +1,19 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-navigation.html" %} +{% load static %} + +{% block style %} + {{ block.super }} + +{% endblock %} {% block body %} - + {{ block.super }} + + {% csrf_token %}
{{ form_login.as_table }}
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/Palto/Palto/templates/Palto/navigation.html b/Palto/Palto/templates/Palto/navigation.html deleted file mode 100644 index eb1e697..0000000 --- a/Palto/Palto/templates/Palto/navigation.html +++ /dev/null @@ -1,20 +0,0 @@ -{% load static %} - - diff --git a/Palto/Palto/templates/Palto/profile.html b/Palto/Palto/templates/Palto/profile.html index e879b97..76f2ed3 100644 --- a/Palto/Palto/templates/Palto/profile.html +++ b/Palto/Palto/templates/Palto/profile.html @@ -1,7 +1,9 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-navigation.html" %} {% load dict_tags %} {% block body %} + {{ block.super }} + {{ profile.username }} {{ profile.email }} {% if profile.is_superuser %}Administrator{% endif %} diff --git a/Palto/Palto/templates/Palto/student_group.html b/Palto/Palto/templates/Palto/student_group.html index 56de3b0..8652ab6 100644 --- a/Palto/Palto/templates/Palto/student_group.html +++ b/Palto/Palto/templates/Palto/student_group.html @@ -1,6 +1,8 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-navigation.html" %} {% block body %} + {{ block.super }} + {# group's information #} diff --git a/Palto/Palto/templates/Palto/teaching_session_list.html b/Palto/Palto/templates/Palto/teaching_session_list.html index 715d933..f629daf 100644 --- a/Palto/Palto/templates/Palto/teaching_session_list.html +++ b/Palto/Palto/templates/Palto/teaching_session_list.html @@ -1,6 +1,8 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-navigation.html" %} {% block body %} + {{ block.super }} + {# table of all the sessions #}
diff --git a/Palto/Palto/templates/Palto/teaching_session_view.html b/Palto/Palto/templates/Palto/teaching_session_view.html index ada42aa..8256b93 100644 --- a/Palto/Palto/templates/Palto/teaching_session_view.html +++ b/Palto/Palto/templates/Palto/teaching_session_view.html @@ -1,7 +1,9 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-navigation.html" %} {% load dict_tags %} {% block body %} + {{ block.super }} + {# session's information #}
diff --git a/Palto/Palto/templates/Palto/teaching_unit_view.html b/Palto/Palto/templates/Palto/teaching_unit_view.html index 956aa5c..f9d2bdc 100644 --- a/Palto/Palto/templates/Palto/teaching_unit_view.html +++ b/Palto/Palto/templates/Palto/teaching_unit_view.html @@ -1,7 +1,9 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-navigation.html" %} {% load dict_tags %} {% block body %} + {{ block.super }} + {# unit's information #}
From 51e8dd217ebf8addadd9a59ed08db4d8b03c499a Mon Sep 17 00:00:00 2001 From: Faraphel Date: Thu, 4 Jan 2024 22:46:48 +0100 Subject: [PATCH 06/17] reorganised the templates inheritances --- Palto/Palto/templates/Palto/absence_list.html | 4 ++- Palto/Palto/templates/Palto/absence_new.html | 4 ++- Palto/Palto/templates/Palto/absence_view.html | 4 ++- .../templates/Palto/base/base-features.html | 27 +++++++++++++++++++ .../templates/Palto/{ => base}/base.html | 21 +++++++-------- .../templates/Palto/department_view.html | 4 ++- Palto/Palto/templates/Palto/homepage.html | 8 +++--- Palto/Palto/templates/Palto/login.html | 14 +++++++--- Palto/Palto/templates/Palto/navigation.html | 20 -------------- Palto/Palto/templates/Palto/profile.html | 4 ++- .../Palto/templates/Palto/student_group.html | 4 ++- .../Palto/teaching_session_list.html | 4 ++- .../Palto/teaching_session_view.html | 4 ++- .../templates/Palto/teaching_unit_view.html | 4 ++- 14 files changed, 79 insertions(+), 47 deletions(-) create mode 100644 Palto/Palto/templates/Palto/base/base-features.html rename Palto/Palto/templates/Palto/{ => base}/base.html (56%) delete mode 100644 Palto/Palto/templates/Palto/navigation.html diff --git a/Palto/Palto/templates/Palto/absence_list.html b/Palto/Palto/templates/Palto/absence_list.html index 9e16e6a..ec63067 100644 --- a/Palto/Palto/templates/Palto/absence_list.html +++ b/Palto/Palto/templates/Palto/absence_list.html @@ -1,6 +1,8 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% block body %} + {{ block.super }} + {# table of all the absences #}
diff --git a/Palto/Palto/templates/Palto/absence_new.html b/Palto/Palto/templates/Palto/absence_new.html index e73e87c..19ebbf9 100644 --- a/Palto/Palto/templates/Palto/absence_new.html +++ b/Palto/Palto/templates/Palto/absence_new.html @@ -1,6 +1,8 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% block body %} + {{ block.super }} + {% csrf_token %}
diff --git a/Palto/Palto/templates/Palto/absence_view.html b/Palto/Palto/templates/Palto/absence_view.html index 03e1c27..ce057ef 100644 --- a/Palto/Palto/templates/Palto/absence_view.html +++ b/Palto/Palto/templates/Palto/absence_view.html @@ -1,6 +1,8 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% block body %} + {{ block.super }} + {# absence's information #}
diff --git a/Palto/Palto/templates/Palto/base/base-features.html b/Palto/Palto/templates/Palto/base/base-features.html new file mode 100644 index 0000000..f4c4b5e --- /dev/null +++ b/Palto/Palto/templates/Palto/base/base-features.html @@ -0,0 +1,27 @@ +{% extends "Palto/base/base.html" %} +{% load static %} + +{% block style %} + {{ block.super }} + +{% endblock %} + +{% block body %} + {{ block.super }} + + +{% endblock %} \ No newline at end of file diff --git a/Palto/Palto/templates/Palto/base.html b/Palto/Palto/templates/Palto/base/base.html similarity index 56% rename from Palto/Palto/templates/Palto/base.html rename to Palto/Palto/templates/Palto/base/base.html index c389599..9893034 100644 --- a/Palto/Palto/templates/Palto/base.html +++ b/Palto/Palto/templates/Palto/base/base.html @@ -7,23 +7,22 @@ - {% block title %}Palto{% endblock %} {# base style #} - + {% block style %} + + + {% endblock %} - {# navigation #} - {% include "Palto/navigation.html" %} - {# body #} {% block body %} {% endblock %} diff --git a/Palto/Palto/templates/Palto/department_view.html b/Palto/Palto/templates/Palto/department_view.html index 906a22f..0199784 100644 --- a/Palto/Palto/templates/Palto/department_view.html +++ b/Palto/Palto/templates/Palto/department_view.html @@ -1,8 +1,10 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% load dict_tags %} {% block body %} + {{ block.super }} + {# department's information #}
diff --git a/Palto/Palto/templates/Palto/homepage.html b/Palto/Palto/templates/Palto/homepage.html index 0795085..e1faee0 100644 --- a/Palto/Palto/templates/Palto/homepage.html +++ b/Palto/Palto/templates/Palto/homepage.html @@ -1,9 +1,9 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% block body %} + {{ block.super }} +

Palto

-

- Palto est un outil de gestion des présences d'élèves dans vos établissements scolaires. -

+

Palto est un outil de gestion des présences d'élèves dans vos établissements scolaires.

{% endblock %} diff --git a/Palto/Palto/templates/Palto/login.html b/Palto/Palto/templates/Palto/login.html index d14cca1..7221a98 100644 --- a/Palto/Palto/templates/Palto/login.html +++ b/Palto/Palto/templates/Palto/login.html @@ -1,11 +1,19 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} +{% load static %} + +{% block style %} + {{ block.super }} + +{% endblock %} {% block body %} - + {{ block.super }} + + {% csrf_token %}
{{ form_login.as_table }}
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/Palto/Palto/templates/Palto/navigation.html b/Palto/Palto/templates/Palto/navigation.html deleted file mode 100644 index eb1e697..0000000 --- a/Palto/Palto/templates/Palto/navigation.html +++ /dev/null @@ -1,20 +0,0 @@ -{% load static %} - - diff --git a/Palto/Palto/templates/Palto/profile.html b/Palto/Palto/templates/Palto/profile.html index e879b97..3c8397e 100644 --- a/Palto/Palto/templates/Palto/profile.html +++ b/Palto/Palto/templates/Palto/profile.html @@ -1,7 +1,9 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% load dict_tags %} {% block body %} + {{ block.super }} + {{ profile.username }} {{ profile.email }} {% if profile.is_superuser %}Administrator{% endif %} diff --git a/Palto/Palto/templates/Palto/student_group.html b/Palto/Palto/templates/Palto/student_group.html index 56de3b0..0a7543f 100644 --- a/Palto/Palto/templates/Palto/student_group.html +++ b/Palto/Palto/templates/Palto/student_group.html @@ -1,6 +1,8 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% block body %} + {{ block.super }} + {# group's information #} diff --git a/Palto/Palto/templates/Palto/teaching_session_list.html b/Palto/Palto/templates/Palto/teaching_session_list.html index 715d933..aea92e3 100644 --- a/Palto/Palto/templates/Palto/teaching_session_list.html +++ b/Palto/Palto/templates/Palto/teaching_session_list.html @@ -1,6 +1,8 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% block body %} + {{ block.super }} + {# table of all the sessions #}
diff --git a/Palto/Palto/templates/Palto/teaching_session_view.html b/Palto/Palto/templates/Palto/teaching_session_view.html index ada42aa..0901425 100644 --- a/Palto/Palto/templates/Palto/teaching_session_view.html +++ b/Palto/Palto/templates/Palto/teaching_session_view.html @@ -1,7 +1,9 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% load dict_tags %} {% block body %} + {{ block.super }} + {# session's information #}
diff --git a/Palto/Palto/templates/Palto/teaching_unit_view.html b/Palto/Palto/templates/Palto/teaching_unit_view.html index 956aa5c..fb1716f 100644 --- a/Palto/Palto/templates/Palto/teaching_unit_view.html +++ b/Palto/Palto/templates/Palto/teaching_unit_view.html @@ -1,7 +1,9 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% load dict_tags %} {% block body %} + {{ block.super }} + {# unit's information #}
From 6a7a824a7ee176658e552ce94d0c37405620db58 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Thu, 4 Jan 2024 23:22:06 +0100 Subject: [PATCH 07/17] stylised the login page --- Palto/Palto/static/Palto/css/login.css | 11 ++++++ Palto/Palto/templates/Palto/homepage.html | 4 +- Palto/Palto/templates/Palto/login.html | 2 +- Palto/Palto/templates/Palto/profile.html | 4 +- .../Palto/templates/Palto/student_group.html | 4 +- .../Palto/teaching_session_list.html | 3 +- .../Palto/teaching_session_view.html | 4 +- .../templates/Palto/teaching_unit_view.html | 4 +- Palto/Palto/views.py | 38 ++++++++++--------- 9 files changed, 50 insertions(+), 24 deletions(-) create mode 100644 Palto/Palto/static/Palto/css/login.css diff --git a/Palto/Palto/static/Palto/css/login.css b/Palto/Palto/static/Palto/css/login.css new file mode 100644 index 0000000..685aa02 --- /dev/null +++ b/Palto/Palto/static/Palto/css/login.css @@ -0,0 +1,11 @@ +#login-form { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +#login-form input { + box-sizing: border-box; + width: 100%; +} \ No newline at end of file diff --git a/Palto/Palto/templates/Palto/homepage.html b/Palto/Palto/templates/Palto/homepage.html index 0795085..1511b54 100644 --- a/Palto/Palto/templates/Palto/homepage.html +++ b/Palto/Palto/templates/Palto/homepage.html @@ -1,6 +1,8 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% block body %} + {{ block.super }} +

Palto

diff --git a/Palto/Palto/templates/Palto/login.html b/Palto/Palto/templates/Palto/login.html index 7221a98..6094857 100644 --- a/Palto/Palto/templates/Palto/login.html +++ b/Palto/Palto/templates/Palto/login.html @@ -12,7 +12,7 @@
{% csrf_token %}

- {{ form_login.as_table }} + {{ form_login.as_p }}
diff --git a/Palto/Palto/templates/Palto/profile.html b/Palto/Palto/templates/Palto/profile.html index e879b97..3c8397e 100644 --- a/Palto/Palto/templates/Palto/profile.html +++ b/Palto/Palto/templates/Palto/profile.html @@ -1,7 +1,9 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% load dict_tags %} {% block body %} + {{ block.super }} + {{ profile.username }} {{ profile.email }} {% if profile.is_superuser %}Administrator{% endif %} diff --git a/Palto/Palto/templates/Palto/student_group.html b/Palto/Palto/templates/Palto/student_group.html index 56de3b0..0a7543f 100644 --- a/Palto/Palto/templates/Palto/student_group.html +++ b/Palto/Palto/templates/Palto/student_group.html @@ -1,6 +1,8 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% block body %} + {{ block.super }} + {# group's information #} diff --git a/Palto/Palto/templates/Palto/teaching_session_list.html b/Palto/Palto/templates/Palto/teaching_session_list.html index 715d933..370008c 100644 --- a/Palto/Palto/templates/Palto/teaching_session_list.html +++ b/Palto/Palto/templates/Palto/teaching_session_list.html @@ -1,6 +1,7 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% block body %} + {{ block.super }} {# table of all the sessions #}
diff --git a/Palto/Palto/templates/Palto/teaching_session_view.html b/Palto/Palto/templates/Palto/teaching_session_view.html index ada42aa..0901425 100644 --- a/Palto/Palto/templates/Palto/teaching_session_view.html +++ b/Palto/Palto/templates/Palto/teaching_session_view.html @@ -1,7 +1,9 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% load dict_tags %} {% block body %} + {{ block.super }} + {# session's information #}
diff --git a/Palto/Palto/templates/Palto/teaching_unit_view.html b/Palto/Palto/templates/Palto/teaching_unit_view.html index 956aa5c..fb1716f 100644 --- a/Palto/Palto/templates/Palto/teaching_unit_view.html +++ b/Palto/Palto/templates/Palto/teaching_unit_view.html @@ -1,7 +1,9 @@ -{% extends "Palto/base.html" %} +{% extends "Palto/base/base-features.html" %} {% load dict_tags %} {% block body %} + {{ block.super }} + {# unit's information #}
diff --git a/Palto/Palto/views.py b/Palto/Palto/views.py index 85d67e1..3b0de87 100644 --- a/Palto/Palto/views.py +++ b/Palto/Palto/views.py @@ -24,24 +24,28 @@ def homepage_view(request: WSGIRequest): def login_view(request: WSGIRequest): # create a login form - form_login = forms.LoginForm(request.POST) - if form_login.is_valid(): - # try to authenticate this user with the credentials - user = authenticate( - username=form_login.cleaned_data["username"], - password=form_login.cleaned_data["password"] - ) - - if user is not None: - # if the user was authenticated, log the user in. - login(request, user) - # redirect him to the main page - return redirect("Palto:homepage") - - else: - # otherwise the credentials were invalid. - form_login.add_error(field=None, error="Invalid credentials.") + if request.POST: + form_login = forms.LoginForm(request.POST) + + if form_login.is_valid(): + # try to authenticate this user with the credentials + user = authenticate( + username=form_login.cleaned_data["username"], + password=form_login.cleaned_data["password"] + ) + + if user is not None: + # if the user was authenticated, log the user in. + login(request, user) + # redirect him to the main page + return redirect("Palto:homepage") + + else: + # otherwise the credentials were invalid. + form_login.add_error(field=None, error="Invalid credentials.") + else: + form_login = forms.LoginForm() # return the page return render( From c603a7b580be7f3e65d6348d14bbbe3bbdd83a17 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Fri, 5 Jan 2024 10:32:30 +0100 Subject: [PATCH 08/17] added migrations steps to README --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 507f27a..eb73612 100644 --- a/README.md +++ b/README.md @@ -12,4 +12,7 @@ this session. 1. Install `python >= 3.11` 2. Create a virtual environment with `python -m venv ./.venv/`. The next steps will be inside it. 3. Install the dependencies with `python -m pip install -r ./requirements.txt`. -4. Run the program by with `python ./manage.py runserver`. +4. Modify the `Palto/settings.py` file to setup your database and other settings. +5. Make the migrations with `python ./manage.py makemigrations`. +6. Apply the migrations to the database with `python ./manage.py migrate`. +7. Run the program by with `python ./manage.py runserver`. From 35e44bcd7c0f1f84b1cb38a6c779c1ac83988f8c Mon Sep 17 00:00:00 2001 From: Faraphel Date: Fri, 5 Jan 2024 10:40:12 +0100 Subject: [PATCH 09/17] added basic css for homepage --- Palto/Palto/static/Palto/css/homepage.css | 9 +++++++++ Palto/Palto/templates/Palto/homepage.html | 10 ++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 Palto/Palto/static/Palto/css/homepage.css diff --git a/Palto/Palto/static/Palto/css/homepage.css b/Palto/Palto/static/Palto/css/homepage.css new file mode 100644 index 0000000..153c5d5 --- /dev/null +++ b/Palto/Palto/static/Palto/css/homepage.css @@ -0,0 +1,9 @@ +.title { + font-size: 500%; + text-align: center; +} + +.text { + width: 60%; + margin: auto; +} \ No newline at end of file diff --git a/Palto/Palto/templates/Palto/homepage.html b/Palto/Palto/templates/Palto/homepage.html index 1511b54..6fedd59 100644 --- a/Palto/Palto/templates/Palto/homepage.html +++ b/Palto/Palto/templates/Palto/homepage.html @@ -1,11 +1,17 @@ {% extends "Palto/base/base-features.html" %} +{% load static %} + +{% block style %} + {{ block.super }} + +{% endblock %} {% block body %} {{ block.super }} -

Palto

+

Palto

-

+

Palto est un outil de gestion des présences d'élèves dans vos établissements scolaires.

{% endblock %} From 06cf3b1160fb62de72ea9d03ddb57eca790083c5 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Fri, 5 Jan 2024 11:26:03 +0100 Subject: [PATCH 10/17] added basic css for profile --- Palto/Palto/static/Palto/css/profile.css | 32 +++++ Palto/Palto/templates/Palto/profile.html | 148 +++++++++++++---------- 2 files changed, 114 insertions(+), 66 deletions(-) create mode 100644 Palto/Palto/static/Palto/css/profile.css diff --git a/Palto/Palto/static/Palto/css/profile.css b/Palto/Palto/static/Palto/css/profile.css new file mode 100644 index 0000000..cb30ff5 --- /dev/null +++ b/Palto/Palto/static/Palto/css/profile.css @@ -0,0 +1,32 @@ +#user-informations { + text-align: center; + margin: 5% auto; +} + +#user-name { + font-size: 200%; + font-weight: bold; + text-decoration: underline; +} + +#user-relations { + border-collapse: collapse; + margin: auto; + text-align: center; +} + +#user-relations > tbody > tr > td, #user-relations > tbody > tr > th { + border: 1px solid black; + padding: 4px; +} + +.user-relation { + border-style: hidden; + border-collapse: collapse; + width: 100%; +} + +.user-relation > tbody > tr > td, .user-relation > tbody > tr > th { + border: 1px solid black; + padding: 4px; +} \ No newline at end of file diff --git a/Palto/Palto/templates/Palto/profile.html b/Palto/Palto/templates/Palto/profile.html index 3c8397e..02ed096 100644 --- a/Palto/Palto/templates/Palto/profile.html +++ b/Palto/Palto/templates/Palto/profile.html @@ -1,78 +1,94 @@ {% extends "Palto/base/base-features.html" %} +{% load static %} {% load dict_tags %} +{% block style %} + {{ block.super }} + +{% endblock %} + {% block body %} {{ block.super }} - {{ profile.username }} - {{ profile.email }} - {% if profile.is_superuser %}Administrator{% endif %} + {# user informations #} +
+ + + + + + +
{{ profile.first_name|title }} {{ profile.last_name|upper }}
{{ profile.username }}
{{ profile.email }}
{% if profile.is_superuser %}Administrator{% endif %}
{# user related departments table #} - - {% for department, profile_department_data in profile_departments_data.items %} - - {# department name #} - - {# relation information #} - + + {% endfor %} +
{{ department.name }} - - {# user managing the department #} - {% if profile_department_data|dict_get:"is_manager" %} - - - - - {% endif %} - {# user managing units #} - {% with managing_units=profile_department_data|dict_get:"managing_units" %} - {% if managing_units|length > 0 %} - - - - - {% endif %} - {% endwith %} - {# user teaching units #} - {% with teaching_units=profile_department_data|dict_get:"teaching_units" %} - {% if teaching_units|length > 0 %} - - - - - {% endif %} - {% endwith %} - {# user studying groups #} - {% with student_groups=profile_department_data|dict_get:"student_groups" %} - {% if student_groups|length > 0 %} +
Responsable de Département/
Responsable d'UE - {% for managing_unit in managing_units %} - - {{ managing_unit.name }} - - {% if not forloop.last %}
{% endif %} - {% endfor %} -
Enseignant - {% for teaching_unit in teaching_units %} - - {{ teaching_unit.name }} - - {% if not forloop.last %}
{% endif %} - {% endfor %} -
+ + {% for department, profile_department_data in profile_departments_data.items %} + + {# department name #} + + {# relation information #} + - - {% endfor %} + {% endif %} + {# user managing units #} + {% with managing_units=profile_department_data|dict_get:"managing_units" %} + {% if managing_units|length > 0 %} + + + + + {% endif %} + {% endwith %} + {# user teaching units #} + {% with teaching_units=profile_department_data|dict_get:"teaching_units" %} + {% if teaching_units|length > 0 %} + + + + + {% endif %} + {% endwith %} + {# user studying groups #} + {% with student_groups=profile_department_data|dict_get:"student_groups" %} + {% if student_groups|length > 0 %} + + + + + {% endif %} + {% endwith %} + +
{{ department.name }} + + + {# user managing the department #} + {% if profile_department_data|dict_get:"is_manager" %} - - + + - {% endif %} - {% endwith %} -
Groupe Étudiant - {% for student_group in student_groups %} - {{ student_group.name }} - {% if not forloop.last %}
{% endif %} - {% endfor %} -
Responsable de Département/
-
Responsable d'UE + {% for managing_unit in managing_units %} + + {{ managing_unit.name }} + + {% if not forloop.last %}
{% endif %} + {% endfor %} +
Enseignant + {% for teaching_unit in teaching_units %} + + {{ teaching_unit.name }} + + {% if not forloop.last %}
{% endif %} + {% endfor %} +
Groupe Étudiant + {% for student_group in student_groups %} + {{ student_group.name }} + {% if not forloop.last %}
{% endif %} + {% endfor %} +
+
{% endblock %} From f829efcb9e635e4d84fe87bcfa9ae30837a47f6e Mon Sep 17 00:00:00 2001 From: Faraphel Date: Fri, 5 Jan 2024 11:43:19 +0100 Subject: [PATCH 11/17] added basic css for department view --- .../static/Palto/css/department_view.css | 39 ++++++++++ .../templates/Palto/department_view.html | 71 +++++++++++-------- 2 files changed, 82 insertions(+), 28 deletions(-) create mode 100644 Palto/Palto/static/Palto/css/department_view.css diff --git a/Palto/Palto/static/Palto/css/department_view.css b/Palto/Palto/static/Palto/css/department_view.css new file mode 100644 index 0000000..cfb6dcb --- /dev/null +++ b/Palto/Palto/static/Palto/css/department_view.css @@ -0,0 +1,39 @@ +#department-informations { + border-collapse: collapse; + border: 2px solid black; + margin: 5% auto; +} + +#department-informations th { + text-align: right; + border: 1px solid black; + padding: 4px; +} + +#department-informations td { + text-align: left; + border: 1px solid black; + padding: 4px; +} + +#department-relations { + display: flex; + width: 60%; + margin: auto; +} + +.department-relation { + border-collapse: collapse; + border: 2px solid black; + margin: 0 auto auto auto; +} + +.department-relation th { + border: 2px solid black; + padding: 4px; +} + +.department-relation td { + border: 2px solid black; + padding: 4px; +} \ No newline at end of file diff --git a/Palto/Palto/templates/Palto/department_view.html b/Palto/Palto/templates/Palto/department_view.html index 0199784..6612a89 100644 --- a/Palto/Palto/templates/Palto/department_view.html +++ b/Palto/Palto/templates/Palto/department_view.html @@ -1,12 +1,17 @@ {% extends "Palto/base/base-features.html" %} {% load dict_tags %} +{% load static %} +{% block style %} + {{ block.super }} + +{% endblock %} {% block body %} {{ block.super }} {# department's information #} - +
@@ -17,39 +22,49 @@ - + + + + + + + + +
Identifiant {{ department.id }}
Mail{% if department.email != None %}{{ department.email }}{% else %} / {% endif %}{{ department.email }}
Enseignants{{ department.teachers.count }}
Étudiants{{ department.students.count }}
- {# department's managers #} - - - - - - - - {% for manager in department.managers.all %} +
+ {# department's managers #} +
Responsables
+ - + - {% endfor %} - -
{{ manager }}Responsables
+ + + {% for manager in department.managers.all %} + + {{ manager }} + + {% endfor %} + + - {# department's teachers #} - - - - - - - - {% for teacher in department.teachers.all %} + {# department's teachers #} +
Enseignants
+ - + - {% endfor %} - -
{{ teacher }}Enseignants
+ + + {% for teacher in department.teachers.all %} + + {{ teacher }} + + {% endfor %} + + + {% endblock %} From 7f1564dd0ddbb366dc8a9c7ad4ab13eec8e47060 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Mon, 8 Jan 2024 11:33:35 +0100 Subject: [PATCH 12/17] navigation bar now contains the page title --- Palto/Palto/static/Palto/css/navigation.css | 6 +++++- Palto/Palto/templates/Palto/absence_list.html | 8 ++++++++ Palto/Palto/templates/Palto/absence_new.html | 8 ++++++++ Palto/Palto/templates/Palto/absence_view.html | 8 ++++++++ Palto/Palto/templates/Palto/base/base-features.html | 6 +++++- Palto/Palto/templates/Palto/base/base.html | 2 +- Palto/Palto/templates/Palto/department_view.html | 8 ++++++++ Palto/Palto/templates/Palto/homepage.html | 8 ++++++++ Palto/Palto/templates/Palto/login.html | 8 ++++++++ Palto/Palto/templates/Palto/profile.html | 8 ++++++++ Palto/Palto/templates/Palto/student_group.html | 8 ++++++++ Palto/Palto/templates/Palto/teaching_session_list.html | 8 ++++++++ Palto/Palto/templates/Palto/teaching_session_view.html | 8 ++++++++ Palto/Palto/templates/Palto/teaching_unit_view.html | 8 ++++++++ 14 files changed, 99 insertions(+), 3 deletions(-) diff --git a/Palto/Palto/static/Palto/css/navigation.css b/Palto/Palto/static/Palto/css/navigation.css index 225b277..d1cceae 100644 --- a/Palto/Palto/static/Palto/css/navigation.css +++ b/Palto/Palto/static/Palto/css/navigation.css @@ -11,7 +11,7 @@ nav { gap: 10px; } -#navigation-title { +#navigation-app-name { font-size: 150%; } @@ -19,6 +19,10 @@ nav { width: 20%; } +#navigation-title { + font-size: 300%; +} + #navigation-buttons { display: flex; margin-left: auto; diff --git a/Palto/Palto/templates/Palto/absence_list.html b/Palto/Palto/templates/Palto/absence_list.html index ec63067..234bba8 100644 --- a/Palto/Palto/templates/Palto/absence_list.html +++ b/Palto/Palto/templates/Palto/absence_list.html @@ -1,5 +1,13 @@ {% extends "Palto/base/base-features.html" %} +{% block page-title %} + Absences +{% endblock %} + +{% block navigation-title %} + Absences +{% endblock %} + {% block body %} {{ block.super }} diff --git a/Palto/Palto/templates/Palto/absence_new.html b/Palto/Palto/templates/Palto/absence_new.html index 19ebbf9..f839a4c 100644 --- a/Palto/Palto/templates/Palto/absence_new.html +++ b/Palto/Palto/templates/Palto/absence_new.html @@ -1,5 +1,13 @@ {% extends "Palto/base/base-features.html" %} +{% block page-title %} + Nouvelle Absence +{% endblock %} + +{% block navigation-title %} + Nouvelle Absence +{% endblock %} + {% block body %} {{ block.super }} diff --git a/Palto/Palto/templates/Palto/absence_view.html b/Palto/Palto/templates/Palto/absence_view.html index ce057ef..a2f1460 100644 --- a/Palto/Palto/templates/Palto/absence_view.html +++ b/Palto/Palto/templates/Palto/absence_view.html @@ -1,5 +1,13 @@ {% extends "Palto/base/base-features.html" %} +{% block page-title %} + Absence +{% endblock %} + +{% block navigation-title %} + Absence +{% endblock %} + {% block body %} {{ block.super }} diff --git a/Palto/Palto/templates/Palto/base/base-features.html b/Palto/Palto/templates/Palto/base/base-features.html index f4c4b5e..2ba3dbc 100644 --- a/Palto/Palto/templates/Palto/base/base-features.html +++ b/Palto/Palto/templates/Palto/base/base-features.html @@ -12,7 +12,11 @@ From 964647e2876d226ddfcd6dc4e649252366beccbe Mon Sep 17 00:00:00 2001 From: Faraphel Date: Wed, 17 Jan 2024 23:30:41 +0100 Subject: [PATCH 17/17] fixed the database loading every database backend instead of only the selected one --- Palto/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Palto/settings.py b/Palto/settings.py index c6c54a6..21cb743 100644 --- a/Palto/settings.py +++ b/Palto/settings.py @@ -90,7 +90,7 @@ # Database # https://docs.djangoproject.com/en/4.2/ref/settings/#databases -DATABASES = { +_DATABASES = { "sqlite": { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / os.getenv("DATABASE_SQLITE_FILENAME", "db.sqlite3"), @@ -113,7 +113,7 @@ }, } -DATABASES["default"] = DATABASES[os.getenv("DATABASE_ENGINE", "sqlite")] +DATABASES = {"default": _DATABASES[os.getenv("DATABASE_ENGINE", "sqlite")]} # Password validation