Compare commits

..

No commits in common. "c770867c2cb1d10b7b63748a5a8dfd4ce6ab1520" and "b76277a6c7def8b929aec26a743a3c9490dae830" have entirely different histories.

16 changed files with 1300 additions and 196 deletions

View File

@ -1,35 +1,2 @@
# Colloscope : Votre colloscope. En ligne.
# kholles-web
Certifié le dernier colloscope dont vous aurez besoin. Avec ses fonctionalités de synchronisation, il reste
toujours à jour pour vous permettre d'aborder vos colles sereinement, si vous connaissez votre cours (apprentissage
du cours non fourni).
## Soyez le premier informé lors d'une modification
Lorsqu'une colle est modifiée, le modification se propage à l'ensemble des pages visibles par les utilisateurs.
Aucune excuse pour manquer sa colle.
## Échangez vos colles en toute confianc
Vous ne pouvez pas venir à une colle ? Aucun problème : il vous suffit de l'échanger !
Le *Marketplace* intégré vous donne la possibilité de récupérer des colles disponibles.
## Un système interopérable
Vous pouvez synchroniser vos colles avec votre application de calendrier favorite. Il lui suffit de supporter
les liens iCalendar. C'est le cas de l'application Calendrier sur iOS, de OneCalendar sur Android et de
Mozilla Thunderbird sur GNU/Linux et macOS (et Microsoft Windows).
## Pensé par un nerd, pour les nerds.
Un système complet d'API REST vous permet d'intégrer ce colloscope à vos programmes tiers.
## Libre, pour toujours.
Colloscope est distribué avec la licence GNU Affero GPL. Cette licence garantit vos quatre libertés, à savoir :
0. Exécutez le code librement ;
1. Modifiez le code librement ;
2. Distribuez le code librement ;
3. Distribuez librement des versions modifiées du code.

View File

@ -383,9 +383,6 @@ class Colle(models.Model):
# func = async_to_sync(swap.notify)
# func()
def week_number(self):
return self.slot.term.cls.week_number(self.datetime.date())
def __str__(self):
return f"Colle {self.slot.subject} ({self.slot.colleur}); {self.datetime} {self.slot.time} {self.slot.room}. Groupe(s) {{{'; '.join(str(groupe) for groupe in self.groups.all())}}}"

View File

@ -13,33 +13,30 @@
Bienvenue {{ student }}. Votre lycée est {{ term.cls.school.description }}, et votre classe est {{ term.cls.description }}.
</p>
<p>Période actuelle : {{ term }}. Votre groupe de colle est {{ group }}. <a href="{% url "colloscope:table" %}">Consulter le colloscope</a></p>
<p>Période actuelle : {{ term }}. Votre groupe de colle est {{ group }}. <a href="table.html">Consulter le colloscope</a></p>
<h2>Mes colles</h2>
<p><a href="{{ calendar_link }}"><i class="fa-regular fa-calendar"></i> Exporter en .ics (ceci est un permalien public)</a></p>
<p><a href="{% url "colloscope:marketplace" %}">Accéder au marketplace</a></p>
<p><a href="{% url "colloscope.marketplace" %}">Accéder au marketplace</a></p>
{% for n, lundi, colles in colles_per_sem %}
{% if colles %}
<h3 class="week" id="week-no-{{ n }}">
<a href="#week-no-{{ n }}">Semaine {{n}} ({{lundi}})</a>
</h3>
<h3 class="week">Semaine {{n}} ({{lundi}})</h3>
<div class="colle-wrapper">
{% for colle in colles %}
<div class="colle">
<span class="summary">{{ colle.slot.subject }} ({{ colle.slot.colleur }})</span>
<ul>
<li><i class="fa-solid fa-graduation-cap"></i> {{ colle.slot.subject }}</li>
<li><i class="fa-solid fa-person-chalkboard"></i> {{ colle.slot.colleur }}</li>
<li><i class="fa-solid fa-clock"></i> {{ colle.datetime|date:"l"|title }} {{ colle.datetime|date:"DATETIME_FORMAT" }}</li>
<li><i class="fa-solid fa-clock"></i> Le {{ colle.datetime|date:"l" }} {{ colle.datetime|date:"DATETIME_FORMAT" }}</li>
<li><i class="fa-solid fa-users"></i> {{ colle.groups.all | print_manager | safe }} ({{ colle.volume }} / {{ colle.slot.capacity }})</li>
<li><i class="fa-solid fa-earth-americas"></i> {{ colle.slot.room }}</li>
<li><i class="fa-solid fa-circle-exclamation"></i>
<form
action="{% url "colloscope:withdraw" %}"
action="{% url "colloscope.withdraw" %}"
method="POST"
onsubmit="return confirm('Êtes-vous sûr de vouloir vous désinscrire de la colle {{ colle }} ');">
{% csrf_token %}

