Marketplace, CSS, iCal and a lot of things... #4
|
@ -6,10 +6,10 @@ from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pd_eleves = pandas.read_csv('Resources/eleves-v2.csv', delimiter=";", header=None)
|
#pd_eleves = pandas.read_csv('Resources/eleves-v2.csv', delimiter=";", header=None)
|
||||||
np_eleves = pd_eleves.to_numpy()
|
#np_eleves = pd_eleves.to_numpy()
|
||||||
|
|
||||||
pd_colles = pandas.read_csv('Resources/colloscope-v3.csv', delimiter=";", header=None)
|
pd_colles = pandas.read_csv('static/colloscope-v3.csv', delimiter=";", header=None)
|
||||||
np_colles = pd_colles.to_numpy()
|
np_colles = pd_colles.to_numpy()
|
||||||
|
|
||||||
local_tz = "Europe/Paris"
|
local_tz = "Europe/Paris"
|
||||||
|
|
|
@ -5,7 +5,7 @@ from os import path
|
||||||
from icalendar import Calendar, Event, vCalAddress, vText
|
from icalendar import Calendar, Event, vCalAddress, vText
|
||||||
|
|
||||||
from colloscope.models import *
|
from colloscope.models import *
|
||||||
from create_calendar import get_calendar
|
from .create_calendar import get_calendar
|
||||||
|
|
||||||
LOCAL_TZ = "Europe/Paris"
|
LOCAL_TZ = "Europe/Paris"
|
||||||
|
|
||||||
|
@ -13,35 +13,29 @@ LOCAL_TZ = "Europe/Paris"
|
||||||
def emailize(nom, prenom=None):
|
def emailize(nom, prenom=None):
|
||||||
if prenom is not None:
|
if prenom is not None:
|
||||||
return "{}.{}@example.com" \
|
return "{}.{}@example.com" \
|
||||||
.format(
|
.format(
|
||||||
prenom.replace(" ", "_").lower(),
|
prenom.replace(" ", "_").lower(),
|
||||||
nom.replace(" ", "_").lower()
|
nom.replace(" ", "_").lower()
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return "{}@example.com" \
|
return "{}@example.com" \
|
||||||
.format(nom.replace(" ", "_").lower())
|
.format(nom.replace(" ", "_").lower())
|
||||||
|
|
||||||
|
|
||||||
def to_calendar(etudiant, periode, include_EDT: bool = True):
|
def to_calendar(etudiant, periode, include_EDT: bool = True):
|
||||||
|
|
||||||
p = path.abspath('./static/Base_Calendar.ics')
|
p = path.abspath('./static/Base_Calendar.ics')
|
||||||
|
|
||||||
with open(p) as f:
|
with open(p) as f:
|
||||||
cal = Calendar.from_ical(f.read())
|
cal = Calendar.from_ical(f.read())
|
||||||
|
|
||||||
|
rotations = periode.query_rotations_etudiant(etudiant)
|
||||||
rotations = Rotation.objects \
|
|
||||||
.filter(groupes__membres=etudiant) \
|
|
||||||
.select_related("creneau__periode__classe__lycee") \
|
|
||||||
.select_related("creneau__matiere") \
|
|
||||||
.select_related("creneau__colleur") \
|
|
||||||
|
|
||||||
for rotation in rotations:
|
for rotation in rotations:
|
||||||
event = Event()
|
event = Event()
|
||||||
|
|
||||||
summary = f"Colle {rotation.creneau.matiere} ({rotation.creneau.colleur})"
|
summary = f"Colle {rotation.creneau.matiere} ({rotation.creneau.colleur})"
|
||||||
event.add("summary", summary)
|
event.add("summary", summary)
|
||||||
|
|
||||||
start = rotation.datetime()
|
start = rotation.datetime()
|
||||||
fin = start + rotation.creneau.duree
|
fin = start + rotation.creneau.duree
|
||||||
|
|
||||||
|
@ -49,13 +43,12 @@ def to_calendar(etudiant, periode, include_EDT: bool = True):
|
||||||
event.add("dtend", fin, parameters={"tzid": LOCAL_TZ})
|
event.add("dtend", fin, parameters={"tzid": LOCAL_TZ})
|
||||||
event.add("dtstamp", datetime.now())
|
event.add("dtstamp", datetime.now())
|
||||||
event.add("uid", str(uuid4()))
|
event.add("uid", str(uuid4()))
|
||||||
|
|
||||||
|
|
||||||
event.add("location", f"{rotation.creneau.salle} ({rotation.creneau.periode.classe.lycee})")
|
event.add("location", f"{rotation.creneau.salle} ({rotation.creneau.periode.classe.lycee})")
|
||||||
event.add("categories", "COLLE-" + str(rotation.creneau.matiere))
|
event.add("categories", "COLLE-" + str(rotation.creneau.matiere))
|
||||||
|
|
||||||
description = f"Groupes: {','.join(str(groupe) for groupe in rotation.groupes.all())}"
|
description = f"Groupes: {','.join(str(groupe) for groupe in rotation.groupes.all())}"
|
||||||
event.add(description)
|
event.add("description", description)
|
||||||
|
|
||||||
organizer = vCalAddress(f"mailto:{emailize(rotation.creneau.colleur.nom)}")
|
organizer = vCalAddress(f"mailto:{emailize(rotation.creneau.colleur.nom)}")
|
||||||
organizer.params["cn"] = vText(str(rotation.creneau.colleur))
|
organizer.params["cn"] = vText(str(rotation.creneau.colleur))
|
||||||
|
@ -71,11 +64,13 @@ def to_calendar(etudiant, periode, include_EDT: bool = True):
|
||||||
|
|
||||||
cal.add_component(event)
|
cal.add_component(event)
|
||||||
|
|
||||||
|
"""
|
||||||
if include_EDT:
|
if include_EDT:
|
||||||
#TODO: get le groupe de l'étudiant et ses langue
|
#TODO: get le groupe de l'étudiant et ses langue
|
||||||
edt = get_calendar()
|
edt = get_calendar()
|
||||||
|
|
||||||
for event in edt.walk("VEVENT"):
|
for event in edt.walk("VEVENT"):
|
||||||
cal.add_component(event)
|
cal.add_component(event)
|
||||||
|
"""
|
||||||
|
|
||||||
return cal
|
return cal
|
||||||
|
|
|
@ -52,7 +52,7 @@ class Classe(models.Model):
|
||||||
vacances = calendrier[zone]
|
vacances = calendrier[zone]
|
||||||
jour0 = self.jour_zero
|
jour0 = self.jour_zero
|
||||||
|
|
||||||
n = 1 + ((jour - jour0).days) // 7
|
n = 1 + (jour - jour0).days // 7
|
||||||
for debut, fin in vacances:
|
for debut, fin in vacances:
|
||||||
if jour > debut:
|
if jour > debut:
|
||||||
n -= round((fin - debut) / timedelta(weeks=1))
|
n -= round((fin - debut) / timedelta(weeks=1))
|
||||||
|
@ -91,7 +91,7 @@ class Classe(models.Model):
|
||||||
|
|
||||||
return jour
|
return jour
|
||||||
|
|
||||||
def periode(self, jour):
|
async def periode(self, jour):
|
||||||
"""
|
"""
|
||||||
Entrées :
|
Entrées :
|
||||||
- self
|
- self
|
||||||
|
@ -104,9 +104,9 @@ class Classe(models.Model):
|
||||||
- Le jour n'est pas dans une période
|
- Le jour n'est pas dans une période
|
||||||
- Le jour est au chevauchement de deux périodes
|
- Le jour est au chevauchement de deux périodes
|
||||||
"""
|
"""
|
||||||
return Periode.objects.get(classe=self, debut__lte=jour, fin__gte=jour)
|
return Periode.objects.aget(classe=self, debut__lte=jour, fin__gte=jour)
|
||||||
|
|
||||||
def periode_actuelle(self):
|
async def periode_actuelle(self):
|
||||||
#return self.periode(date.today()) // ne fonctionne pas entre les périodes
|
#return self.periode(date.today()) // ne fonctionne pas entre les périodes
|
||||||
"""
|
"""
|
||||||
On prend la période non révolue la plus récente
|
On prend la période non révolue la plus récente
|
||||||
|
@ -115,7 +115,7 @@ class Classe(models.Model):
|
||||||
return Periode.objects \
|
return Periode.objects \
|
||||||
.filter(classe=self, fin__gte=date.today()) \
|
.filter(classe=self, fin__gte=date.today()) \
|
||||||
.order_by("-debut") \
|
.order_by("-debut") \
|
||||||
.first()
|
.afirst()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.libelle} ({self.lycee.libelle})"
|
return f"{self.libelle} ({self.lycee.libelle})"
|
||||||
|
@ -356,10 +356,6 @@ class Rotation(models.Model):
|
||||||
amendement = Amendement(rotation=self, etudiant=etudiant, est_positif=est_positif)
|
amendement = Amendement(rotation=self, etudiant=etudiant, est_positif=est_positif)
|
||||||
amendement.save()
|
amendement.save()
|
||||||
|
|
||||||
if notifier:
|
|
||||||
loop =
|
|
||||||
asyncio.run_until_complete(amendement.notifier())
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.creneau} le {self.date} avec groupes {'+'.join(str(groupe) for groupe in self.groupes.all())}"
|
return f"{self.creneau} le {self.date} avec groupes {'+'.join(str(groupe) for groupe in self.groupes.all())}"
|
||||||
|
|
||||||
|
@ -391,16 +387,16 @@ class Profil(models.Model):
|
||||||
return f"Profil {self.utilisateur} : {self.etudiant} ; {self.colleur}"
|
return f"Profil {self.utilisateur} : {self.etudiant} ; {self.colleur}"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_request(request, preprocess=lambda query: query):
|
async def from_request(request, preprocess=lambda query: query):
|
||||||
user = request.user
|
user = request.user
|
||||||
session = request.session
|
session = request.session
|
||||||
|
|
||||||
match session.get("profil"):
|
match await session.aget("profil"):
|
||||||
case "etudiant":
|
case "etudiant":
|
||||||
profil = preprocess(Profil.objects.filter(utilisateur=user)).get()
|
profil = await preprocess(Profil.objects.filter(utilisateur=user)).aget()
|
||||||
return profil.etudiant
|
return profil.etudiant
|
||||||
case "colleur":
|
case "colleur":
|
||||||
profil = preprocess(Profil.objects.filter(utilisateur=user)).get()
|
profil = await preprocess(Profil.objects.filter(utilisateur=user)).aget()
|
||||||
return profil.colleur
|
return profil.colleur
|
||||||
case _:
|
case _:
|
||||||
raise ValueError("profil non choisi")
|
raise ValueError("profil non choisi")
|
||||||
|
|
|
@ -53,25 +53,25 @@ def choix_profil(request):
|
||||||
return HttpResponse(template.render(context))
|
return HttpResponse(template.render(context))
|
||||||
|
|
||||||
|
|
||||||
def get_lien_calendrier(etudiant, periode):
|
async def get_lien_calendrier(etudiant, periode):
|
||||||
try:
|
try:
|
||||||
lien = LienCalendrier.objects.get(etudiant=etudiant, periode=periode)
|
lien = await LienCalendrier.objects.aget(etudiant=etudiant, periode=periode)
|
||||||
except LienCalendrier.DoesNotExist:
|
except LienCalendrier.DoesNotExist:
|
||||||
code = uuid4().hex
|
code = uuid4().hex
|
||||||
lien = LienCalendrier(code=code, etudiant=etudiant, periode=periode)
|
lien = LienCalendrier(code=code, etudiant=etudiant, periode=periode)
|
||||||
lien.save()
|
await lien.asave()
|
||||||
|
|
||||||
return f"calendrier.ics?key={lien.code}"
|
return f"calendrier.ics?key={lien.code}"
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
#@login_required
|
||||||
def dashboard(request):
|
async def dashboard(request):
|
||||||
try:
|
try:
|
||||||
etudiant = Profil.from_request(
|
etudiant = await Profil.from_request(
|
||||||
request,
|
request,
|
||||||
preprocess=lambda query: query \
|
preprocess=lambda query: (query
|
||||||
.select_related("etudiant__classe") \
|
.select_related("etudiant__classe")
|
||||||
.prefetch_related("etudiant__classe__periode_set")
|
.prefetch_related("etudiant__classe__periode_set"))
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return redirect("colloscope.choix_profil")
|
return redirect("colloscope.choix_profil")
|
||||||
|
@ -79,19 +79,19 @@ def dashboard(request):
|
||||||
if not isinstance(etudiant, Etudiant):
|
if not isinstance(etudiant, Etudiant):
|
||||||
return HttpResponse("pas encore supporté")
|
return HttpResponse("pas encore supporté")
|
||||||
|
|
||||||
periode = etudiant.classe.periode_actuelle()
|
periode = await etudiant.classe.periode_actuelle()
|
||||||
groupe = etudiant.groupe_de_colle(periode)
|
groupe = await etudiant.groupe_de_colle(periode)
|
||||||
|
|
||||||
rotations = periode.query_rotations_etudiant(etudiant)
|
rotations = periode.query_rotations_etudiant(etudiant)
|
||||||
|
|
||||||
colles_par_sem = [None] * len(periode.range_semaines())
|
colles_par_sem = [None] * len(periode.range_semaines())
|
||||||
for i, n in enumerate(periode.range_semaines()):
|
for i, n in enumerate(periode.range_semaines()):
|
||||||
lundi = periode.classe.date_debut_sem(n)
|
lundi = periode.classe.date_debut_sem(n)
|
||||||
colles = rotations.filter(date__gte=lundi, date__lt=lundi+timedelta(weeks=1))
|
colles = rotations.filter(date__gte=lundi, date__lt=lundi + timedelta(weeks=1))
|
||||||
colles_par_sem[i] = n, lundi, colles
|
colles_par_sem[i] = n, lundi, colles
|
||||||
|
|
||||||
template = loader.get_template("dashboard.html")
|
template = loader.get_template("dashboard.html")
|
||||||
lien_calendrier = get_lien_calendrier(etudiant, periode)
|
lien_calendrier = await get_lien_calendrier(etudiant, periode)
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
"etudiant": etudiant,
|
"etudiant": etudiant,
|
||||||
|
@ -105,9 +105,9 @@ def dashboard(request):
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def marketplace(request):
|
async def marketplace(request):
|
||||||
try:
|
try:
|
||||||
etudiant = Profil.from_request(
|
etudiant = await Profil.from_request(
|
||||||
request,
|
request,
|
||||||
preprocess=lambda query: query \
|
preprocess=lambda query: query \
|
||||||
.select_related("etudiant__classe") \
|
.select_related("etudiant__classe") \
|
||||||
|
@ -119,14 +119,13 @@ def marketplace(request):
|
||||||
if not isinstance(etudiant, Etudiant):
|
if not isinstance(etudiant, Etudiant):
|
||||||
return HttpResponse("pas encore supporté")
|
return HttpResponse("pas encore supporté")
|
||||||
|
|
||||||
|
|
||||||
periode = etudiant.classe.periode_actuelle()
|
periode = etudiant.classe.periode_actuelle()
|
||||||
colles = periode.query_rotations_not_full()
|
colles = periode.query_rotations_not_full()
|
||||||
|
|
||||||
template = loader.get_template("marketplace.html")
|
template = loader.get_template("marketplace.html")
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
"colles" : colles
|
"colles": colles
|
||||||
}
|
}
|
||||||
|
|
||||||
return HttpResponse(template.render(context, request))
|
return HttpResponse(template.render(context, request))
|
||||||
|
@ -246,12 +245,12 @@ def amender(request, colle_id, est_positif):
|
||||||
#try:
|
#try:
|
||||||
if est_positif:
|
if est_positif:
|
||||||
(Rotation.objects
|
(Rotation.objects
|
||||||
.get(id=colle_id, creneau__periode__classe=etudiant.classe)
|
.get(id=colle_id, creneau__periode__classe=etudiant.classe)
|
||||||
.amender(est_positif=True, etudiant=etudiant, notifier=True))
|
.amender(est_positif=True, etudiant=etudiant, notifier=True))
|
||||||
else:
|
else:
|
||||||
(Rotation.objects
|
(Rotation.objects
|
||||||
.get(id=colle_id, groupes__etudiant=etudiant)
|
.get(id=colle_id, groupes__etudiant=etudiant)
|
||||||
.amender(est_positif=False, etudiant=etudiant, notifier=True))
|
.amender(est_positif=False, etudiant=etudiant, notifier=True))
|
||||||
|
|
||||||
return HttpResponse("ok")
|
return HttpResponse("ok")
|
||||||
#except Exception as e:
|
#except Exception as e:
|
||||||
|
@ -262,6 +261,7 @@ def amender(request, colle_id, est_positif):
|
||||||
def inscription(request, colle_id):
|
def inscription(request, colle_id):
|
||||||
return amender(request, colle_id, True)
|
return amender(request, colle_id, True)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def desinscription(request, colle_id):
|
def desinscription(request, colle_id):
|
||||||
return amender(request, colle_id, False)
|
return amender(request, colle_id, False)
|
||||||
|
|
|
@ -39,6 +39,7 @@ CORS_ORIGIN_WHITELIST = [
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
|
"daphne",
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
|
@ -76,7 +77,8 @@ TEMPLATES = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
WSGI_APPLICATION = 'kholles_web.wsgi.application'
|
ASGI_APPLICATION = "kholles_web.asgi.application"
|
||||||
|
#WSGI_APPLICATION = 'kholles_web.wsgi.application'
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases
|
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases
|
||||||
|
|
Loading…
Reference in New Issue