+ favicon
+ all variable names translated to English + Better marketplace
This commit is contained in:
parent
7b593eec08
commit
0e6eda5fa8
|
@ -2,32 +2,34 @@ from django.contrib import admin
|
|||
from colloscope.models import *
|
||||
|
||||
|
||||
@admin.register(Lycee)
|
||||
@admin.register(School)
|
||||
class LyceeAdmin(admin.ModelAdmin):
|
||||
list_display = ('uai', 'libelle', 'vacances')
|
||||
list_display = ('uai', 'description', 'vacation')
|
||||
|
||||
|
||||
admin.site.register(Classe)
|
||||
admin.site.register(Periode)
|
||||
admin.site.register(Matiere)
|
||||
admin.site.register(Critere)
|
||||
admin.site.register(Groupe)
|
||||
admin.site.register(Etudiant)
|
||||
admin.site.register(Appartenance)
|
||||
admin.site.register(Class)
|
||||
admin.site.register(Term)
|
||||
admin.site.register(Subject)
|
||||
admin.site.register(GroupType)
|
||||
admin.site.register(Group)
|
||||
admin.site.register(Student)
|
||||
admin.site.register(Member)
|
||||
admin.site.register(Colleur)
|
||||
|
||||
@admin.register(Creneau)
|
||||
class CreneauAdmin(admin.ModelAdmin):
|
||||
list_display = ('matiere', 'colleur', "periode", 'view_jour', "heure", "duree")
|
||||
list_filter = ("matiere", "colleur", "periode")
|
||||
|
||||
def view_jour(self, obj):
|
||||
@admin.register(Slot)
|
||||
class SlotAdmin(admin.ModelAdmin):
|
||||
list_display = ('subject', 'colleur', "term", 'view_day', "time", "duration")
|
||||
list_filter = ("subject", "colleur", "term")
|
||||
|
||||
def view_day(self, obj):
|
||||
jours = ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"]
|
||||
return jours[obj.jour]
|
||||
|
||||
view_jour.short_description = 'Jour'
|
||||
view_day.short_description = 'Day'
|
||||
|
||||
admin.site.register(Rotation)
|
||||
admin.site.register(Amendement)
|
||||
admin.site.register(Profil)
|
||||
admin.site.register(LienCalendrier)
|
||||
|
||||
admin.site.register(Colle)
|
||||
admin.site.register(Swap)
|
||||
admin.site.register(Profile)
|
||||
admin.site.register(CalendarLink)
|
||||
|
|
|
@ -10,11 +10,11 @@ from .create_calendar import get_calendar
|
|||
LOCAL_TZ = "Europe/Paris"
|
||||
|
||||
|
||||
def emailize(nom, prenom=None):
|
||||
if prenom is not None:
|
||||
def emailize(nom, first_name=None):
|
||||
if first_name is not None:
|
||||
return "{}.{}@example.com" \
|
||||
.format(
|
||||
prenom.replace(" ", "_").lower(),
|
||||
first_name.replace(" ", "_").lower(),
|
||||
nom.replace(" ", "_").lower()
|
||||
)
|
||||
else:
|
||||
|
@ -22,41 +22,41 @@ def emailize(nom, prenom=None):
|
|||
.format(nom.replace(" ", "_").lower())
|
||||
|
||||
|
||||
def to_calendar(etudiant, periode, include_EDT: bool = True):
|
||||
def to_calendar(student, term, include_EDT: bool = True):
|
||||
p = path.abspath('./static/Base_Calendar.ics')
|
||||
|
||||
with open(p) as f:
|
||||
cal = Calendar.from_ical(f.read())
|
||||
|
||||
rotations = periode.query_rotations_etudiant(etudiant)
|
||||
colles = term.query_colles_of_student(student)
|
||||
|
||||
for rotation in rotations:
|
||||
for colle in colles:
|
||||
event = Event()
|
||||
|
||||
summary = f"Colle {rotation.creneau.matiere} ({rotation.creneau.colleur})"
|
||||
summary = f"Colle {colle.slot.subject} ({colle.slot.colleur})"
|
||||
event.add("summary", summary)
|
||||
|
||||
start = rotation.datetime()
|
||||
fin = start + rotation.creneau.duree
|
||||
start = colle.datetime()
|
||||
fin = start + colle.slot.duration
|
||||
|
||||
event.add("dtstart", start, parameters={"tzid": LOCAL_TZ})
|
||||
event.add("dtend", fin, parameters={"tzid": LOCAL_TZ})
|
||||
event.add("dtstamp", datetime.now())
|
||||
event.add("uid", str(uuid4()))
|
||||
|
||||
event.add("location", f"{rotation.creneau.salle} ({rotation.creneau.periode.classe.lycee})")
|
||||
event.add("categories", "COLLE-" + str(rotation.creneau.matiere))
|
||||
event.add("location", f"{colle.slot.room} ({colle.slot.term.cls.school})")
|
||||
event.add("categories", "COLLE-" + str(colle.slot.subject))
|
||||
|
||||
description = f"Groupes: {','.join(str(groupe) for groupe in rotation.groupes.all())}"
|
||||
description = f"Groupes: {','.join(str(group) for group in colle.groups.all())}"
|
||||
event.add("description", description)
|
||||
|
||||
organizer = vCalAddress(f"mailto:{emailize(rotation.creneau.colleur.nom)}")
|
||||
organizer.params["cn"] = vText(str(rotation.creneau.colleur))
|
||||
organizer = vCalAddress(f"mailto:{emailize(colle.slot.colleur.name)}")
|
||||
organizer.params["cn"] = vText(str(colle.slot.colleur))
|
||||
organizer.params["role"] = vText("Colleur")
|
||||
event.add("organizer", organizer)
|
||||
|
||||
for e in rotation.groupe_effectif():
|
||||
attendee = vCalAddress("mailto:{emailize(e.nom, prenom=e.prenom)}")
|
||||
for e in colle.final_group():
|
||||
attendee = vCalAddress("mailto:{emailize(e.name, first_name=e.first_name)}")
|
||||
attendee.params["role"] = vText("Etudiant")
|
||||
attendee.params["cn"] = vText(str(e))
|
||||
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
# Generated by Django 5.0.4 on 2024-05-02 19:09
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('colloscope', '0011_alter_liencalendrier_code'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameModel(
|
||||
old_name='Lycee',
|
||||
new_name='School',
|
||||
),
|
||||
migrations.RenameModel(
|
||||
old_name='Classe',
|
||||
new_name='Class',
|
||||
),
|
||||
migrations.RenameModel(
|
||||
old_name='Periode',
|
||||
new_name='Term',
|
||||
),
|
||||
migrations.RenameModel(
|
||||
old_name='Matiere',
|
||||
new_name='Subject',
|
||||
),
|
||||
migrations.RenameModel(
|
||||
old_name='Critere',
|
||||
new_name='GroupType',
|
||||
),
|
||||
migrations.RenameModel(
|
||||
old_name='Groupe',
|
||||
new_name='Group',
|
||||
),
|
||||
migrations.RenameModel(
|
||||
old_name='Etudiant',
|
||||
new_name='Student',
|
||||
),
|
||||
migrations.RenameModel(
|
||||
old_name='Appartenance',
|
||||
new_name='Member',
|
||||
),
|
||||
migrations.RenameModel(
|
||||
old_name='Creneau',
|
||||
new_name='Slot',
|
||||
),
|
||||
migrations.RenameModel(
|
||||
old_name='Rotation',
|
||||
new_name='Colle',
|
||||
),
|
||||
migrations.RenameModel(
|
||||
old_name='Amendement',
|
||||
new_name='Swap',
|
||||
),
|
||||
migrations.RenameModel(
|
||||
old_name='Profil',
|
||||
new_name='Profile',
|
||||
),
|
||||
migrations.RenameModel(
|
||||
old_name='LienCalendrier',
|
||||
new_name='CalendarLink',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='colle',
|
||||
name='groupes',
|
||||
field=models.ManyToManyField(to='colloscope.group'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='member',
|
||||
name='groupe',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='colloscope.group'),
|
||||
),
|
||||
]
|
|
@ -3,17 +3,16 @@ from datetime import date, datetime, timedelta
|
|||
from asgiref.sync import async_to_sync
|
||||
from pytz import timezone
|
||||
|
||||
import asyncio
|
||||
import aiohttp
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import F, Q, Count
|
||||
from django.db.models import F, Q, Count, QuerySet
|
||||
from django.contrib.auth.models import User
|
||||
from django.conf import settings
|
||||
|
||||
from discord import Webhook
|
||||
|
||||
calendrier = {
|
||||
calendar = {
|
||||
"C": [
|
||||
(date(2023, 10, 21), date(2023, 11, 6)),
|
||||
(date(2023, 12, 23), date(2024, 1, 8)),
|
||||
|
@ -24,43 +23,43 @@ calendrier = {
|
|||
}
|
||||
|
||||
|
||||
class Lycee(models.Model):
|
||||
class School(models.Model):
|
||||
uai = models.CharField(max_length=10)
|
||||
libelle = models.CharField(max_length=100)
|
||||
vacances = models.CharField(max_length=1)
|
||||
description = models.CharField(max_length=100)
|
||||
vacation = models.CharField(max_length=1)
|
||||
|
||||
def __str__(self):
|
||||
return self.libelle
|
||||
def __str__(self) -> str:
|
||||
return self.description
|
||||
|
||||
|
||||
class Classe(models.Model):
|
||||
lycee = models.ForeignKey(Lycee, on_delete=models.CASCADE)
|
||||
libelle = models.CharField(max_length=20)
|
||||
annee = models.IntegerField()
|
||||
jour_zero = models.DateField()
|
||||
class Class(models.Model):
|
||||
school = models.ForeignKey(School, on_delete=models.CASCADE)
|
||||
description = models.CharField(max_length=20)
|
||||
year = models.IntegerField()
|
||||
day_zero = models.DateField()
|
||||
|
||||
def no_semaine(self, jour):
|
||||
def week_number(self, day: date) -> int:
|
||||
"""
|
||||
Entrées :
|
||||
- self
|
||||
- jour (datetime.date)
|
||||
- day (datetime.date)
|
||||
|
||||
Sortie :
|
||||
- Le numéro de la semaine contenant jour, sans compter les vacances.
|
||||
Renvoie un numéro non spécifiée si le jour est pendant une période de vacances
|
||||
- Le numéro de la semaine contenant day, sans compter les vacation.
|
||||
Renvoie un numéro non spécifiée si le day est pendant une période de vacation
|
||||
"""
|
||||
|
||||
zone = self.lycee.vacances
|
||||
vacances = calendrier[zone]
|
||||
jour0 = self.jour_zero
|
||||
zone = self.school.vacation
|
||||
vacation = calendar[zone]
|
||||
day0 = self.day_zero
|
||||
|
||||
n = 1 + (jour - jour0).days // 7
|
||||
for debut, fin in vacances:
|
||||
if jour > debut:
|
||||
n = 1 + (day - day0).days // 7
|
||||
for debut, fin in vacation:
|
||||
if day > debut:
|
||||
n -= round((fin - debut) / timedelta(weeks=1))
|
||||
return n
|
||||
|
||||
def no_aujourdhui(self):
|
||||
def today_number(self) -> int:
|
||||
"""
|
||||
Entrée:
|
||||
- self
|
||||
|
@ -69,9 +68,9 @@ class Classe(models.Model):
|
|||
- Le numéro de la semaine courante
|
||||
"""
|
||||
|
||||
return self.no_semaine(date.today())
|
||||
return self.week_number(date.today())
|
||||
|
||||
def date_debut_sem(self, n):
|
||||
def week_beginning_date(self, n: int) -> date:
|
||||
"""
|
||||
Entrée:
|
||||
- self
|
||||
|
@ -81,59 +80,57 @@ class Classe(models.Model):
|
|||
- Le date du lundi de la semaine n
|
||||
"""
|
||||
|
||||
zone = self.lycee.vacances
|
||||
vacances = calendrier[zone]
|
||||
jour0 = self.jour_zero
|
||||
zone = self.school.vacation
|
||||
vacation = calendar[zone]
|
||||
day0 = self.day_zero
|
||||
|
||||
jour = jour0 + (n - 1) * timedelta(weeks=1)
|
||||
day = day0 + (n - 1) * timedelta(weeks=1)
|
||||
|
||||
for debut, fin in vacances:
|
||||
if jour >= debut:
|
||||
jour += round((fin - debut) / timedelta(weeks=1)) * timedelta(weeks=1)
|
||||
for begin, end in vacation:
|
||||
if day >= begin:
|
||||
day += round((end - begin) / timedelta(weeks=1)) * timedelta(weeks=1)
|
||||
|
||||
return jour
|
||||
return day
|
||||
|
||||
def periode(self, jour):
|
||||
def term_of_date(self, day: date):
|
||||
"""
|
||||
Entrées :
|
||||
- self
|
||||
- jour (datetime.date)
|
||||
- day (datetime.date)
|
||||
|
||||
Sortie :
|
||||
- La période (si elle existe et est unique) contenant jour
|
||||
- La période (si elle existe et est unique) contenant day
|
||||
|
||||
Exceptions:
|
||||
- Le jour n'est pas dans une période
|
||||
- Le jour est au chevauchement de deux périodes
|
||||
- Le day n'est pas dans une période
|
||||
- Le day est au chevauchement de deux périodes
|
||||
"""
|
||||
return Periode.objects.get(classe=self, debut__lte=jour, fin__gte=jour)
|
||||
return Term.objects.get(cls=self, debut__lte=day, fin__gte=day)
|
||||
|
||||
def periode_actuelle(self):
|
||||
#return self.periode(date.today()) // ne fonctionne pas entre les périodes
|
||||
def current_term(self):
|
||||
"""
|
||||
On prend la période non révolue la plus récente
|
||||
"""
|
||||
|
||||
return Periode.objects \
|
||||
.filter(classe=self, fin__gte=date.today()) \
|
||||
.order_by("-debut") \
|
||||
.first()
|
||||
return (Term.objects
|
||||
.filter(cls=self, end__gte=date.today())
|
||||
.order_by("-begin")
|
||||
.first())
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.libelle} ({self.lycee.libelle})"
|
||||
return f"{self.description} ({self.lycee.description})"
|
||||
|
||||
|
||||
class Periode(models.Model):
|
||||
classe = models.ForeignKey(Classe, on_delete=models.CASCADE)
|
||||
#critere_colle = models.ForeignKey(Critere, on_delete=models.SET_NULL, null=True)
|
||||
libelle = models.CharField(max_length=100)
|
||||
debut = models.DateField()
|
||||
fin = models.DateField()
|
||||
class Term(models.Model):
|
||||
cls = models.ForeignKey(Class, on_delete=models.CASCADE)
|
||||
description = models.CharField(max_length=100)
|
||||
begin = models.DateField()
|
||||
end = models.DateField()
|
||||
|
||||
class Meta:
|
||||
ordering = ["debut"]
|
||||
ordering = ["begin"]
|
||||
|
||||
def range_semaines(self):
|
||||
def range_weeks(self) -> range:
|
||||
"""
|
||||
Entrée:
|
||||
- self
|
||||
|
@ -141,284 +138,284 @@ class Periode(models.Model):
|
|||
Sortie:
|
||||
- Un range des numéros de semaine
|
||||
"""
|
||||
return range(self.classe.no_semaine(self.debut), self.classe.no_semaine(self.fin) + 1)
|
||||
return range(self.cls.week_number(self.begin), self.cls.week_number(self.end) + 1)
|
||||
|
||||
def query_rotations(self):
|
||||
return (Rotation.objects
|
||||
.select_related("creneau", "creneau__periode")
|
||||
.prefetch_related("amendement_set")
|
||||
.filter(creneau__periode=self)
|
||||
.annotate(adt_plus=Count("amendement", filter=Q(amendement__est_positif=1)))
|
||||
.annotate(adt_minus=Count("amendement", filter=Q(amendement__est_positif=0)))
|
||||
.annotate(volume=F("creneau__capacite") + F("adt_plus") - F("adt_minus")))
|
||||
def query_colles(self) -> QuerySet:
|
||||
return (Colle.objects
|
||||
.select_related("slot", "slot__term")
|
||||
.prefetch_related("swap_set")
|
||||
.filter(slot__term=self)
|
||||
.annotate(adt_plus=Count("swap", filter=Q(swap__enroll=1)))
|
||||
.annotate(adt_minus=Count("swap", filter=Q(swap__enroll=0)))
|
||||
.annotate(volume=F("slot__capacity") + F("adt_plus") - F("adt_minus")))
|
||||
|
||||
def query_rotations_etudiant(self, etudiant):
|
||||
return (Rotation.objects
|
||||
.select_related("creneau", "creneau__periode")
|
||||
.prefetch_related("amendement_set")
|
||||
.filter(creneau__periode=self)
|
||||
.filter((Q(groupes__etudiant=etudiant)
|
||||
& ~Q(amendement__est_positif=0, amendement__etudiant=etudiant))
|
||||
| Q(amendement__est_positif=1, amendement__etudiant=etudiant))
|
||||
.annotate(adt_plus=Count("amendement", filter=Q(amendement__est_positif=1)))
|
||||
.annotate(adt_minus=Count("amendement", filter=Q(amendement__est_positif=0)))
|
||||
.annotate(volume=F("creneau__capacite") + F("adt_plus") - F("adt_minus")))
|
||||
def query_colles_of_student(self, student) -> QuerySet:
|
||||
return (Colle.objects
|
||||
.select_related("slot", "slot__term")
|
||||
.prefetch_related("swap_set")
|
||||
.filter(slot__term=self)
|
||||
.filter((Q(groups__student=student)
|
||||
& ~Q(swap__enroll=0, swap__student=student))
|
||||
| Q(swap__enroll=1, swap__student=student))
|
||||
.annotate(adt_plus=Count("swap", filter=Q(swap__enroll=1)))
|
||||
.annotate(adt_minus=Count("swap", filter=Q(swap__enroll=0)))
|
||||
.annotate(volume=F("slot__capacity") + F("adt_plus") - F("adt_minus")))
|
||||
|
||||
def query_rotations_not_full(self):
|
||||
return (self.query_rotations()
|
||||
.filter(volume__lt=F("creneau__capacite"), date__gte=date.today()))
|
||||
def query_colles_not_full(self) -> QuerySet:
|
||||
return (self.query_colles()
|
||||
.filter(volume__lt=F("slot__capacity"), date__gte=date.today()))
|
||||
|
||||
def __str__(self):
|
||||
return self.libelle
|
||||
def __str__(self) -> str:
|
||||
return self.description
|
||||
|
||||
|
||||
class Matiere(models.Model):
|
||||
classe = models.ForeignKey(Classe, on_delete=models.CASCADE)
|
||||
libelle = models.CharField(max_length=100)
|
||||
class Subject(models.Model):
|
||||
cls = models.ForeignKey(Class, on_delete=models.CASCADE)
|
||||
description = models.CharField(max_length=100)
|
||||
code = models.CharField(max_length=20)
|
||||
|
||||
def __str__(self):
|
||||
return self.libelle
|
||||
return self.description
|
||||
|
||||
|
||||
class Critere(models.Model):
|
||||
periode = models.ForeignKey(Periode, on_delete=models.CASCADE)
|
||||
libelle = models.CharField(max_length=100)
|
||||
class GroupType(models.Model):
|
||||
term = models.ForeignKey(Term, on_delete=models.CASCADE)
|
||||
description = models.CharField(max_length=100)
|
||||
|
||||
def __str__(self):
|
||||
return self.libelle
|
||||
return self.description
|
||||
|
||||
|
||||
class Groupe(models.Model):
|
||||
#class Meta:
|
||||
# ordering=[F("periode").classe.libelle, F("periode").libelle, "libelle"]
|
||||
class Group(models.Model):
|
||||
class Meta:
|
||||
ordering = ["term__cls__description", "term__description", "description"]
|
||||
|
||||
periode = models.ForeignKey(Periode, on_delete=models.CASCADE)
|
||||
critere = models.ForeignKey(Critere, null=True, on_delete=models.CASCADE)
|
||||
libelle = models.CharField(max_length=100)
|
||||
term = models.ForeignKey(Term, on_delete=models.CASCADE)
|
||||
type = models.ForeignKey(GroupType, null=True, on_delete=models.CASCADE)
|
||||
description = models.CharField(max_length=100)
|
||||
|
||||
membres = models.ManyToManyField("Etudiant", through="Appartenance")
|
||||
members = models.ManyToManyField("Student", through="Member")
|
||||
|
||||
def __str__(self):
|
||||
return self.libelle
|
||||
return self.description
|
||||
|
||||
#def get_colles(self):
|
||||
# return Rotation.objects.filter(creneau__periode=self.periode,
|
||||
# Q(groupes=self) || Q(a)).order_by("date")
|
||||
"""def get_colles(self):
|
||||
return Rotation.objects.filter(slot__term=self.term,
|
||||
Q(groupes=self) || Q(a)).order_by("date")
|
||||
|
||||
def get_colles_par_sem(self):
|
||||
semaines = ((s, self.periode.classe.date_debut_sem(s)) for s in self.periode.range_semaines())
|
||||
semaines = ((s, self.term.cls.week_beginning_date(s)) for s in self.term.range_semaines())
|
||||
colles_flat = self.get_colles()
|
||||
|
||||
return [
|
||||
(sem, lundi,
|
||||
colles_flat.filter(date__gte=lundi, date__lt=lundi + timedelta(weeks=1)))
|
||||
for sem, lundi in semaines
|
||||
]
|
||||
]"""
|
||||
|
||||
|
||||
class Etudiant(models.Model):
|
||||
class Student(models.Model):
|
||||
class Meta:
|
||||
ordering = ["classe", "nom", "prenom"]
|
||||
ordering = ["cls", "last_name", "first_name"]
|
||||
|
||||
classe = models.ForeignKey(Classe, on_delete=models.CASCADE)
|
||||
prenom = models.CharField(max_length=100)
|
||||
nom = models.CharField(max_length=100)
|
||||
groupes = models.ManyToManyField("Groupe", through="Appartenance")
|
||||
cls = models.ForeignKey(Class, on_delete=models.CASCADE)
|
||||
first_name = models.CharField(max_length=100)
|
||||
last_name = models.CharField(max_length=100)
|
||||
groups = models.ManyToManyField("Group", through="Member")
|
||||
|
||||
def appartient(self, groupe):
|
||||
def is_member(self, group):
|
||||
"""
|
||||
Renvoie si self appartient au groupe.
|
||||
"""
|
||||
return groupe.membres.contains(self)
|
||||
return group.members.contains(self)
|
||||
|
||||
def groupe_du_critere(self, periode, critere):
|
||||
def group_of_type(self, term, type_):
|
||||
"""
|
||||
Renvoie le groupe du critère auquel self appartient.
|
||||
"""
|
||||
if isinstance(critere, str):
|
||||
critere = Critere.objects.get(periode=periode, libelle=critere)
|
||||
if isinstance(type_, str):
|
||||
type_ = GroupType.objects.get(term=term, description=type_)
|
||||
|
||||
return Appartenance.objects.get(groupe__periode=periode, etudiant=self, groupe__critere=critere).groupe
|
||||
return Member.objects.get(group__term=term, student=self, group__type=type_).group
|
||||
|
||||
def groupe_de_colle(self, periode):
|
||||
def colle_group(self, term):
|
||||
"""
|
||||
Renvoie le groupe de colle de self pendant periode.
|
||||
Renvoie le groupe de colle de self pendant term.
|
||||
"""
|
||||
return self.groupe_du_critere(periode, "colle")
|
||||
return self.group_of_type(term, "colle")
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.prenom} {self.nom}"
|
||||
return f"{self.first_name} {self.last_name}"
|
||||
|
||||
|
||||
class Appartenance(models.Model):
|
||||
etudiant = models.ForeignKey(Etudiant, on_delete=models.CASCADE)
|
||||
groupe = models.ForeignKey(Groupe, on_delete=models.CASCADE)
|
||||
class Member(models.Model):
|
||||
student = models.ForeignKey(Student, on_delete=models.CASCADE)
|
||||
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
||||
|
||||
|
||||
class Colleur(models.Model):
|
||||
civilite = models.CharField(max_length=1)
|
||||
nom = models.CharField(max_length=100)
|
||||
gender = models.CharField(max_length=1)
|
||||
name = models.CharField(max_length=100)
|
||||
|
||||
def __str__(self):
|
||||
if self.civilite == "M":
|
||||
return f"M. {self.nom}"
|
||||
if self.gender == "M":
|
||||
return f"M. {self.name}"
|
||||
else:
|
||||
return f"Mme {self.nom}"
|
||||
return f"Mme {self.name}"
|
||||
|
||||
def get_classes(self):
|
||||
return (x.periode.classe for x in Creneau.objects.filter(colleur=self).select_related("periode__classe"))
|
||||
return (x.term_of_date.cls for x in Slot.objects.filter(colleur=self).select_related("term__cls"))
|
||||
|
||||
|
||||
class Creneau(models.Model):
|
||||
periode = models.ForeignKey(Periode, on_delete=models.CASCADE)
|
||||
jour = models.IntegerField()
|
||||
heure = models.TimeField()
|
||||
duree = models.DurationField()
|
||||
salle = models.CharField(max_length=20)
|
||||
matiere = models.ForeignKey(Matiere, on_delete=models.CASCADE)
|
||||
class Slot(models.Model):
|
||||
term = models.ForeignKey(Term, on_delete=models.CASCADE)
|
||||
day = models.IntegerField()
|
||||
time = models.TimeField()
|
||||
duration = models.DurationField()
|
||||
room = models.CharField(max_length=20)
|
||||
subject = models.ForeignKey(Subject, on_delete=models.CASCADE)
|
||||
colleur = models.ForeignKey(Colleur, on_delete=models.CASCADE)
|
||||
est_colle = models.BooleanField()
|
||||
capacite = models.IntegerField()
|
||||
type = models.ForeignKey(GroupType, on_delete=models.CASCADE)
|
||||
capacity = models.IntegerField()
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Creneaux"
|
||||
verbose_name_plural = "slots"
|
||||
|
||||
def __str__(self):
|
||||
jours = ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"]
|
||||
days = ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"]
|
||||
|
||||
return f"Colle {self.matiere} avec {self.colleur} {jours[self.jour]} {self.heure}"
|
||||
return f"Colle {self.subject} avec {self.colleur} {days[self.day]} {self.time}"
|
||||
|
||||
|
||||
class Rotation(models.Model):
|
||||
class Colle(models.Model):
|
||||
class Meta:
|
||||
ordering = ["creneau__periode__classe", "creneau__matiere__libelle", "creneau__colleur__nom", "date",
|
||||
"creneau__heure"]
|
||||
ordering = ["slot__term__cls", "slot__subject__description", "slot__colleur__name", "date",
|
||||
"slot__time"]
|
||||
|
||||
creneau = models.ForeignKey(Creneau, on_delete=models.CASCADE)
|
||||
groupes = models.ManyToManyField(Groupe)
|
||||
slot = models.ForeignKey(Slot, on_delete=models.CASCADE)
|
||||
groups = models.ManyToManyField(Group)
|
||||
date = models.DateField()
|
||||
|
||||
def groupe_initial(self):
|
||||
def initial_group(self):
|
||||
"""
|
||||
Renvoie les étudiants inscrits à la colle sans prendre en compte les amendements.
|
||||
Renvoie les étudiants inscrits à la colle sans prendre en compte les swaps.
|
||||
"""
|
||||
return Etudiant.objects.filter(id__in=Appartenance.objects.filter(groupe__in=self.groupes.all()))
|
||||
return Student.objects.filter(id__in=Member.objects.filter(groupe__in=self.groups.all()))
|
||||
|
||||
def groupe_effectif(self):
|
||||
def final_group(self):
|
||||
"""
|
||||
Renvoie les étudiants inscrits à la colle en tenant compte des amendements.
|
||||
Renvoie les étudiants inscrits à la colle en tenant compte des swaps.
|
||||
"""
|
||||
amendements = Amendement.objects.filter(rotation=self)
|
||||
swaps = Swap.objects.filter(colle=self)
|
||||
|
||||
return Etudiant.objects.filter(
|
||||
(Q(id__in=Appartenance.objects.filter(groupe__in=self.groupes.all()))
|
||||
| Q(id__in=amendements.filter(est_positif=True).values("etudiant_id")))
|
||||
& ~Q(id__in=amendements.filter(est_positif=False).values("etudiant_id"))
|
||||
return Student.objects.filter(
|
||||
(Q(id__in=Member.objects.filter(group__in=self.groups.all()))
|
||||
| Q(id__in=swaps.filter(enroll=True).values("student_id")))
|
||||
& ~Q(id__in=swaps.filter(enroll=False).values("student_id"))
|
||||
)
|
||||
|
||||
def effectif(self):
|
||||
def volume(self):
|
||||
"""
|
||||
Renvoie le nombre d'étudiants inscrits à la colle en tenant compte des amendements.
|
||||
Renvoie le nombre d'étudiants inscrits à la colle en tenant compte des swaps.
|
||||
"""
|
||||
n_base = sum(len(groupe.membres.count()) for groupe in self.groupes.all())
|
||||
n_plus = len(Amendement.objects.filter(est_positif=True, rotation=self))
|
||||
n_moins = len(Amendement.objects.filter(est_positif=False, rotation=self))
|
||||
n_base = sum(len(group.members.count()) for group in self.groups.all())
|
||||
n_plus = len(Swap.objects.filter(enroll=True, colle=self))
|
||||
n_moins = len(Swap.objects.filter(enroll=False, colle=self))
|
||||
|
||||
return n_base + n_plus - n_moins
|
||||
|
||||
def est_pleine(self):
|
||||
def is_full(self):
|
||||
"""
|
||||
Renvoie si la colle est pleine.
|
||||
"""
|
||||
eff = self.effectif()
|
||||
return eff >= self.creneau.capacite
|
||||
eff = self.volume()
|
||||
return eff >= self.slot.capacity
|
||||
|
||||
def est_modifiee(self):
|
||||
def is_edited(self):
|
||||
"""
|
||||
Renvoie si la colle a été amendée.
|
||||
"""
|
||||
return Amendement.objects.filter(rotation=self).exists()
|
||||
return Swap.objects.filter(colle=self).exists()
|
||||
|
||||
def amender(self, etudiant, est_positif, notifier=False):
|
||||
def amend(self, student, enroll, notify=False):
|
||||
"""
|
||||
Amende la colle en (des)inscrivant etudiant à la colle self, selon est_positif.
|
||||
Amende la colle en (des)inscrivant student à la colle self, selon enroll.
|
||||
"""
|
||||
|
||||
if Amendement.objects.filter(rotation=self, etudiant=etudiant, est_positif=est_positif).exists():
|
||||
if Swap.objects.filter(colle=self, student=student, enroll=enroll).exists():
|
||||
raise Exception("Duplication")
|
||||
elif Amendement.objects.filter(rotation=self, etudiant=etudiant, est_positif=not est_positif).exists():
|
||||
# les amendements complémentaires s'annulent
|
||||
Amendement.objects.get(rotation=self, etudiant=etudiant, est_positif=not est_positif).delete()
|
||||
elif est_positif and any(etudiant.appartient(groupe) for groupe in self.groupes.all()):
|
||||
elif Swap.objects.filter(colle=self, student=student, enroll=not enroll).exists():
|
||||
# les swaps complémentaires s'annulent
|
||||
Swap.objects.get(colle=self, student=student, enroll=not enroll).delete()
|
||||
elif enroll and any(student.is_member(group) for group in self.groups.all()):
|
||||
# on ne peut pas s'ajouter si on est dans le groupe de base
|
||||
raise Exception("Vous êtes déjà dans le groupe")
|
||||
elif not est_positif and all(not etudiant.appartient(groupe) for groupe in self.groupes.all()):
|
||||
elif not enroll and all(not student.is_member(group) for group in self.groups.all()):
|
||||
raise Exception("Vous n'êtes pas dans le groupe")
|
||||
elif est_positif and self.est_pleine():
|
||||
elif enroll and self.is_full():
|
||||
raise Exception("Capacité dépassée")
|
||||
else:
|
||||
amendement = Amendement(rotation=self, etudiant=etudiant, est_positif=est_positif)
|
||||
amendement.save()
|
||||
swap = Swap(colle=self, student=student, enroll=enroll)
|
||||
swap.save()
|
||||
|
||||
if notifier:
|
||||
func = async_to_sync(amendement.notifier)
|
||||
func()
|
||||
#if notify:
|
||||
# func = async_to_sync(swap.notify)
|
||||
# func()
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.creneau} le {self.date} avec groupes {'+'.join(str(groupe) for groupe in self.groupes.all())}"
|
||||
return f"{self.slot} le {self.date} avec groupes {'+'.join(str(groupe) for groupe in self.groups.all())}"
|
||||
|
||||
def datetime(self):
|
||||
return datetime.combine(self.date, self.creneau.heure, tzinfo=timezone("Europe/Paris"))
|
||||
return datetime.combine(self.date, self.slot.time, tzinfo=timezone("Europe/Paris"))
|
||||
|
||||
|
||||
class Amendement(models.Model):
|
||||
est_positif = models.BooleanField()
|
||||
rotation = models.ForeignKey(Rotation, on_delete=models.CASCADE)
|
||||
etudiant = models.ForeignKey(Etudiant, on_delete=models.CASCADE)
|
||||
class Swap(models.Model):
|
||||
enroll = models.BooleanField()
|
||||
colle = models.ForeignKey(Colle, on_delete=models.CASCADE)
|
||||
student = models.ForeignKey(Student, on_delete=models.CASCADE)
|
||||
|
||||
async def notifier(self):
|
||||
async def notify(self):
|
||||
async with aiohttp.ClientSession() as session:
|
||||
webhook = Webhook.from_url(settings.DISCORD_NOTIFY_WEBHOOK_URL, session=session)
|
||||
|
||||
if self.est_positif:
|
||||
await webhook.send(f"Colle réservée : {self.rotation}", username=settings.DISCORD_NOTIFY_WEBHOOK_USERNAME)
|
||||
if self.enroll:
|
||||
await webhook.send(f"Colle réservée : {self.colle}", username=settings.DISCORD_NOTIFY_WEBHOOK_USERNAME)
|
||||
else:
|
||||
await webhook.send(f"Colle libérée : {self.rotation}", username=settings.DISCORD_NOTIFY_WEBHOOK_USERNAME)
|
||||
await webhook.send(f"Colle libérée : {self.colle}", username=settings.DISCORD_NOTIFY_WEBHOOK_USERNAME)
|
||||
|
||||
|
||||
class Profil(models.Model):
|
||||
utilisateur = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
|
||||
etudiant = models.ForeignKey(Etudiant, null=True, blank=True, on_delete=models.SET_NULL)
|
||||
class Profile(models.Model):
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
|
||||
student = models.ForeignKey(Student, null=True, blank=True, on_delete=models.SET_NULL)
|
||||
colleur = models.ForeignKey(Colleur, null=True, blank=True, on_delete=models.SET_NULL)
|
||||
|
||||
def __str__(self):
|
||||
return f"Profil {self.utilisateur} : {self.etudiant} ; {self.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("profil"):
|
||||
case "etudiant":
|
||||
profil = preprocess(Profil.objects.filter(utilisateur=user)).get()
|
||||
return profil.etudiant
|
||||
match session.get("profile"):
|
||||
case "student":
|
||||
profil = preprocess(Profile.objects.filter(user=user)).get()
|
||||
return profil.student
|
||||
case "colleur":
|
||||
profil = preprocess(Profil.objects.filter(utilisateur=user)).get()
|
||||
profil = preprocess(Profile.objects.filter(user=user)).get()
|
||||
return profil.colleur
|
||||
case _:
|
||||
raise ValueError("profil non choisi")
|
||||
|
||||
|
||||
class LienCalendrier(models.Model):
|
||||
code = models.CharField(max_length=32, unique=True)
|
||||
etudiant = models.ForeignKey(Etudiant, on_delete=models.CASCADE)
|
||||
periode = models.ForeignKey(Periode, on_delete=models.CASCADE)
|
||||
class CalendarLink(models.Model):
|
||||
key = models.CharField(max_length=32, unique=True)
|
||||
student = models.ForeignKey(Student, on_delete=models.CASCADE)
|
||||
term = models.ForeignKey(Term, on_delete=models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=['etudiant', 'periode'], name='unique_etudiant_periode_combination'
|
||||
fields=['student', 'term'], name='unique_student_term_combination'
|
||||
)
|
||||
]
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
from datetime import date, timedelta
|
||||
|
||||
from django.shortcuts import redirect
|
||||
from django.http import HttpResponse
|
||||
from fpdf import FPDF
|
||||
|
||||
from colloscope.models import *
|
||||
|
||||
from fpdf import FPDF
|
||||
|
||||
|
||||
class PDF(FPDF):
|
||||
def liste_eleves(self, periode):
|
||||
classe = periode.classe
|
||||
etudiants = Etudiant.objects.filter(classe=classe)
|
||||
def liste_eleves(self, term):
|
||||
cls = term.cls
|
||||
students = Student.objects.filter(cls=cls)
|
||||
|
||||
with self.table(
|
||||
align="RIGHT",
|
||||
|
@ -19,27 +21,27 @@ class PDF(FPDF):
|
|||
for th in ("Nom", "Prénom", "Grp.", "TD",): #"LV1", "LV2"):
|
||||
header.cell(th)
|
||||
|
||||
for etu in etudiants:
|
||||
for etu in students:
|
||||
row = table.row()
|
||||
row.cell(etu.nom.upper()) # Nom
|
||||
row.cell(etu.prenom) # Prénom
|
||||
row.cell(etu.groupe_de_colle(periode).libelle) # Groupe
|
||||
row.cell(etu.groupe_du_critere(periode, "td").libelle)
|
||||
row.cell(etu.last_name.upper()) # Nom
|
||||
row.cell(etu.first_name) # Prénom
|
||||
row.cell(etu.colle_group(term).description) # Groupe
|
||||
row.cell(etu.group_of_type(term, "td").description)
|
||||
#row.cell("??") # LV1
|
||||
#row.cell("??") # LV2
|
||||
|
||||
|
||||
def table_colloscope(self, periode, heading=True, est_colle=True):
|
||||
semaines = periode.range_semaines()
|
||||
lundis = [ periode.classe.date_debut_sem(n) for n in semaines ]
|
||||
creneaux = Creneau.objects.filter(periode=periode, est_colle=est_colle)
|
||||
jours = ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"]
|
||||
def table_colloscope(self, term, heading=True, type="colle"):
|
||||
weeks = term.range_weeks()
|
||||
lundis = [term.cls.week_beginning_date(n) for n in weeks]
|
||||
slots = Slot.objects.filter(term=term, type__description=type)
|
||||
weekdays = ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"]
|
||||
|
||||
with self.table(
|
||||
align="LEFT",
|
||||
width=190,
|
||||
line_height=3,
|
||||
col_widths=(2, 1, 1, 3, 1, *(1,)*len(semaines)),
|
||||
col_widths=(2, 1, 1, 3, 1, *(1,)*len(weeks)),
|
||||
num_heading_rows=2 if heading else 0,
|
||||
first_row_as_headings=heading) as table:
|
||||
|
||||
|
@ -48,7 +50,7 @@ class PDF(FPDF):
|
|||
for th in ("Matière", "Jour", "Heure", "Colleur", "Salle"):
|
||||
header.cell(th, align="CENTER", rowspan=2)
|
||||
|
||||
for sem in semaines:
|
||||
for sem in weeks:
|
||||
header.cell(str(sem), align="CENTER")
|
||||
|
||||
header2 = table.row()
|
||||
|
@ -56,38 +58,38 @@ class PDF(FPDF):
|
|||
header2.cell(lundi.strftime("%d/%m/%y"), align="CENTER")
|
||||
|
||||
|
||||
for i, c in enumerate(creneaux):
|
||||
matiere = c.matiere
|
||||
jour = c.jour
|
||||
heure = c.heure
|
||||
for i, c in enumerate(slots):
|
||||
subject = c.subject
|
||||
day = c.day
|
||||
time = c.time
|
||||
colleur = c.colleur
|
||||
salle = c.salle
|
||||
room = c.room
|
||||
|
||||
row = table.row()
|
||||
row.cell(matiere.libelle)
|
||||
row.cell(jours[jour])
|
||||
row.cell(heure.strftime("%H:%M"))
|
||||
row.cell("{} {}".format("M." if colleur.civilite=="M" else "Mme", colleur.nom.upper()))
|
||||
row.cell(salle)
|
||||
row.cell(subject.description)
|
||||
row.cell(weekdays[day])
|
||||
row.cell(time.strftime("%H:%M"))
|
||||
row.cell("{} {}".format("M." if colleur.gender=="M" else "Mme", colleur.name.upper()))
|
||||
row.cell(room)
|
||||
|
||||
for s in semaines:
|
||||
lundi = periode.classe.date_debut_sem(s)
|
||||
for s in weeks:
|
||||
lundi = term.cls.week_beginning_date(s)
|
||||
|
||||
if Rotation.objects.filter(creneau=c, date__gte=lundi, date__lt=lundi+timedelta(weeks=1)).exists():
|
||||
r = Rotation.objects.get(creneau=c, date__gte=lundi, date__lt=lundi+timedelta(weeks=1))
|
||||
groupes = r.groupes
|
||||
content = ", ".join(g.libelle for g in groupes.all())
|
||||
if Colle.objects.filter(slot=c, date__gte=lundi, date__lt=lundi + timedelta(weeks=1)).exists():
|
||||
r = Colle.objects.get(slot=c, date__gte=lundi, date__lt=lundi + timedelta(weeks=1))
|
||||
groups = r.groups
|
||||
content = ", ".join(g.description for g in groups.all())
|
||||
|
||||
with self.local_context(fill_color=(255, 100, 100) if r.est_modifiee() else None):
|
||||
with self.local_context(fill_color=(255, 100, 100) if r.is_edited() else None):
|
||||
row.cell(content, align="CENTER")
|
||||
else:
|
||||
row.cell()
|
||||
|
||||
def generate(periode):
|
||||
def generate(term):
|
||||
pdf = PDF(orientation="landscape", format="a4")
|
||||
pdf.set_font("helvetica", size=6)
|
||||
|
||||
titre = f"Colloscope {periode.classe.libelle} {periode.libelle}"
|
||||
titre = f"Colloscope {term.cls.description} {term.description}"
|
||||
|
||||
pdf.set_title(titre)
|
||||
pdf.set_author("colles.mp2i-vms.fr")
|
||||
|
@ -97,39 +99,39 @@ def generate(periode):
|
|||
pdf.set_line_width(0.1)
|
||||
base_y = pdf.t_margin + 10
|
||||
pdf.set_y(base_y)
|
||||
pdf.liste_eleves(periode)
|
||||
pdf.liste_eleves(term)
|
||||
pdf.set_y(base_y)
|
||||
pdf.table_colloscope(periode)
|
||||
pdf.table_colloscope(term)
|
||||
pdf.y += 3
|
||||
pdf.table_colloscope(periode, heading=False, est_colle=False)
|
||||
pdf.table_colloscope(term, heading=False, type="td")
|
||||
|
||||
return pdf
|
||||
|
||||
|
||||
def handle(request):
|
||||
try:
|
||||
etudiant = Profil.from_request(
|
||||
student = Profile.from_request(
|
||||
request,
|
||||
preprocess=lambda query: query \
|
||||
.select_related("etudiant__classe") \
|
||||
.prefetch_related("etudiant__classe__periode_set")
|
||||
.select_related("student__cls") \
|
||||
.prefetch_related("student__cls__term_set")
|
||||
)
|
||||
except ValueError:
|
||||
return redirect("colloscope.choix_profil")
|
||||
return redirect("colloscope.select_profile")
|
||||
|
||||
if not isinstance(etudiant, Etudiant):
|
||||
if not isinstance(student, Student):
|
||||
return HttpResponse("pas encore supporté")
|
||||
|
||||
|
||||
periode_str = request.GET.get("periode")
|
||||
if periode_str is None:
|
||||
periode = etudiant.classe.periode_actuelle()
|
||||
term_str = request.GET.get("term")
|
||||
if term_str is None:
|
||||
term = student.cls.current_term()
|
||||
else:
|
||||
periode = Periode.objects.get(id=int(periode_str), classe=etudiant.classe)
|
||||
term = Term.objects.get(id=int(term_str), cls=student.cls)
|
||||
|
||||
return generate(periode)
|
||||
return generate(term)
|
||||
|
||||
|
||||
def main():
|
||||
periode = Periode.objects.get(id=3)
|
||||
return generate(periode)
|
||||
term = Term.objects.get(id=3)
|
||||
return generate(term)
|
||||
|
|
|
@ -2,8 +2,8 @@ from colloscope.models import *
|
|||
|
||||
def table_colloscope(periode, heading=True, est_colle=True):
|
||||
semaines = periode.range_semaines()
|
||||
lundis = [ periode.classe.date_debut_sem(n) for n in semaines ]
|
||||
creneaux = Creneau.objects.filter(periode=periode, est_colle=est_colle)
|
||||
lundis = [periode.classe.week_beginning_date(n) for n in semaines]
|
||||
creneaux = Slot.objects.filter(periode=periode, est_colle=est_colle)
|
||||
jours = ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"]
|
||||
|
||||
s = ""
|
||||
|
@ -28,26 +28,26 @@ def table_colloscope(periode, heading=True, est_colle=True):
|
|||
s += "</tr>\n"
|
||||
|
||||
for i, c in enumerate(creneaux):
|
||||
matiere = c.matiere
|
||||
matiere = c.subject
|
||||
jour = c.jour
|
||||
heure = c.heure
|
||||
heure = c.time
|
||||
colleur = c.colleur
|
||||
salle = c.salle
|
||||
salle = c.room
|
||||
|
||||
s += "<tr>\n"
|
||||
s += f"<td>{matiere.libelle}</td>\n"
|
||||
s += f"<td>{matiere.description}</td>\n"
|
||||
s += f"<td>{jours[jour]}</td>\n"
|
||||
s += f"<td>{heure.strftime('%H:%M')}</td>\n"
|
||||
s += "<td>{} {}</td>\n".format("M." if colleur.civilite=="M" else "Mme", colleur.nom.upper())
|
||||
s += f"<td>salle</td>\n"
|
||||
|
||||
for sem in semaines:
|
||||
if Rotation.objects.filter(creneau=c, semaine=sem).exists():
|
||||
r = Rotation.objects.get(creneau=c, semaine=sem)
|
||||
if Colle.objects.filter(creneau=c, semaine=sem).exists():
|
||||
r = Colle.objects.get(creneau=c, semaine=sem)
|
||||
groupes = r.groupes
|
||||
content = ", ".join(g.libelle for g in groupes.all())
|
||||
content = ", ".join(g.description for g in groupes.all())
|
||||
|
||||
if r.est_modifiee():
|
||||
if r.is_edited():
|
||||
s += f"<td class='modif'>{content}</td>\n"
|
||||
else:
|
||||
s += f"<td>{content}</td>\n"
|
||||
|
|
|
@ -7,27 +7,43 @@
|
|||
<h1>Tableau de bord</h1>
|
||||
|
||||
<p>
|
||||
Bienvenue {{ etudiant }}. Votre lycée est {{ periode.classe.lycee.libelle }}, et votre classe est {{ periode.classe.libelle }}.
|
||||
Bienvenue {{ student }}. Votre lycée est {{ term.cls.school.description }}, et votre classe est {{ term.cls.description }}.
|
||||
</p>
|
||||
|
||||
<p>Période actuelle : {{ periode }}. Votre groupe de colle est {{ groupe }}. <a href="table.html">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>
|
||||
<a href="{{ lien_calendrier }}">Exporter en .ics (ceci est un permalien public)</a>
|
||||
|
||||
|
||||
<p><a href="{{ calendar_link }}">Exporter en .ics (ceci est un permalien public)</a></p>
|
||||
|
||||
<p><a href="{% url "colloscope.marketplace" %}">Accéder au marketplace</a></p>
|
||||
<ul>
|
||||
{% for n, lundi, colles in rotations %}
|
||||
{% for n, lundi, colles in colles_per_sem %}
|
||||
<li>Semaine {{n}} ({{lundi}})</li>
|
||||
<ul>
|
||||
{% for colle in colles %}
|
||||
<li>{{ colle.creneau.matiere }} ({{ colle.creneau.colleur }}) <a href="{% url "colloscope.desinscription" colle_id=colle.id %}">Absent ?</a>:</li>
|
||||
<ul>
|
||||
<li>Le {{ colle.date }} à {{ colle.creneau.heure }}</li>
|
||||
<li>Groupes : {{ colle.groupes.all | join:"+" }}</li>
|
||||
<li>Salle : {{ colle.creneau.salle }}</li>
|
||||
<li>Capacité : {{ colle.volume }} / {{ colle.creneau.capacite }}</li>
|
||||
</ul>
|
||||
{% endfor %}
|
||||
{% if colles %}
|
||||
{% for colle in colles %}
|
||||
<li>{{ colle.slot.subject }} ({{ colle.slot.colleur }})</li>
|
||||
<ul>
|
||||
<li>Le {{ colle.date }} à {{ colle.slot.time }}</li>
|
||||
<li>Groupes : {{ colle.groups.all | join:"+" }}</li>
|
||||
<li>Salle : {{ colle.slot.room }}</li>
|
||||
<li>Capacité : {{ colle.volume }} / {{ colle.slot.capacity }}</li>
|
||||
<li>Absent ?
|
||||
<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 }}">
|
||||
<input type="submit" value="Rendre disponible">
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
Pas de colles à venir cette semaine.
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
|
|
@ -3,21 +3,34 @@
|
|||
{% block title %}Marketplace{% endblock title %}
|
||||
|
||||
{% block main %}
|
||||
<a href="{% url "colloscope.dashboard" %}">Retour au tableau de bord</a>
|
||||
|
||||
<h1>Marketplace</h1>
|
||||
|
||||
Bienvenue sur le marketplace.
|
||||
|
||||
Les colles libres sont :
|
||||
|
||||
<ul>
|
||||
{% for colle in colles %}
|
||||
<li>Colle !</li>
|
||||
{% if colles %}
|
||||
<ul>
|
||||
<li>{{ colle }}</li>
|
||||
<li>Places occupées : {{ colle.volume }} / {{ colle.creneau.capacite }}</li>
|
||||
<li><a href={% url "colloscope.inscription" colle_id=colle.id %}>Réserver</a></li>
|
||||
Les colles libres sont :
|
||||
{% for colle in colles %}
|
||||
<li>Colle !</li>
|
||||
<ul>
|
||||
<li>{{ colle }}</li>
|
||||
<li>Places occupées : {{ colle.volume }} / {{ colle.slot.capacity }}</li>
|
||||
<li>
|
||||
<form action="{% url "colloscope.enroll" %}"
|
||||
method="POST"
|
||||
onsubmit="return confirm('Êtes-vous sûr de vouloir vous inscrire à la colle {{ colle }} ');">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="colle_id" value="{{ colle.id }}">
|
||||
<input type="submit" value="Réserver">
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
Aucune colle n'est disponible
|
||||
{% endif %}
|
||||
|
||||
{% endblock main %}
|
|
@ -17,16 +17,16 @@
|
|||
{% block main %}
|
||||
|
||||
<p>
|
||||
Lycée : {{ periode.classe.lycee.libelle }}. Classe : {{ periode.classe.libelle }}. <a href="dashboard.html">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 : {{ periode.libelle }}</h2>
|
||||
<h2>Colloscope : {{ term.description }}</h2>
|
||||
|
||||
<form method="get" action="{% url "colloscope.table" %}">
|
||||
Changer de période :
|
||||
<select name="periode" id="periode">
|
||||
{% for p in periode.classe.periode_set.all %}
|
||||
{% if p.id == periode.id %}
|
||||
<select name="term" id="term">
|
||||
{% for p in term.cls.term_set.all %}
|
||||
{% if p.id == term.id %}
|
||||
<option value="{{ p.id }}" selected>{{ p }}</option>
|
||||
{% else %}
|
||||
<option value="{{ p.id }}" selected>{{ p }}</option>
|
||||
|
@ -36,8 +36,8 @@
|
|||
<button type="submit">Valider</button>
|
||||
</form>
|
||||
|
||||
{% if request.GET.periode %}
|
||||
<a href="export.pdf?periode={{ request.GET.periode }}" target="_blank">Exporter le colloscope</a>
|
||||
{% if request.GET.term %}
|
||||
<a href="export.pdf?term={{ request.GET.term }}" target="_blank">Exporter le colloscope</a>
|
||||
{% else %}
|
||||
<a href="export.pdf" target="_blank">Exporter le colloscope</a>
|
||||
{% endif %}
|
||||
|
@ -53,7 +53,7 @@
|
|||
<col>
|
||||
</colgroup>
|
||||
<colgroup>
|
||||
{% for _ in semaines %}
|
||||
{% for _ in weeks %}
|
||||
<col>
|
||||
{% endfor %}
|
||||
</colgroup>
|
||||
|
@ -64,32 +64,32 @@
|
|||
<th rowspan=2>Heure</th>
|
||||
<th rowspan=2>Colleur</th>
|
||||
<th rowspan=2>Salle</th>
|
||||
{% for n in semaines %}
|
||||
{% for n in weeks %}
|
||||
<th>{{ n }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
{% for lundi in lundis %}
|
||||
<th>{{ lundi | strftime:"%d/%m/%y" }}</th>
|
||||
{% for monday in mondays %}
|
||||
<th>{{ monday | strftime:"%d/%m/%y" }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
|
||||
|
||||
{% for c, rs in rotations %}
|
||||
{% for c, rs in colles %}
|
||||
<tr>
|
||||
<td>{{ c.matiere.libelle }}</td>
|
||||
<td>{{ jours | getitem:c.jour }}</td>
|
||||
<td>{{ c.heure | strftime:"%H:%M" }}</td>
|
||||
<td>{{ c.subject.description }}</td>
|
||||
<td>{{ days | getitem:c.day }}</td>
|
||||
<td>{{ c.time | strftime:"%H:%M" }}</td>
|
||||
<td>{{ c.colleur }}</td>
|
||||
<td>{{ c.salle }}</td>
|
||||
<td>{{ c.room }}</td>
|
||||
|
||||
{% for sem, exists, r, est_modifiee, groupes in rs %}
|
||||
{% for sem, exists, r, is_edited, groups in rs %}
|
||||
{% if exists %}
|
||||
{% if est_modifiee %}
|
||||
<td class="modif">{{ groupes | join:"," }}</td>
|
||||
{% if is_edited %}
|
||||
<td class="modif">{{ groups | join:"," }}</td>
|
||||
{% else %}
|
||||
<td>{{ groupes | join:"," }}</td>
|
||||
<td>{{ groups | join:"," }}</td>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<td></td>
|
||||
|
|
|
@ -6,9 +6,9 @@ urlpatterns = [
|
|||
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("calendrier.ics", views.icalendar, name="colloscope.calendrier"),
|
||||
path("choix_profil", views.choix_profil, name="colloscope.choix_profil"),
|
||||
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/inscription/<int:colle_id>", views.inscription, name="colloscope.inscription"),
|
||||
path("action/desinscription/<int:colle_id>", views.desinscription, name="colloscope.desinscription"),
|
||||
path("action/enroll", views.enroll, name="colloscope.enroll"),
|
||||
path("action/withdraw", views.withdraw, name="colloscope.withdraw"),
|
||||
]
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
from datetime import date, timedelta
|
||||
from uuid import uuid4
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.shortcuts import redirect
|
||||
from django.http import HttpResponse
|
||||
from django import forms
|
||||
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 colloscope.models import *
|
||||
from colloscope.table import table_colloscope
|
||||
from colloscope.pdfexport import handle
|
||||
from colloscope.icalexport import to_calendar
|
||||
|
||||
|
||||
def handler404(request):
|
||||
template = loader.get_template("404.html")
|
||||
#response.status_code = 404
|
||||
context = {}
|
||||
return HttpResponse(template.render(context))
|
||||
return HttpResponse(template.render(context), status=404)
|
||||
|
||||
|
||||
def home_redirect(request):
|
||||
|
@ -25,169 +23,182 @@ def home_redirect(request):
|
|||
|
||||
|
||||
@login_required
|
||||
def choix_profil(request):
|
||||
def select_profile(request):
|
||||
user = request.user
|
||||
session = request.session
|
||||
|
||||
if not Profil.objects.filter(utilisateur=user).exists():
|
||||
profil = Profil(utilisateur=user)
|
||||
profil.save()
|
||||
if not Profile.objects.filter(user=user).exists():
|
||||
profile = Profile(user=user)
|
||||
profile.save()
|
||||
else:
|
||||
profil = Profil.objects.get(utilisateur=user)
|
||||
profile = Profile.objects.get(user=user)
|
||||
|
||||
if profil.etudiant is not None and profil.colleur is None:
|
||||
session["profil"] = "etudiant"
|
||||
if profile.student is not None and profile.colleur is None:
|
||||
session["profile"] = "student"
|
||||
return redirect("/colloscope/")
|
||||
elif profil.colleur is not None and profil.etudiant is None:
|
||||
session["profil"] = "colleur"
|
||||
elif profile.colleur is not None and profile.student is None:
|
||||
session["profile"] = "colleur"
|
||||
return redirect("/colloscope/")
|
||||
else:
|
||||
if profil.etudiant is not None:
|
||||
template = loader.get_template("choix_profil.html")
|
||||
if profile.student is not None:
|
||||
template = loader.get_template("select_profile.html")
|
||||
else:
|
||||
template = loader.get_template("profil_non_associe.html")
|
||||
template = loader.get_template("unbound_profile.html")
|
||||
|
||||
context = {
|
||||
"profil": profil,
|
||||
"profile": profile,
|
||||
}
|
||||
return HttpResponse(template.render(context))
|
||||
|
||||
|
||||
def get_lien_calendrier(etudiant, periode):
|
||||
def get_lien_calendrier(student, term):
|
||||
try:
|
||||
lien = LienCalendrier.objects.get(etudiant=etudiant, periode=periode)
|
||||
except LienCalendrier.DoesNotExist:
|
||||
code = uuid4().hex
|
||||
lien = LienCalendrier(code=code, etudiant=etudiant, periode=periode)
|
||||
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.code}"
|
||||
return f"calendrier.ics?key={lien.key}"
|
||||
|
||||
|
||||
#@login_required
|
||||
@login_required
|
||||
def dashboard(request):
|
||||
try:
|
||||
etudiant = Profil.from_request(
|
||||
student = Profile.from_request(
|
||||
request,
|
||||
preprocess=lambda query: (query
|
||||
.select_related("etudiant__classe")
|
||||
.prefetch_related("etudiant__classe__periode_set"))
|
||||
.select_related("student__cls")
|
||||
.prefetch_related("student__cls__term_set"))
|
||||
)
|
||||
except ValueError:
|
||||
return redirect("colloscope.choix_profil")
|
||||
return redirect("colloscope.select_profile")
|
||||
|
||||
if not isinstance(etudiant, Etudiant):
|
||||
if not isinstance(student, Student):
|
||||
return HttpResponse("pas encore supporté")
|
||||
|
||||
periode = etudiant.classe.periode_actuelle()
|
||||
groupe = etudiant.groupe_de_colle(periode)
|
||||
term = student.cls.current_term()
|
||||
group = student.colle_group(term)
|
||||
|
||||
rotations = periode.query_rotations_etudiant(etudiant)
|
||||
colles = term.query_colles_of_student(student)
|
||||
|
||||
colles_par_sem = [None] * len(periode.range_semaines())
|
||||
for i, n in enumerate(periode.range_semaines()):
|
||||
lundi = periode.classe.date_debut_sem(n)
|
||||
colles = rotations.filter(date__gte=lundi, date__lt=lundi + timedelta(weeks=1))
|
||||
colles_par_sem[i] = n, lundi, colles
|
||||
colles_per_sem = [None] * len(term.range_weeks())
|
||||
for k, n in enumerate(term.range_weeks()):
|
||||
lundi = term.cls.week_beginning_date(n)
|
||||
colles_per_sem[k] = n, lundi, colles.filter(date__gte=max(lundi, date.today()),
|
||||
date__lt=lundi + timedelta(weeks=1))
|
||||
|
||||
template = loader.get_template("dashboard.html")
|
||||
lien_calendrier = get_lien_calendrier(etudiant, periode)
|
||||
calendar_link = get_calendar_link(student, term)
|
||||
|
||||
context = {
|
||||
"etudiant": etudiant,
|
||||
"periode": periode,
|
||||
"groupe": groupe,
|
||||
"rotations": colles_par_sem,
|
||||
"lien_calendrier": lien_calendrier,
|
||||
"student": student,
|
||||
"term": term,
|
||||
"group": group,
|
||||
"colles_per_sem": colles_per_sem,
|
||||
"calendar_link": calendar_link,
|
||||
}
|
||||
|
||||
return HttpResponse(template.render(context, request))
|
||||
|
||||
|
||||
|
||||
class AmendForm(forms.Form):
|
||||
colle_id = forms.IntegerField(widget=forms.HiddenInput(), required=True)
|
||||
|
||||
|
||||
class EnrollForm(AmendForm):
|
||||
pass
|
||||
|
||||
|
||||
class WithdrawForm(AmendForm):
|
||||
pass
|
||||
|
||||
|
||||
@login_required
|
||||
def marketplace(request):
|
||||
try:
|
||||
etudiant = Profil.from_request(
|
||||
student = Profile.from_request(
|
||||
request,
|
||||
preprocess=lambda query: query \
|
||||
.select_related("etudiant__classe") \
|
||||
.prefetch_related("etudiant__classe__periode_set")
|
||||
preprocess=lambda query: (query
|
||||
.select_related("student__cls")
|
||||
.prefetch_related("student__cls__term_set"))
|
||||
)
|
||||
except ValueError:
|
||||
return redirect("colloscope.choix_profil")
|
||||
return redirect("colloscope.select_profile")
|
||||
|
||||
if not isinstance(etudiant, Etudiant):
|
||||
if not isinstance(student, Student):
|
||||
return HttpResponse("pas encore supporté")
|
||||
|
||||
periode = etudiant.classe.periode_actuelle()
|
||||
colles = periode.query_rotations_not_full()
|
||||
|
||||
template = loader.get_template("marketplace.html")
|
||||
term = student.cls.current_term()
|
||||
colles = term.query_colles_not_full()
|
||||
|
||||
context = {
|
||||
"colles": colles
|
||||
"colles": colles,
|
||||
}
|
||||
|
||||
return HttpResponse(template.render(context, request))
|
||||
return render(request, "marketplace.html", context)
|
||||
|
||||
|
||||
@login_required
|
||||
def colloscope(request):
|
||||
try:
|
||||
etudiant = Profil.from_request(
|
||||
student = Profile.from_request(
|
||||
request,
|
||||
preprocess=lambda query: query \
|
||||
.select_related("etudiant__classe") \
|
||||
.prefetch_related("etudiant__classe__periode_set")
|
||||
preprocess=lambda query: (query
|
||||
.select_related("student__cls")
|
||||
.prefetch_related("student__cls__term_set"))
|
||||
)
|
||||
except ValueError:
|
||||
return redirect("colloscope.choix_profil")
|
||||
return redirect("colloscope.select_profile")
|
||||
|
||||
if not isinstance(etudiant, Etudiant):
|
||||
if not isinstance(student, Student):
|
||||
return HttpResponse("pas encore supporté")
|
||||
|
||||
periode_str = request.GET.get("periode")
|
||||
if periode_str is None:
|
||||
periode = etudiant.classe.periode_actuelle()
|
||||
term_str = request.GET.get("term")
|
||||
if term_str is None:
|
||||
term = student.cls.current_term()
|
||||
else:
|
||||
try:
|
||||
periode = Periode.objects.get(id=int(periode_str), classe=etudiant.classe)
|
||||
except Periode.DoesNotExist:
|
||||
term = Term.objects.get(id=int(term_str), cls=student.cls)
|
||||
except Term.DoesNotExist:
|
||||
template = loader.get_template("404.html")
|
||||
context = {}
|
||||
response = HttpResponse(template.render(context, request))
|
||||
response.status_code = 404
|
||||
|
||||
creneaux = Creneau.objects \
|
||||
.filter(periode=periode, est_colle=True) \
|
||||
.prefetch_related("rotation_set")
|
||||
return response
|
||||
|
||||
semaines = periode.range_semaines()
|
||||
rotations = [(c, []) for c in creneaux]
|
||||
for c, l in rotations:
|
||||
for sem in semaines:
|
||||
lundi = periode.classe.date_debut_sem(sem)
|
||||
slots = Slot.objects \
|
||||
.filter(term=term, type__description="colle") \
|
||||
.prefetch_related("colle_set")
|
||||
|
||||
rot = Rotation.objects.filter(creneau=c, date__gte=lundi, date__lt=lundi + timedelta(weeks=1))
|
||||
weeks = term.range_weeks()
|
||||
colles = [(c, []) for c in slots]
|
||||
for c, l in colles:
|
||||
for sem in weeks:
|
||||
lundi = term.cls.week_beginning_date(sem)
|
||||
|
||||
rot = Colle.objects.filter(slot=c, date__gte=lundi, date__lt=lundi + timedelta(weeks=1))
|
||||
exists = rot.exists()
|
||||
|
||||
if exists:
|
||||
r = rot.first()
|
||||
est_modifiee = r.est_modifiee()
|
||||
groupes = (g.libelle for g in r.groupes.all())
|
||||
is_edited = r.is_edited()
|
||||
groups = (g.description for g in r.groups.all())
|
||||
else:
|
||||
r = est_modifiee = groupes = None
|
||||
r = is_edited = groups = None
|
||||
|
||||
l.append((sem, exists, r, est_modifiee, groupes))
|
||||
l.append((sem, exists, r, is_edited, groups))
|
||||
|
||||
template = loader.get_template("table.html")
|
||||
|
||||
context = {
|
||||
"periode": periode,
|
||||
"semaines": semaines,
|
||||
"lundis": [periode.classe.date_debut_sem(n) for n in semaines],
|
||||
"jours": ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
|
||||
"rotations": rotations,
|
||||
"term": term,
|
||||
"weeks": weeks,
|
||||
"mondays": [term.cls.week_beginning_date(n) for n in weeks],
|
||||
"days": ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
|
||||
"colles": colles,
|
||||
}
|
||||
|
||||
return HttpResponse(template.render(context, request))
|
||||
|
@ -198,75 +209,79 @@ def export(request):
|
|||
return HttpResponse(bytes(handle(request).output()), content_type="application/pdf")
|
||||
|
||||
|
||||
def get_lien_calendrier(etudiant, periode):
|
||||
def get_calendar_link(student, term):
|
||||
try:
|
||||
lien = LienCalendrier.objects.get(etudiant=etudiant, periode=periode)
|
||||
except LienCalendrier.DoesNotExist:
|
||||
lien = CalendarLink.objects.get(student=student, term=term)
|
||||
except CalendarLink.DoesNotExist:
|
||||
code = uuid4().hex
|
||||
lien = LienCalendrier(code=code, etudiant=etudiant, periode=periode)
|
||||
lien = CalendarLink(key=key, student=student, term=term)
|
||||
lien.save()
|
||||
|
||||
return f"calendrier.ics?key={lien.code}"
|
||||
return f"export/calendar/{lien.key}/calendar.ics"
|
||||
|
||||
|
||||
def icalendar(request):
|
||||
if request.GET.get("key") is not None:
|
||||
try:
|
||||
lien = LienCalendrier.objects.get(code=request.GET.get("key"))
|
||||
def icalendar(request, key):
|
||||
try:
|
||||
link = CalendarLink.objects.get(key=key)
|
||||
|
||||
if not request.GET.get("edt"):
|
||||
return HttpResponse(to_calendar(lien.etudiant, lien.periode, include_EDT=True).to_ical(),
|
||||
content_type="text/calendar")
|
||||
|
||||
return HttpResponse(to_calendar(lien.etudiant, lien.periode, include_EDT=True).to_ical(),
|
||||
if not request.GET.get("edt"):
|
||||
return HttpResponse(to_calendar(link.student, link.term, include_EDT=True).to_ical(),
|
||||
content_type="text/calendar")
|
||||
|
||||
except LienCalendrier.DoesNotExist:
|
||||
return HttpResponse("Invalid key", status=404)
|
||||
else:
|
||||
return HttpResponse("Unspecified key", status=404)
|
||||
return HttpResponse(to_calendar(link.student, link.term, include_EDT=True).to_ical(),
|
||||
content_type="text/calendar")
|
||||
|
||||
except CalendarLink.DoesNotExist:
|
||||
return HttpResponse("Invalid key", status=404)
|
||||
|
||||
|
||||
@login_required
|
||||
def amender(request, colle_id, est_positif):
|
||||
def amend(request, colle_id, do_enroll):
|
||||
try:
|
||||
etudiant = Profil.from_request(
|
||||
student = Profile.from_request(
|
||||
request,
|
||||
preprocess=lambda query: query \
|
||||
.select_related("etudiant__classe") \
|
||||
.prefetch_related("etudiant__classe__periode_set")
|
||||
preprocess=lambda query: (query
|
||||
.select_related("student__cls")
|
||||
.prefetch_related("student__cls__term_set"))
|
||||
)
|
||||
except ValueError:
|
||||
return redirect("colloscope.choix_profil")
|
||||
|
||||
if not isinstance(etudiant, Etudiant):
|
||||
if not isinstance(student, Student):
|
||||
return HttpResponse("pas encore supporté")
|
||||
|
||||
#try:
|
||||
if est_positif:
|
||||
(Rotation.objects
|
||||
.get(id=colle_id, creneau__periode__classe=etudiant.classe)
|
||||
.amender(est_positif=True, etudiant=etudiant, notifier=True))
|
||||
if do_enroll:
|
||||
(Colle.objects
|
||||
.get(id=colle_id, slot__term__cls=student.cls)
|
||||
.amend(enroll=True, student=student, notify=True))
|
||||
else:
|
||||
(Rotation.objects
|
||||
.get(id=colle_id, groupes__etudiant=etudiant)
|
||||
.amender(est_positif=False, etudiant=etudiant, notifier=True))
|
||||
|
||||
return HttpResponse("ok")
|
||||
#except Exception as e:
|
||||
# return HttpResponse(f"aïe : {e}")
|
||||
(Colle.objects
|
||||
.get(id=colle_id, groups__student=student)
|
||||
.amend(enroll=False, student=student, notify=True))
|
||||
|
||||
|
||||
@require_POST
|
||||
@login_required
|
||||
def inscription(request, colle_id):
|
||||
return amender(request, colle_id, True)
|
||||
def enroll(request):
|
||||
form = WithdrawForm(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
colle_id = form.cleaned_data["colle_id"]
|
||||
amend(request, colle_id, True)
|
||||
else:
|
||||
print("!!!! invalide")
|
||||
|
||||
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
|
||||
|
||||
@require_POST
|
||||
@login_required
|
||||
def desinscription(request, colle_id):
|
||||
return amender(request, colle_id, False)
|
||||
def withdraw(request):
|
||||
form = WithdrawForm(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
colle_id = form.cleaned_data["colle_id"]
|
||||
amend(request, colle_id, False)
|
||||
else:
|
||||
print("!!!! invalide")
|
||||
|
||||
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
|
||||
|
||||
def data_dump(request):
|
||||
template = loader.get_template("data_dump.html")
|
||||
return HttpResponse(template.render())
|
||||
|
|
|
@ -16,12 +16,14 @@ Including another URLconf
|
|||
"""
|
||||
from django.contrib import admin, auth
|
||||
from django.urls import include, path
|
||||
from django.contrib.staticfiles import views as vstatic
|
||||
|
||||
from colloscope.views import home_redirect
|
||||
|
||||
urlpatterns = [
|
||||
path('', home_redirect, name="home"),
|
||||
path("favicon.ico", lambda req: vstatic.serve(req, "favicon.ico")),
|
||||
path('colloscope/', include('colloscope.urls')),
|
||||
path('admin/', admin.site.urls),
|
||||
path('comptes/', include("django.contrib.auth.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
|
@ -20,11 +20,11 @@ def scrape(periode, chemin):
|
|||
else:
|
||||
c = Colleur.objects.get(nom=nom_colleur, civilite=civilite)
|
||||
|
||||
if not Matiere.objects.filter(classe=periode.classe, libelle=matiere).exists():
|
||||
m = Matiere(classe=periode.classe, libelle=matiere, code=matiere.upper())
|
||||
if not Subject.objects.filter(classe=periode.classe, libelle=matiere).exists():
|
||||
m = Subject(classe=periode.classe, libelle=matiere, code=matiere.upper())
|
||||
m.save()
|
||||
else:
|
||||
m = Matiere.objects.get(classe=periode.classe, libelle=matiere)
|
||||
m = Subject.objects.get(classe=periode.classe, libelle=matiere)
|
||||
|
||||
jours_dict = {"dimanche": 0, "lundi": 1, "mardi": 2, "mercredi": 3, "jeudi": 4, "vendredi": 5, "samedi": 6}
|
||||
j = jours_dict[jour]
|
||||
|
@ -40,11 +40,11 @@ def scrape(periode, chemin):
|
|||
|
||||
print(f"--> Traitement de {c=}, {m=}, {j=}, {h=}, {d=}, {c2=}")
|
||||
|
||||
if not Creneau.objects.filter(periode=periode, jour=j, heure=h, duree=d, matiere=m, colleur=c, est_colle=True, capacite=c2).exists():
|
||||
creneau = Creneau(periode=periode, jour=j, heure=h, duree=d, salle="nc", matiere=m, colleur=c, est_colle=True, capacite=c2)
|
||||
if not Slot.objects.filter(periode=periode, jour=j, heure=h, duree=d, matiere=m, colleur=c, est_colle=True, capacite=c2).exists():
|
||||
creneau = Slot(periode=periode, jour=j, heure=h, duree=d, salle="nc", matiere=m, colleur=c, est_colle=True, capacite=c2)
|
||||
creneau.save()
|
||||
else:
|
||||
creneau = Creneau.objects.get(periode=periode, jour=j, heure=h, duree=d, matiere=m, colleur=c, est_colle=True, capacite=c2)
|
||||
creneau = Slot.objects.get(periode=periode, jour=j, heure=h, duree=d, matiere=m, colleur=c, est_colle=True, capacite=c2)
|
||||
|
||||
for i, r in enumerate(rotations):
|
||||
sem = headers[4+i].split("/")
|
||||
|
@ -53,16 +53,16 @@ def scrape(periode, chemin):
|
|||
|
||||
s = date.fromisoformat("-".join(sem)) + (j-1) * timedelta(days=1)
|
||||
|
||||
if not Rotation.objects.filter(creneau=creneau, date=s):
|
||||
rot = Rotation(creneau=creneau, date=s)
|
||||
if not Colle.objects.filter(creneau=creneau, date=s):
|
||||
rot = Colle(creneau=creneau, date=s)
|
||||
rot.save()
|
||||
else:
|
||||
rot = Rotation.objects.get(creneau=creneau, date=s)
|
||||
rot = Colle.objects.get(creneau=creneau, date=s)
|
||||
|
||||
rot.groupes.add(Groupe.objects.get(libelle=r))
|
||||
rot.groupes.add(Group.objects.get(libelle=r))
|
||||
|
||||
def main():
|
||||
periode = Periode.objects.get(id=3)
|
||||
periode = Term.objects.get(id=3)
|
||||
scrape(periode, "colloscope.csv")
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
|
@ -7,5 +7,5 @@
|
|||
{% endblock header %}
|
||||
|
||||
{% block main %}
|
||||
Vous vous êtes perdu.
|
||||
Vous vous êtes perdu. ASKMULLER
|
||||
{% endblock main %}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
{% if request.user.is_authenticated %}
|
||||
<div class="bandeau">
|
||||
Vous êtes connecté avec le compte <b>{{ user.username }}</b>.
|
||||
{% if request.session.profil == "etudiant" %}
|
||||
{% if request.session.profil == "student" %}
|
||||
Profil actuel : étudiant.
|
||||
{% elif request.session.profil == "colleur" %}
|
||||
Profil actuel : colleur.
|
||||
|
|
Loading…
Reference in New Issue