View File

@ -15,14 +15,13 @@
<div class="colle-wrapper">
{% for colle in colles %}
<div class="colle">
<span class="summary">{{ colle.slot.subject }} ({{ colle.slot.colleur }})</span>
<ul>
<li><i class="fa-solid fa-graduation-cap"></i> {{ colle.slot.subject }}</li>
<li><i class="fa-solid fa-person-chalkboard"></i> {{ colle.slot.colleur }}</li>
<li><i class="fa-solid fa-clock"></i> {{ colle.datetime|date:"l"|title }} {{ colle.datetime|date:"DATETIME_FORMAT" }}</li>
<li><i class="fa-solid fa-clock"></i> Le {{ colle.datetime|date:"l" }} {{ colle.datetime|date:"DATETIME_FORMAT" }}</li>
<li><i class="fa-solid fa-users"></i> {{ colle.groups.all | print_manager | safe }} ({{ colle.volume }} / {{ colle.slot.capacity }})</li>
<li><i class="fa-solid fa-earth-americas"></i> {{ colle.slot.room }}</li>
<li><i class="fa-solid fa-circle-exclamation"></i>
<form action="{% url "colloscope:enroll" %}"
<form action="{% url "colloscope.enroll" %}"
method="POST"
onsubmit="return confirm('Êtes-vous sûr de vouloir vous inscrire à la colle {{ colle }} ');">
{% csrf_token %}

View File

@ -13,12 +13,12 @@
<h1>Colloscope</h1>
<p>
Lycée : {{ term.cls.school.description }}. Classe : {{ term.cls.description }}. <a href="{% url "colloscope:table" %}">Retour au tableau de bord</a>
Lycée : {{ term.cls.school.description }}. Classe : {{ term.cls.description }}. <a href="dashboard.html">Retour au tableau de bord</a>
</p>
<h2>Colloscope : {{ term.description }}</h2>
<form method="get" action="{% url "colloscope:table" %}">
<form method="get" action="{% url "colloscope.table" %}">
Changer de période&nbsp;:
<select name="term" id="term">
{% for p in term.cls.term_set.all %}

View File

@ -1,15 +1,14 @@
from django.urls import path
from django.shortcuts import redirect
from . import views
urlpatterns = [
path("", lambda req: redirect("colloscope:dashboard"), name="home"),
path("table", views.colloscope, name="table"),
path("dashboard", views.dashboard, name="dashboard"),
path("export.pdf", views.export, name="export"),
path("export/calendar/<str:key>/calendar.ics", views.icalendar, name="export-ics"),
path("select_profile", views.select_profile, name="select_profile"),
path("marketplace", views.marketplace, name="marketplace"),
path("action/enroll", views.enroll, name="enroll"),
path("action/withdraw", views.withdraw, name="withdraw"),
path("", views.home_redirect, name="colloscope.home"),
path("table.html", views.colloscope, name="colloscope.table"),
path("dashboard.html", views.dashboard, name="colloscope.dashboard"),
path("export.pdf", views.export, name="colloscope.export"),
path("export/calendar/<str:key>/calendar.ics", views.icalendar, name="colloscope.calendar.ics"),
path("select_profile", views.select_profile, name="colloscope.select_profile"),
path("marketplace.html", views.marketplace, name="colloscope.marketplace"),
path("action/enroll", views.enroll, name="colloscope.enroll"),
path("action/withdraw", views.withdraw, name="colloscope.withdraw"),
]

