Compare commits
No commits in common. "dev" and "main" have entirely different histories.
35
README.md
35
README.md
|
@ -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.
|
|
@ -1,5 +1,4 @@
|
|||
from django.contrib import admin
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from colloscope.models import *
|
||||
|
||||
|
||||
|
@ -32,59 +31,18 @@ class ColleInline(admin.StackedInline):
|
|||
|
||||
@admin.register(Slot)
|
||||
class SlotAdmin(admin.ModelAdmin):
|
||||
list_display = ('subject', 'colleur', "term", 'get_day', "time", "duration")
|
||||
list_display = ('subject', 'colleur', "term", 'view_day', "time", "duration")
|
||||
list_filter = ("subject", "colleur", "term")
|
||||
inlines = [ColleInline]
|
||||
|
||||
def get_day(self, obj):
|
||||
def view_day(self, obj):
|
||||
jours = ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"]
|
||||
return jours[obj.day]
|
||||
|
||||
get_day.short_description = _('Day')
|
||||
|
||||
|
||||
class SwapInline(admin.StackedInline):
|
||||
model = Swap
|
||||
raw_id_fields = ("colle",)
|
||||
|
||||
|
||||
@admin.register(Colle)
|
||||
class ColleAdmin(admin.ModelAdmin):
|
||||
list_display = ('get_subject', 'get_colleur', 'get_room', 'datetime',)
|
||||
list_filter = ('slot',)
|
||||
inlines = [SwapInline]
|
||||
|
||||
def get_subject(self, obj):
|
||||
return obj.slot.subject
|
||||
|
||||
def get_colleur(self, obj):
|
||||
return obj.slot.colleur
|
||||
|
||||
def get_room(self, obj):
|
||||
return obj.slot.room
|
||||
|
||||
get_subject.short_description = _('Subject')
|
||||
get_colleur.short_description = _('Colleur')
|
||||
get_room.short_description = _('Room')
|
||||
|
||||
|
||||
@admin.register(Swap)
|
||||
class SwapAdmin(admin.ModelAdmin):
|
||||
list_display = ('get_subject', 'get_colleur', 'get_datetime', 'enroll', 'student')
|
||||
list_filter = ('enroll', 'student')
|
||||
|
||||
def get_subject(self, obj):
|
||||
return obj.colle.slot.subject
|
||||
get_subject.short_description = _('Subject')
|
||||
|
||||
def get_colleur(self, obj):
|
||||
return obj.colle.slot.colleur
|
||||
get_subject.short_description = _('Colleur')
|
||||
|
||||
def get_datetime(self, obj):
|
||||
return obj.colle.datetime
|
||||
get_subject.short_description = _('Heure')
|
||||
view_day.short_description = 'Day'
|
||||
|
||||
|
||||
admin.site.register(Colle)
|
||||
admin.site.register(Swap)
|
||||
admin.site.register(Profile)
|
||||
admin.site.register(CalendarLink)
|
||||
|
|
|
@ -9,7 +9,6 @@ from django.db import models
|
|||
from django.db.models import F, Q, Count, QuerySet, Subquery, OuterRef, Sum
|
||||
from django.contrib.auth.models import User
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from discord import Webhook
|
||||
|
||||
|
@ -386,9 +385,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())}}}"
|
||||
|
||||
|
@ -414,7 +410,22 @@ class Profile(models.Model):
|
|||
colleur = models.ForeignKey(Colleur, null=True, blank=True, on_delete=models.SET_NULL)
|
||||
|
||||
def __str__(self):
|
||||
return "Student" if self.student is not None else "Colleur"
|
||||
return f"Profil {self.user} : {self.student} ; {self.colleur}"
|
||||
|
||||
@staticmethod
|
||||
def from_request(request, preprocess=lambda query: query):
|
||||
user = request.user
|
||||
session = request.session
|
||||
|
||||
match session.get("profile"):
|
||||
case "student":
|
||||
profil = preprocess(Profile.objects.filter(user=user)).get()
|
||||
return profil.student
|
||||
case "colleur":
|
||||
profil = preprocess(Profile.objects.filter(user=user)).get()
|
||||
return profil.colleur
|
||||
case _:
|
||||
raise ValueError("profil non choisi")
|
||||
|
||||
|
||||
class CalendarLink(models.Model):
|
||||
|
|
|
@ -110,10 +110,12 @@ def generate(term):
|
|||
|
||||
def handle(request):
|
||||
try:
|
||||
student = (Student.objects
|
||||
.select_related("cls")
|
||||
.prefetch_related("cls__term_set")
|
||||
.get(profile__user=request.user))
|
||||
student = Profile.from_request(
|
||||
request,
|
||||
preprocess=lambda query: query \
|
||||
.select_related("student__cls") \
|
||||
.prefetch_related("student__cls__term_set")
|
||||
)
|
||||
except ValueError:
|
||||
return redirect("colloscope.select_profile")
|
||||
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load static %}
|
||||
{% load extras %}
|
||||
|
||||
{% block title %}Tableau de bord{% endblock title %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
{% block intro %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% if colles %}
|
||||
{% regroup colles by week_number as week_list %}
|
||||
{% for week in week_list %}
|
||||
|
||||
<h3 class="week" id="week-no-{{ week.grouper }}">
|
||||
<a href="#week-no-{{ week.grouper }}">Semaine {{ week.grouper }}</a>
|
||||
</h3>
|
||||
<div class="colle-wrapper">
|
||||
{% for colle in week.list %}
|
||||
<div class="colle">
|
||||
<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>
|
||||
<details>
|
||||
<summary><i class="fa-solid fa-users"></i>
|
||||
{{ colle.groups.all | print_manager | safe }}
|
||||
({{ colle.volume }} / {{ colle.slot.capacity }})</summary>
|
||||
{% if colle.final_group.exists %}
|
||||
<ul>
|
||||
{% for member in colle.final_group.all %}
|
||||
<li>{{ member }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
Personne n'est inscrit à cette colle.
|
||||
{% endif %}
|
||||
</details>
|
||||
</li>
|
||||
<li><i class="fa-solid fa-earth-americas"></i> {{ colle.slot.room }}</li>
|
||||
{% if False %}
|
||||
|
||||
<li><i class="fa-solid fa-circle-exclamation"></i>
|
||||
<form
|
||||
action="{% url "colloscope:withdraw" %}"
|
||||
method="POST"
|
||||
onsubmit="return confirm('Êtes-vous sûr de vouloir vous désinscrire de la colle {{ colle }} ');">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="colle_id" value="{{ colle.id }}">
|
||||
<button type="submit">Rendre disponible</button>
|
||||
</form>
|
||||
</li>
|
||||
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
|
||||
Aucune colle.
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endblock main %}
|
|
@ -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 %}
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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 :
|
||||
<select name="term" id="term">
|
||||
{% for p in term.cls.term_set.all %}
|
||||
|
@ -33,9 +33,9 @@
|
|||
</form>
|
||||
|
||||
{% if request.GET.term %}
|
||||
<a href="{% url 'colloscope:export' %}?term={{ request.GET.term }}" target="_blank">Exporter le colloscope</a>
|
||||
<a href="export.pdf?term={{ request.GET.term }}" target="_blank">Exporter le colloscope</a>
|
||||
{% else %}
|
||||
<a href="{% url 'colloscope:export' %}" target="_blank">Exporter le colloscope</a>
|
||||
<a href="export.pdf" target="_blank">Exporter le colloscope</a>
|
||||
{% endif %}
|
||||
|
||||
<div class="table-wrapper">
|
||||
|
|
|
@ -1,20 +1,14 @@
|
|||
from django.urls import path
|
||||
from django.shortcuts import redirect
|
||||
from . import views
|
||||
from .views import ColleListView
|
||||
|
||||
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("calendrier.ics",
|
||||
lambda req: redirect("colloscope:export-ics", key=req.GET.get("key")), name="export-ics-old"),
|
||||
path("marketplace/", views.marketplace, name="marketplace"),
|
||||
path("action/enroll/", views.enroll, name="enroll"),
|
||||
path("action/withdraw/", views.withdraw, name="withdraw"),
|
||||
path("listing/<int:term>/", ColleListView.as_view(), name="colles"),
|
||||
path("listing/<int:term>/by_subject/<int:subject>/", ColleListView.as_view(), name="colles_by_subject"),
|
||||
path("listing/<int:term>/by_colleur/<int:colleur>/", ColleListView.as_view(), name="colles_by_colleur"),
|
||||
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"),
|
||||
]
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
from uuid import uuid4
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.shortcuts import redirect, render
|
||||
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
|
||||
|
@ -16,41 +13,66 @@ 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)
|
||||
|
||||
|
||||
class ColleListView(ListView):
|
||||
model = Colle
|
||||
context_object_name = "colles"
|
||||
def home_redirect(request):
|
||||
return redirect("/colloscope/dashboard.html")
|
||||
|
||||
def get_queryset(self):
|
||||
term = Term.objects.get(pk=self.kwargs.get("term"))
|
||||
base_query = (term.cls
|
||||
.current_term()
|
||||
.query_colles()
|
||||
.filter(datetime__gte=date.today()))
|
||||
|
||||
if self.kwargs.get("subject") is not None:
|
||||
print(base_query)
|
||||
print(self.kwargs.get("subject"))
|
||||
base_query = base_query.filter(slot__subject__id=self.kwargs.get("subject"))
|
||||
if self.kwargs.get("colleur") is not None:
|
||||
base_query = base_query.filter(slot__colleur__id=self.kwargs.get("colleur"))
|
||||
@login_required
|
||||
def select_profile(request):
|
||||
user = request.user
|
||||
session = request.session
|
||||
|
||||
return base_query
|
||||
if not Profile.objects.filter(user=user).exists():
|
||||
profile = Profile(user=user)
|
||||
profile.save()
|
||||
else:
|
||||
profile = Profile.objects.get(user=user)
|
||||
|
||||
if profile.student is not None and profile.colleur is None:
|
||||
session["profile"] = "student"
|
||||
return redirect("/colloscope/")
|
||||
elif profile.colleur is not None and profile.student is None:
|
||||
session["profile"] = "colleur"
|
||||
return redirect("/colloscope/")
|
||||
else:
|
||||
if profile.student is not None:
|
||||
template = loader.get_template("select_profile.html")
|
||||
else:
|
||||
template = loader.get_template("unbound_profile.html")
|
||||
|
||||
context = {
|
||||
"profile": profile,
|
||||
}
|
||||
return HttpResponse(template.render(context))
|
||||
|
||||
|
||||
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}"
|
||||
|
||||
|
||||
@login_required
|
||||
def dashboard(request):
|
||||
try:
|
||||
student = (Student.objects
|
||||
.select_related("cls")
|
||||
.prefetch_related("cls__term_set")
|
||||
.get(profile__user=request.user))
|
||||
|
||||
student = Profile.from_request(
|
||||
request,
|
||||
preprocess=lambda query: (query
|
||||
.select_related("student__cls")
|
||||
.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é")
|
||||
|
@ -95,15 +117,17 @@ class WithdrawForm(AmendForm):
|
|||
@login_required
|
||||
def marketplace(request):
|
||||
try:
|
||||
student = (Student.objects
|
||||
.select_related("cls")
|
||||
.prefetch_related("cls__term_set")
|
||||
.get(profile__user=request.user))
|
||||
student = Profile.from_request(
|
||||
request,
|
||||
preprocess=lambda query: (query
|
||||
.select_related("student__cls")
|
||||
.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)
|
||||
|
@ -118,12 +142,14 @@ def marketplace(request):
|
|||
@login_required
|
||||
def colloscope(request):
|
||||
try:
|
||||
student = (Student.objects
|
||||
.select_related("cls")
|
||||
.prefetch_related("cls__term_set")
|
||||
.get(profile__user=request.user))
|
||||
student = Profile.from_request(
|
||||
request,
|
||||
preprocess=lambda query: (query
|
||||
.select_related("student__cls")
|
||||
.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é")
|
||||
|
@ -191,7 +217,7 @@ def get_calendar_link(student, term):
|
|||
lien = CalendarLink(key=key, student=student, term=term)
|
||||
lien.save()
|
||||
|
||||
return f"/colloscope/export/calendar/{lien.key}/calendar.ics"
|
||||
return f"export/calendar/{lien.key}/calendar.ics"
|
||||
|
||||
|
||||
def icalendar(request, key):
|
||||
|
@ -211,10 +237,12 @@ def icalendar(request, key):
|
|||
|
||||
def amend(request, colle_id, do_enroll):
|
||||
try:
|
||||
student = (Student.objects
|
||||
.select_related("cls")
|
||||
.prefetch_related("cls__term_set")
|
||||
.get(profile__user=request.user))
|
||||
student = Profile.from_request(
|
||||
request,
|
||||
preprocess=lambda query: (query
|
||||
.select_related("student__cls")
|
||||
.prefetch_related("student__cls__term_set"))
|
||||
)
|
||||
except ValueError:
|
||||
return redirect("colloscope.choix_profil")
|
||||
|
||||
|
|
|
@ -52,7 +52,6 @@ INSTALLED_APPS = [
|
|||
"rest_framework",
|
||||
'rest_framework_simplejwt',
|
||||
'colloscope',
|
||||
"front",
|
||||
"drf_spectacular",
|
||||
]
|
||||
|
||||
|
@ -125,7 +124,6 @@ LANGUAGE_CODE = 'fr'
|
|||
TIME_ZONE = 'Europe/Paris'
|
||||
|
||||
USE_I18N = True
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
@ -158,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"
|
||||
|
|
|
@ -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
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.user.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 %}© 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 %}© 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>
|
||||
|
|
|
@ -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 ? Aucun problème : il vous suffit de l'échanger !
|
||||
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 :
|
||||
</p>
|
||||
<ol start=0>
|
||||
<li>Exécutez le code librement ;</li>
|
||||
<li>Modifiez le code librement ;</li>
|
||||
<li>Distribuez le code librement ;</li>
|
||||
<li>Distribuez librement des versions modifiées du code.</li>
|
||||
</ol>
|
||||
|
||||
{% endblock %}
|
Loading…
Reference in New Issue