View File

@ -6,8 +6,6 @@ from django.http import HttpResponse, HttpResponseRedirect
from django.template import loader
from django.views.decorators.http import require_POST
from django.contrib.auth.decorators import login_required
from django.views.generic import ListView
from django.utils.translation import gettext_lazy as _
from colloscope.models import *
from colloscope.pdfexport import handle
@ -15,8 +13,13 @@ from colloscope.icalexport import to_calendar
def handler404(request):
template = loader.get_template("404.html")
context = {}
return render(request, '404.html', context, status=404)
return HttpResponse(template.render(context), status=404)
def home_redirect(request):
return redirect("/colloscope/dashboard.html")
@login_required
@ -32,10 +35,10 @@ def select_profile(request):
if profile.student is not None and profile.colleur is None:
session["profile"] = "student"
return redirect("colloscope:home")
return redirect("/colloscope/")
elif profile.colleur is not None and profile.student is None:
session["profile"] = "colleur"
return redirect("colloscope:home")
return redirect("/colloscope/")
else:
if profile.student is not None:
template = loader.get_template("select_profile.html")
@ -48,11 +51,16 @@ def select_profile(request):
return HttpResponse(template.render(context))
class ColleListView(ListView):
model = Colle
def get_lien_calendrier(student, term):
try:
lien = CalendarLink.objects.get(student=student, term=term)
except CalendarLink.DoesNotExist:
key = uuid4().hex
lien = CalendarLink(key=key, student=student, term=term)
lien.save()
return f"calendrier.ics?key={lien.key}"
def get_queryset(self):
pass
@login_required
def dashboard(request):
@ -64,7 +72,7 @@ def dashboard(request):
.prefetch_related("student__cls__term_set"))
)
except ValueError:
return redirect("colloscope:select_profile")
return redirect("colloscope.select_profile")
if not isinstance(student, Student):
return HttpResponse("pas encore supporté")
@ -116,10 +124,10 @@ def marketplace(request):
.prefetch_related("student__cls__term_set"))
)
except ValueError:
return redirect("colloscope:select_profile")
return redirect("colloscope.select_profile")
if not isinstance(student, Student):
return HttpResponse(_("Not supported yet."))
return HttpResponse("pas encore supporté")
term = student.cls.current_term()
colles = term.query_colles_not_full_excluding_student(student)

View File

@ -52,7 +52,6 @@ INSTALLED_APPS = [
"rest_framework",
'rest_framework_simplejwt',
'colloscope',
"front",
"drf_spectacular",
]
@ -157,8 +156,8 @@ STATICFILES_FINDERS = [
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGIN_URL = "/accounts/login"
LOGIN_REDIRECT_URL = "colloscope:dashboard"
LOGOUT_REDIRECT_URL = "front:index"
LOGIN_REDIRECT_URL = "home"
LOGOUT_REDIRECT_URL = "home"
DISCORD_NOTIFY_WEBHOOK_URL = "https://discord.com/api/webhooks/YOUR_URL"
DISCORD_NOTIFY_WEBHOOK_USERNAME = "Watchdog"

View File

@ -16,15 +16,16 @@ Including another URLconf
"""
from django.contrib import admin, auth
from django.urls import include, path
from django.shortcuts import redirect, render
from django.shortcuts import redirect
from django.contrib.staticfiles import views as vstatic
from rest_framework import routers
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView
from colloscope.views import home_redirect
from colloscope.viewsets import *
router = routers.SimpleRouter()
@ -42,9 +43,7 @@ router.register("calendarlink", CalendarLinkViewset, basename='calendarlink')
urlpatterns = [
path('', lambda req: render(req, "index.html", {}), name="home"),
path("__debug__/", include("debug_toolbar.urls")),
path('', home_redirect, name="home"),
path('api-auth/', include('rest_framework.urls')),
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
@ -56,7 +55,7 @@ urlpatterns = [
path("oauth2/", include('oauth2_provider.urls', namespace='oauth2_provider')),
path("favicon.ico", lambda req: vstatic.serve(req, "favicon.ico")),
path('colloscope/', include(('colloscope.urls', "colloscope"), namespace="colloscope")),
path('colloscope/', include('colloscope.urls')),
path('admin/', admin.site.urls),
path('accounts/', include("django.contrib.auth.urls")),
]

File diff suppressed because it is too large Load Diff

View File

@ -1239,13 +1239,3 @@ msgstr ""
#: venv/lib/python3.12/site-packages/django/views/templates/default_urlconf.html:248
msgid "Connect, get help, or contribute"
msgstr ""
#: colloscope/views.py:122
msgid "Not supported yet."
msgstr "Pas encore supporté."
#: front/templates/index.html:7
msgid "Your colloscope. Online."
msgstr "Votre colloscope. En ligne."

View File

@ -14,7 +14,6 @@ defusedxml==0.7.1
discord.py==2.3.2
Django==5.0.4
django-cors-headers==4.3.1
django-debug-toolbar==4.3.0
django-oauth-toolkit==2.3.0
django-smtp-ssl==1.0
djangorestframework==3.15.1

View File

@ -7,15 +7,6 @@ body {
margin: 0;
}
a:link, a:visited {
color: blue;
text-decoration: underline;
}
a:link:active, a:visited:active {
color: darkblue;
}
header .bandeau {
display: block;
background-color: #333;
@ -88,7 +79,7 @@ header .bandeau button:active {
}
main {
margin: 0 auto;
margin: 20px auto;
width: clamp(350px, 60%, 1200px);
background-color: white;
padding: 10px;
@ -138,11 +129,7 @@ nav.semaine .select, nav.semaine .label {
text-align: center;
}
nav.semaine .select {
background-color: dodgerblue;
color: white;
width: 1em;
}
nav.semaine .select { background-color: dodgerblue; color: white; width: 1em; }
nav.semaine .select:hover { background-color: #0077ea; }
nav.semaine .label:hover {
@ -157,26 +144,13 @@ p.programme {
footer {
text-align: center;
margin: 20px 0;
}
.week {
background-color: dodgerblue;
color: white;
padding: 5px 10px;
border-radius: 5px;
transition: background-color 200ms;
}
.week a, .week a:hover, .week a:active {
color: white;
text-decoration: none;
}
.week:hover {
background-color: #0077ea;
padding: 5px;
}
.week.empty {
@ -185,7 +159,7 @@ footer {
.colle-wrapper {
display: grid;
gap: 15px;
gap: 10px;
}
@media screen and (min-width: 400px)
@ -196,15 +170,8 @@ footer {
}
.colle {
padding: 15px;
border-radius: 8px;
box-shadow: 0 3px 6px rgba(0,0,0,0.04),0 3px 6px rgba(0,0,0,0.0575);
transition: background-color 200ms;
}
.colle:hover {
background-color: #fafafa;
border: 1px solid black;
padding: 10px;
}
.colle span {
@ -213,7 +180,6 @@ footer {
.colle ul {
padding: 0;
margin: 0;
}
.colle li {

@ -1 +1 @@
Subproject commit 811b224d6a8a644dffd6c34cb54acbbd1a0f4db0
Subproject commit 9e2427d5ae8e7fafef9fe001394e9566e181f217

View File

@ -32,27 +32,20 @@
<div class="navbar">
<div class="block">
<a href="{% url "home" %}">
<div class="link"><i class="fa-solid fa-home"></i> Accueil</div>
</a>
{% if request.user.is_authenticated %}
<a href="{% url "colloscope:dashboard" %}">
<a href="{% url "colloscope.dashboard" %}">
<div class="link"><i class="fa-solid fa-rocket"></i> Tableau de bord</div>
</a>
<a href="{% url "colloscope:table" %}">
<a href="{% url "colloscope.table" %}">
<div class="link"><i class="fa-solid fa-calendar"></i> Colloscope</div>
</a>
<a href="{% url "colloscope:marketplace" %}">
<a href="{% url "colloscope.marketplace" %}">
<div class="link"><i class="fa-solid fa-shop"></i> Marketplace</div>
</a>
{% endif %}
</div>
<div class="block">
{% if request.user.is_authenticated %}
<div class="link">
<i class="fa-solid fa-user"></i> {{ user.username }} ({{ request.session.profile }})
</div>
<form action="{% url 'logout' %}" method="post">
{% csrf_token %}
<button class="link" type="submit" href="{% url "login" %}">
@ -73,6 +66,6 @@
{% block main %}{% endblock main %}
</main>
<footer>
{% block footer %}&copy; colles.mp2i-vms.fr 2024 - <a href="https://git.mp2i-vms.fr/mp2i-vms/colles.mp2i-vms.fr" target="_blank">Code source</a> - <a href="https://www.gnu.org/licenses/agpl-3.0.html" target="_blank">Licence GNU AGPL v3 or later</a>{% endblock footer %}
{% block footer %}&copy; colles.mp2i-vms.fr 2024 - <a href="https://git.mp2i-vms.fr/mp2i-vms/kholles-web" target="_blank">Code source</a> - <a href="https://www.gnu.org/licenses/agpl-3.0.html" target="_blank">Licence GNU AGPL v3 or later</a>{% endblock footer %}
</footer>
</body>

View File

@ -1,50 +0,0 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}Accueil{% endblock %}
{% block main %}
<h1>{% translate "Your colloscope. Online." %}</h1>
<p>
Certifié le dernier colloscope dont vous aurez besoin. Avec ses fonctionalités de synchronisation, il reste
toujours à jour pour vous permettre d'aborder vos colles sereinement, si vous connaissez votre cours (apprentissage
du cours non fourni).
</p>
<h2>Soyez le premier informé lors d'une modification</h2>
<p>
Lorsqu'une colle est modifiée, le modification se propage à l'ensemble des pages visibles par les utilisateurs.
Aucune excuse pour manquer sa colle.
</p>
<h2>Échangez vos colles en toute confiance</h2>
<p>
Vous ne pouvez pas venir à une colle&nbsp;? Aucun problème&nbsp;: il vous suffit de l'échanger&nbsp;!
Le <em>Marketplace</em> intégré vous donne la possibilité de récupérer des colles disponibles.
</p>
<h2>Un système interopérable</h2>
<p>
Vous pouvez synchroniser vos colles avec votre application de calendrier favorite. Il lui suffit de supporter
les liens iCalendar. C'est le cas de l'application Calendrier sur iOS, de OneCalendar sur Android et de
Mozilla Thunderbird sur GNU/Linux et macOS (et Microsoft Windows).
</p>
<h2>Pensé par un nerd, pour les nerds.</h2>
<p>
Un système complet d'API REST vous permet d'intégrer ce colloscope à vos programmes tiers.
</p>
<h2>Libre, pour toujours.</h2>
<p>
Colloscope est distribué avec la licence GNU Affero GPL. Cette licence garantit vos quatre libertés, à savoir&nbsp;:
</p>
<ol start=0>
<li>Exécutez le code librement&nbsp;;</li>
<li>Modifiez le code librement&nbsp;;</li>
<li>Distribuez le code librement&nbsp;;</li>
<li>Distribuez librement des versions modifiées du code.</li>
</ol>
{% endblock %}