From fcb2d4efe1f5442b7a7ccf846ce63c68a95af389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Mogu=C3=A9rou?= Date: Sat, 23 Dec 2023 15:34:22 +0100 Subject: [PATCH 01/11] Revert "Actualiser Resources/eleves.csv" This reverts commit 1ec8fca6288dc01ee118fd145d26ae403cd71e5d. --- Resources/eleves.csv | 92 ++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/Resources/eleves.csv b/Resources/eleves.csv index 8821c28..261d139 100644 --- a/Resources/eleves.csv +++ b/Resources/eleves.csv @@ -1,46 +1,46 @@ -Nom,Prénon,Groupe de coll,TD -ABOUJAIB,Alexandre,1,A -AJAN,George,1,A -AKRAD,Lina,5,A -AUBERT,Nicolas,3,A -BADR,Roman,3,A -BAZIRE,Aurélien,3,A -BOIT,Arthur,5,A -BOUBKER,Youssef,5,A -BOUDJEMA,Dylan,1,A -CHIRIAC,Minhea,7,A -COURIER,Marine,7,A -DAGUIN,Joseph,7,A -DAUGUEN,Gabriel,9,A -DE WEER,Matthias,9,A -DESBOUIS,Katell,11,A -DUPOUY,Jérémie,11,A -HARIRI--GAUTIER-PICARD,Grégoire,11,A -JURICEVIC,Matteo,13,A -KNANOUA,Anas,13,A -LESENNE,Pierrick,13,A -LIN,Hao,9,A -MASBATIN,Lucas,15,A -MAYURAN,Mithushan,15,A -MESSAHLI,Yassine,2,B -MOGUÉROU,Valentin,2,B -MOHELLEBI,Mathéo,2,B -MOUISSET--FERRARA,Maël,4,B -OTTAVI,Corentin,4,B -PONCE,Alexian,4,B -PUJOL,Raphaël,6,B -PUSTETTO,Mathis,6,B -RADICE,Roman,6,B -RAT,Evelyn,8,B -ROUSSE,Louis,8,B -ROUX,Gaetan,8,B -ROUYRE--CROS,Célian,10,B -SOURBE,François-G,10,B -STOURBE,Simon,10,B -THAI,Dany,12,B -THÉODORE,Jonathan,12,B -VANDROUX,Benoit,12,B -VEYSSIERE,Thibaud,14,B -VIÉ,Adrien,14,B -YE,Luan,14,B -ZARKA,Amélie,15,A +Nom,Prénon,Groupe de coll,TD +ABOUJAIB,Alexandre,1,A +AJAN,George,1,A +AKRAD,Lina,5,A +AUBERT,Nicolas,3,A +BADR,Roman,3,A +BAZIRE,Aurélien,3,A +BOIT,Arthur,5,A +BOUBKER,Youssef,5,A +BOUDJEMA,Dylan,1,A +CHIRIAC,Mihnea,7,A +COURIER,Marine,7,A +DAGUIN,Joseph,7,A +DAUGUEN,Gabriel,9,A +DE WEER,Matthias,9,A +DESBOUIS,Katell,11,A +DUPOUY,Jérémie,11,A +HARIRI--GAUTIER-PICARD,Grégoire,11,A +JURICEVIC,Matteo,13,A +KNANOUA,Anas,13,A +LESENNE,Pierrick,13,A +LIN,Hao,9,A +MASBATIN,Lucas,15,A +MAYURAN,Mithushan,15,A +MESSAHLI,Yassine,2,B +MOGUÉROU,Valentin,2,B +MOHELLEBI,Mathéo,2,B +MOUISSET--FERRARA,Maël,4,B +OTTAVI,Corentin,4,B +PONCE,Alexian,4,B +PUJOL,Raphaël,6,B +PUSTETTO,Mathis,6,B +RADICE,Roman,6,B +RAT,Evelyn,8,B +ROUSSE,Louis,8,B +ROUX,Gaetan,8,B +ROUYRE--CROS,Célian,10,B +SOURBE,François-G,10,B +STOURBE,Simon,10,B +THAI,Dany,12,B +THÉODORE,Jonathan,12,B +VANDROUX,Benoit,12,B +VEYSSIERE,Thibaud,14,B +VIÉ,Adrien,14,B +YE,Luan,14,B +ZARKA,Amélie,15,A -- 2.45.2 From e44066743d18e5fe3da13d46fbf295f230fd2bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Mogu=C3=A9rou?= Date: Tue, 26 Dec 2023 20:07:20 +0100 Subject: [PATCH 02/11] Quoicoubeh --- main.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/main.py b/main.py index 856bd5c..a533f34 100644 --- a/main.py +++ b/main.py @@ -1,13 +1,13 @@ from typing import Optional, List from os import getenv, listdir -import discord +import re +import discord from discord import app_commands from discord.app_commands import Choice from discord.ext import commands from dotenv import load_dotenv - load_dotenv() @@ -16,12 +16,14 @@ class MyClient(commands.Bot): intents = discord.Intents.none() intents.guilds = True intents.messages = True + intents.message_content = True super().__init__(intents=intents, command_prefix=".") self.MY_GUILD = discord.Object(id=getenv("GUILD_ID")) self.initial_extensions = ["cogs." + f[:-3] for f in listdir("./cogs") if f.endswith(".py") and f.__str__() != "__init__.py"] + #self.add_listener(self.on_message) async def setup_hook(self): # cogs @@ -36,6 +38,11 @@ class MyClient(commands.Bot): print(f"Discord version : {discord.__version__}") print('------') + async def on_message(self, msg): + p = re.compile("[qQ]uoi[ \\.!?;]*$") + print(f"{msg!r}") + if p.search(msg.content) is not None: + await msg.reply("Quoicoubeh !") if __name__ == "__main__": client = MyClient() -- 2.45.2 From 1e771544aacb7ce179f9dac13db1f72365c9d2a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Mogu=C3=A9rou?= Date: Mon, 1 Jan 2024 13:55:03 +0100 Subject: [PATCH 03/11] ajout des guillemets --- main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.py b/main.py index a533f34..35b4e7c 100644 --- a/main.py +++ b/main.py @@ -39,7 +39,7 @@ class MyClient(commands.Bot): print('------') async def on_message(self, msg): - p = re.compile("[qQ]uoi[ \\.!?;]*$") + p = re.compile("[qQ]uoi[ \\.!?;\"»]*$") print(f"{msg!r}") if p.search(msg.content) is not None: await msg.reply("Quoicoubeh !") -- 2.45.2 From 3d9995773e86666c5340da8de9ec7f7e036246af Mon Sep 17 00:00:00 2001 From: joseph Date: Mon, 12 Feb 2024 15:00:25 +0100 Subject: [PATCH 04/11] ajout edt semestre 2 --- Resources/Base_Calendar.ics | 2 +- Resources/colloscope-v2.csv | 73 ++++++++++ Resources/eleves-v2.csv | 46 +++++++ cogs/edt.py | 3 +- create_calendar.py | 263 ++++++++++++++++++++++++++---------- 5 files changed, 310 insertions(+), 77 deletions(-) create mode 100644 Resources/colloscope-v2.csv create mode 100644 Resources/eleves-v2.csv diff --git a/Resources/Base_Calendar.ics b/Resources/Base_Calendar.ics index 8afc8c0..1d0d7bb 100644 --- a/Resources/Base_Calendar.ics +++ b/Resources/Base_Calendar.ics @@ -1,5 +1,5 @@ BEGIN:VCALENDAR -PRODID:-//mp2i-vms//Stackity Bot Inc//EN +PRODID:-//mp2i-vms-[2]-(23-24)-s2//Stackity Bot Inc//EN VERSION:2.0 CALSCALE:GREGORIAN METHOD:PUBLISH diff --git a/Resources/colloscope-v2.csv b/Resources/colloscope-v2.csv new file mode 100644 index 0000000..47f761e --- /dev/null +++ b/Resources/colloscope-v2.csv @@ -0,0 +1,73 @@ +;Semaine;;;;;;;18;19;20;21;22;23 +;;;;;;;;26/02/24;04/03/24;11/03/24;18/03/24;25/03/24;01/04/24 +type;matière;jour;heure;durée;colleur;récurrent (semaines);salle;;;;;; +;;;;;;;;;;;;; +colle;Mathématiques;vendredi;17h;1h;M. OUBAHA;;C382;2;3;4;5;6;7 +colle;Anglais;mercredi;14h;1h;Mme. LE GOURIELLEC;;C393;2;3;4;1;2;3 +colle;Mathématiques;mercredi;15h;1h;M. BOULLY;;R004;3;4;5;6;7;8 +colle;Physique;mardi;14h;1h;Mme. CHEVALIER;;R103;9;4;5;6;7;8 +colle;Mathématiques;mardi;18h;1h;M. RAPIN;;V152;4;5;6;7;8;9 +colle;Anglais;mardi;14h;1h;Mme. BELAGOUNE;;C454;14;15;6;7;8;9 +;pas de colle;;;;;;;5;6;7;8;9;10 +colle;Physique;mardi;17h;1h;M. COLIN;;C386;5;6;7;8;9;10 +colle;Mathématiques;mercredi;13h30;1h;M. BOUVEROT;;;6;7;8;9;10;11 +colle;Anglais;lundi;13h;1h;M. HERBAUT;;V052;6;7;8;9;10;11 +colle;Mathématiques;mardi;14h;1h;Mme. MULLAERT;;M070;7;8;9;10;11;12 +colle;Physique;mercredi;17h;1h;M. POUPY;;R012;7;8;9;10;11;12 +;pas de colle;;;;;;;;;;;; +colle;Anglais;mercredi;16h;1h;Mme. MANN;;C380;8;9;10;11;12;13 +;pas de colle;;;;;;;9;10;11;12;13;14 +colle;Physique;mardi;17h;1h;Mme. CHEVALIER;;R103;3;10;1;2;3;14 +colle;Mathématiques;mercredi;13h;1h;M. CARPINTERO;;V152;10;11;12;13;14;15 +colle;Anglais;mercredi;15h;1h;Mme. LE GOURIELLEC;;C393;10;11;12;13;14;1 +colle;Mathématiques;mercredi;14h30;1h;M. BOUVEROT;;;11;12;13;14;15;13 +colle;Physique;jeudi;18h;1h;M. DE ROUX;;C054;11;12;13;14;15; +colle;Mathématiques;vendredi;18h;1h;M. OUBAHA;;C382;12;13;14;15;12;1 +colle;Anglais;jeudi;15h;1h;Mme. BELAGOUNE;;C386;12;13;14;15;;15 +;pas de colle;;;;;;;13;14;15;11;1;2 +colle;Physique;vendredi;16h;1h;Mme. CHIBANI;;C284;13;14;15;;1;2 +colle;Mathématiques;mercredi;14h;1h;M. BOULLY;;R004;14;15;10;1;2;3 +colle;Anglais;jeudi;14h;1h;Mme. BELAGOUNE;;C386;4;5;;5;6;7 +colle;Mathématiques;jeudi;18h;1h;M. RAPIN;;C284;15;9;1;2;3;4 +colle;Physique;lundi;12h;1h;Mme. CHEVALIER;;R105;15;;11;12;13;4 +colle;Mathématiques;mercredi;14h;1h;M. CARPINTERO;;V152;8;1;2;3;4;5 +colle;Anglais;mercredi;17h;1h;Mme. MANN;;C380;;1;2;3;4;5 +;pas de colle;;;;;;;1;2;3;4;5;6 +colle;Physique;mercredi;18h;1h;M. POUPY;;R012;1;2;3;4;5;6 +colle;Informatique;lundi;12h;1h;M. JOSPIN;;;13;4;9;6;11;7 +colle;Informatique;lundi;13h;1h;M. JOSPIN;;;14;8;15;5;13;8 +colle;TP Info;mercredi;14h;2h;;;;5,12,15;10,9,13;11,6,14;4,7,8;5,9,10;6,15,12 +colle;TP Info;mercredi;16h;2h;;;;6,11,9;7,14,10;4,5,8;12,13,15;; +;;;;;;;;;;;;; +cours;TP Physique;lundi;8h30;1h30;Mme CHEVALIER;1;R417;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15 +cours;TP Physique;lundi;10h;1h30;Mme CHEVALIER;1;R417;gr 1 à 8;gr 1 à 8;gr 1 à 8;gr 1 à 8;gr 1 à 8;gr 1 à 8 +cours;TP Info;lundi;10h;1h30;M. HALFON;2;C154;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15 +cours;TP Info;lundi;8h30;1h30;M. HALFON;2;C154;gr 4 à 8;gr 4 à 8;gr 4 à 8;gr 4 à 8;gr 4 à 8;gr 4 à 8 +cours;TD Maths;vendredi;11h;2h;Mme MULLAERT;2;M103;B+2+3;A+1;B+2+3;A+1;B+2+3;A+1 +cours;TD Maths;vendredi;14h;2h;Mme MULLAERT;2;M103;A+1;B+2+3;A+1;B+2+3;A+1;B+2+3 +cours;TP Info;vendredi;14h;2h;M. HALFON;2;;B;A;B;A;B;A +cours;TP Info;vendredi;11h;2h;M. HALFON;2;;A;B;A;B;A;B +cours;TD Physique;jeudi;14h;1h;Mme CHEVALIER;1;R011;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15 +cours;TD Physique;jeudi;15h;1h;Mme CHEVALIER;1;R011;gr 1 à 8;gr 1 à 8;gr 1 à 8;gr 1 à 8;gr 1 à 8;gr 1 à 8 +cours;Info;jeudi;10h;3h;M. HALFON;1;;A+B;;;;; +cours ;Chimie;jeudi;10h;2h;Mme CHEVALIER;1;R101;SI;;;;; +cours;TIPE Physique;jeudi;12h;0h30;Mme CHEVALIER;1;R101;SI;;;;; +cours;TP ITC ;jeudi;13h30;1h30;M. HALFON;1;;SI;;;;; +cours;TP SI;lundi;8h;2h;M. DERUMAUX;1;;SI;;;;; +cours;TIPE Physique;lundi;11h30;0h30;Mme CHEVALIER;1;;SI;;;;; +cours;SI;lundi;12h;1h;M. DERUMAUX;1;;SI;;;;; +cours;SI;mardi;14h;1h;M. DERUMAUX;1;;SI;;;;; +cours ;Maths;lundi;14h;4h;Mme MULLAERT;1;M103;A+B+SI;;;;; +cours;Maths;mardi;8h;3h;Mme MULLAERT;1;M103;A+B+SI;;;;; +cours;Physique;mardi;15h;2h;Mme CHEVALIER;1;R013;A+B+SI;;;;; +cours ;Français-Philo;mercredi;10h;2h;Mme CHAPIRO;1;M103;A+B+SI;;;;; +cours;Physique;jeudi;8h;2h;Mme CHEVALIER;1;R101;A+B+SI;;;;; +cours;EPS;jeudi;16h;2h;M. TORRES-LACAZE;1;Gymnase;A+B+SI;;;;; +cours;Maths;vendredi;8h;3h;Mme MULLAERT;1;M103;A+B+SI;;;;; +;;;;;;;;;;;;; +cours;Anglais LV1;mardi;11h;2h;;1;;;;;;; +cours;Anglais LV2;mardi ;11h;1h30;;1;;;;;;; +cours;Espagnol LV1;mercredi;8h;2h;;1;;;;;;; +cours;Espagnol LV1;mercredi;8h30;1h30;;1;;;;;;; +cours;Allemand LV1 ;mercredi;8h;2h;;1;;;;;;; +cours;Allemand LV2;mercredi;8h30;1h30;;1;;;;;;; diff --git a/Resources/eleves-v2.csv b/Resources/eleves-v2.csv new file mode 100644 index 0000000..3b49c19 --- /dev/null +++ b/Resources/eleves-v2.csv @@ -0,0 +1,46 @@ +Nom;Prénon;Groupe de colle;TD +ABOUJAIB;Alexandre;4;A +AJAN;George;4;A +AKRAD;Lina;1;SI +AUBERT;Nicolas;1;SI +BADR;Roman;4;A +BAZIRE;Aurélien;5;A +BOIT;Arthur;5;A +BOUBKER;Youssef;5;A +BOUDJEMA;Dylan;1;SI +CHIRIAC;Mihnea;6;A +COURIER;Marine;6;A +DAGUIN;Joseph;6;A +DAUGUEN;Gabriel;7;A +DE WEER;Matthias;7;A +DESBOUIS;Katell;2;SI +DUPOUY;Jérémie;7;A +HARIRI--GAUTIER-PICARD;Grégoire;8;A +JURICEVIC;Matteo;8;A +KNANOUA;Anas;8;A +LESENNE;Pierrick;9;A +LIN;Hao;2;SI +MASBATIN;Lucas;2;SI +MAYURAN;Mithushan;9;A +MESSAHLI;Yassine;9;A +MOGUÉROU;Valentin;10;B +MOHELLEBI;Mathéo;10;B +MOUISSET--FERRARA;Maël;10;B +OTTAVI;Corentin;11;B +PONCE;Alexian;11;B +PUJOL;Raphaël;11;B +PUSTETTO;Mathis;12;B +RADICE;Roman;12;B +RAT;Evelyn;12;B +ROUSSE;Louis;3;SI +ROUX;Gaetan;3;SI +ROUYRE--CROS;Célian;3;SI +SOURBE;François-Gabriel;13;B +STOURBE;Simon;13;B +THAI;Dany;13;B +THÉODORE;Jonathan;14;B +VANDROUX;Benoit;14;B +VEYSSIERE;Thibaud;14;B +VIÉ;Adrien;15;B +YE;Luan;15;B +ZARKA;Amélie;15;B diff --git a/cogs/edt.py b/cogs/edt.py index 826782a..aa3fd58 100644 --- a/cogs/edt.py +++ b/cogs/edt.py @@ -5,14 +5,13 @@ from discord.ext import commands from classes.my_cog import MyCog -from create_calendar import get_calendar, get_eleves, display +from create_calendar import get_calendar, display from io import BytesIO class EDT(MyCog): def __init__(self, bot): super().__init__(bot) - self.eleves = get_eleves() self.bot = bot @app_commands.command(name="edt") diff --git a/create_calendar.py b/create_calendar.py index 58042cc..dc60579 100644 --- a/create_calendar.py +++ b/create_calendar.py @@ -6,10 +6,10 @@ from pathlib import Path -pd_eleves = pandas.read_csv('Resources/eleves.csv') +pd_eleves = pandas.read_csv('Resources/eleves-v2.csv', delimiter=";", header=None) np_eleves = pd_eleves.to_numpy() -pd_colles = pandas.read_csv('Resources/colles.csv') +pd_colles = pandas.read_csv('Resources/colloscope-v2.csv', delimiter=";", header=None) np_colles = pd_colles.to_numpy() local_tz = "Europe/Paris" @@ -22,6 +22,15 @@ jour_to_delta = { "vendredi": 4, } +jour_to_byday = { + "lundi": "MO", + "mardi": "TU", + "mercredi": "WE", + "jeudi": "TH", + "vendredi": "FR", +} + + langues = ["Anglais", "Allemand", "Espagnol"] option_langues = { @@ -61,14 +70,14 @@ def add_events_from_ics(filename: str, new_cal: icalendar.Calendar): return new_cal -def get_eleves(): +def get_td_groupe(groupe: str) -> str: """ - Renvoie la liste des eleves avec leur groupe associés à leur groupe, a utiliser dans la /cmd + Renvoie le groupe de TD d'un groupe de colle (A, B ou SI) """ - liste = {} for row in np_eleves[1:]: - liste[f"{row[0]} {row[1]} - {row[2]}"] = row[2] - return liste + if row[2] == groupe: + return row[3] + def debut_semaine_to_datetime(date_string: str) -> datetime.time: """ @@ -77,6 +86,50 @@ def debut_semaine_to_datetime(date_string: str) -> datetime.time: return datetime.datetime.strptime(date_string, "%d/%m/%y") +def heure_to_timedelta(heure: str) -> datetime.timedelta: + """ + Transforme une heure au format "8h30" ou "1h30" ou "2h" en timedelta. + """ + heure = heure.split("h") + delta = datetime.timedelta(hours=int(heure[0])) + + if heure[1] != '': + delta += datetime.timedelta(minutes=int(heure[1])) + + return delta + +def creer_evenement(titre: str, debut: datetime.datetime, duree: datetime.timedelta, description: str = None, localisation: str = None, rrule: str = None) -> icalendar.Event: + """ + Renvoie un évènement icalendar.Event() + + titre str: le titre de l'évènement + debut datetime.datetime: la date de début + duree datetime.timedelta: la durée + description str: la description (Optionelle) + localisation str: localisation (Optionelle) + rrule str: règle de récurrence https://icalendar.org/iCalendar-RFC-5545/3-8-5-3-recurrence-rule.html (Optionelle) + """ + new_event = icalendar.Event() + new_event.add("summary", titre) + new_event.add("dtstart", debut, parameters={"tzid": local_tz}) + debut += duree + new_event.add("dtend", debut, parameters={"tzid": local_tz}) + + if localisation is not None: + new_event.add("location", localisation) + if description is not None: + new_event.add("description", description) + if rrule is not None: + new_event.add("rrule", rrule) + + new_event.add("uid", str(uuid.uuid4())) + new_event.add("dtstamp", datetime.datetime.now()) + + # print(f"\nNouvel évènement: \n - {titre} \n - {debut - duree} \n- {duree} \n- {localisation} \n - {rrule}") + # nécessaire pour se conformer à la norme RFC 5545 + + return new_event + def get_colles_groupe(np_colles, groupe, option_langue): """ Renvoie les colles pour un groupe sous la forme d'une liste d'évènements ICS @@ -86,47 +139,53 @@ def get_colles_groupe(np_colles, groupe, option_langue): option_langue: str, les options de langue """ liste_colles = [] - for row in np_colles[1:]: + for row in np_colles[4:39]: - if pandas.isnull(row[0]) or row[0] == "pas de colle": + if pandas.isnull(row[1]) or row[1] == "pas de colle": # il n'y a pas de colle, on skip ! continue # Si la colle n'est pas la LV1 de l'élève, on skip - if row[0] == "Anglais" and not option_langue.startswith("EN"): + if row[1] == "Anglais" and not option_langue.startswith("EN"): continue - elif row[0] == "Allemand" and not option_langue.startswith("DE"): + elif row[1] == "Allemand" and not option_langue.startswith("DE"): continue - elif row[0] == "Espagnol" and not option_langue.startswith("ES"): + elif row[1] == "Espagnol" and not option_langue.startswith("ES"): continue - for index, colle in enumerate(row[5:]): - # les quatre premières cases ne sont pas - if pandas.isnull(colle) or colle != groupe: + for index, colle in enumerate(row[8:]): + if pandas.isnull(colle): continue + # les huit premières cases ne sont pas concernées + elif colle != groupe and ("," in list(colle) and groupe not in colle.split(",")): + continue + # dans le cas où plusieurs groupes de colles soient concernés - new_colle = icalendar.Event() - new_colle.add("summary", f"Colle {row[0]}") - new_colle.add("description", f"{row[3]}") - new_colle.add("location", row[4]) + duree = heure_to_timedelta(row[4]) + # transforme la durée en timedelta + + date = debut_semaine_to_datetime(np_colles[1][index+8]) + # TODO + date += datetime.timedelta(days=jour_to_delta[row[2]]) + date += heure_to_timedelta(row[3]) + # génère la date à partir de la semaine, du jour et de l'heure - new_colle.add("dtstamp", datetime.datetime.now()) + localisation = row[7] if not pandas.isnull(row[7]) else None - new_colle.add("uid", str(uuid.uuid4())) - date = debut_semaine_to_datetime(np_colles[0][index+5]) - date += datetime.timedelta(days=jour_to_delta[row[1]]) - date += datetime.timedelta(hours=int(row[2][:-1])) - new_colle.add("dtstart", date, parameters={"tzid": local_tz}) - - date += datetime.timedelta(hours=1) - new_colle.add("dtend", date, parameters={"tzid": local_tz}) + new_colle = creer_evenement( + titre=f"Colle {row[1]}", + description=f"{row[5]}", + localisation=localisation, + debut=date, + duree=duree + ) liste_colles.append(new_colle) return liste_colles -def get_cours_SI(np_colles, groupe): +def get_cours(np_colles, groupe): """ Renvoie les colles pour un groupe sous la forme d'une liste d'évènements ICS, cad icalendar.Event @@ -134,74 +193,131 @@ def get_cours_SI(np_colles, groupe): np_colles: l'array 2D numpy contenant le colloscope groupe: str, le numéro du groupe """ - liste_cours = [] - for index, cell in enumerate(np_colles[-1][5:]): - heure = 17 - groupes = cell.split("§") - if groupe in groupes or f"\n{groupe}" in groupes: - heure = 16 + listes_cours = [] + groupe_td = get_td_groupe(groupe) - cours_si = icalendar.Event() - cours_si.add("summary", "TD SI") - cours_si.add("description", "M. Derumeaux R415") - cours_si.add("dtstamp", datetime.datetime.now()) - cours_si.add("uid", str(uuid.uuid4())) + for row in np_colles[41:66]: - date = debut_semaine_to_datetime(np_colles[0][index+5]) - date += datetime.timedelta(days=jour_to_delta["mardi"]) - date += datetime.timedelta(hours=heure) - cours_si.add("dtstart", date, parameters={"tzid": local_tz}) + if pandas.isnull(row[1]): + continue + + first_date = np_colles[1][8] - date += datetime.timedelta(hours=1) - cours_si.add("dtend", date, parameters={"tzid": local_tz}) - liste_cours.append(cours_si) + eleves = row[8] + + + if "à" in list(eleves): - return liste_cours + eleves = eleves.split(" ") + debut, fin = [grp for grp in eleves if grp.isdigit()] + + if not int(debut) <= int(groupe) <= int(fin): + continue + + elif "+" in list(eleves): + eleves = eleves.split("+") + + if groupe not in [grp for grp in eleves if grp.isdigit()]: + + if groupe_td not in [grp for grp in eleves]: + if int(row[6]) > 1: + if groupe in [grp for grp in row[9].split("+") if grp.isdigit()]: + first_date = np_colles[1][9] + elif groupe_td in [grp for grp in row[9].split("+")]: + first_date = np_colles[1][9] + else: + + continue + + else: + continue + + # si la 1ère occurence du cours est la 1ère ou la 2e semaine + + + elif groupe != eleves and groupe_td != eleves: + if pandas.isnull(row[9]) or (groupe != row[9] and groupe_td != row[9]): + continue + else: + first_date = np_colles[1][9] + + # vérification que le groupe est concerné par le cours + + first_date = debut_semaine_to_datetime(first_date) + + first_date += heure_to_timedelta(row[3]) + first_date += datetime.timedelta(days=jour_to_delta[row[2]]) + + duree = heure_to_timedelta(row[4]) + + localisation = row[7] if not pandas.isnull(row[7]) else None + + last_date = debut_semaine_to_datetime(np_colles[1][-1]) + datetime.timedelta(days=5) + + rrule = {"FREQ": "WEEKLY", "UNTIL": last_date, "INTERVAL": row[6], "BYDAY": jour_to_byday[row[2]], "WKST": "MO"} + + new_cours = creer_evenement( + titre=row[1], + description=row[5], + localisation=localisation, + debut=first_date, + duree=duree, + rrule=rrule + ) + + listes_cours.append(new_cours) + + return listes_cours def get_langues(langues): """ - Renvoie la liste de cours de langue associés - list[icalendar.Event] + Renvoie la liste de cours de langue associés sous forme de list[icalendar.Event] """ - liste_langues = [] - p = Path(__file__).with_name('Resources') - p = Path(p, f"EDT_Langues.ics") - with p.open('r') as f: - opened_cal = icalendar.Calendar.from_ical(f.read()) - - for event in opened_cal.walk("vevent"): - if event.get("summary") in option_langues[langues]: - liste_langues.append(event) + liste_cours = [] + langues = option_langues[langues] - return liste_langues - + for row in np_colles[67:]: -def get_calendar(groupe, langues, split: bool = False): + if row[1] in langues: + + debut = debut_semaine_to_datetime(np_colles[1][9]) + debut += heure_to_timedelta(row[3]) + debut += datetime.timedelta(days=jour_to_delta[row[2]]) + + duree = heure_to_timedelta(row[4]) + + last_date = debut_semaine_to_datetime(np_colles[1][-1]) + datetime.timedelta(days=5) + + rrule = {"FREQ": "WEEKLY", "UNTIL": last_date, "INTERVAL": row[6], "BYDAY": jour_to_byday[row[2]], "WKST": "MO"} + + new_cours = creer_evenement( + titre=row[1], + debut=debut, + duree=duree, + rrule=rrule + ) + + liste_cours.append(new_cours) + + return liste_cours + + +def get_calendar(groupe: str, langues: str, split: bool = False): """" Renvoie un calendrier (icalendar.Calendar) pour un groupe avec des langues donné """ - moitie = None - for row in np_eleves[1:]: - if row[2] == int(groupe): - moitie = row[3] - break new_cal_edt = open_ics("Base_Calendar.ics") if split: new_cal_colles = open_ics("Base_Calendar.ics") - - - new_cal_edt = add_events_from_ics(filename="EDT_Base.ics", new_cal=new_cal_edt) - new_cal_edt = add_events_from_ics(filename=f"EDT_{moitie}.ics", new_cal=new_cal_edt) - for event in get_langues(langues): new_cal_edt.add_component(event) - for event in get_cours_SI(np_colles, groupe): + for event in get_cours(np_colles, groupe): new_cal_edt.add_component(event) if split: @@ -214,5 +330,4 @@ def get_calendar(groupe, langues, split: bool = False): new_cal_edt.add_component(event) - return [new_cal_edt.to_ical()] \ No newline at end of file -- 2.45.2 From 825f45d7afec93db8f5da23a448b80959b90a973 Mon Sep 17 00:00:00 2001 From: joseph Date: Mon, 12 Feb 2024 15:04:25 +0100 Subject: [PATCH 05/11] cleanup files --- Resources/Colloscope.ods | Bin 39760 -> 0 bytes Resources/EDT_A.ics | 227 ------------------------------ Resources/EDT_B.ics | 220 ----------------------------- Resources/EDT_Base.ics | 269 ------------------------------------ Resources/EDT_Langues.ics | 122 ---------------- Resources/colles.csv | 74 ---------- Resources/colloscope-v2.ods | Bin 0 -> 32398 bytes Resources/eleves.csv | 46 ------ 8 files changed, 958 deletions(-) delete mode 100644 Resources/Colloscope.ods delete mode 100644 Resources/EDT_A.ics delete mode 100644 Resources/EDT_B.ics delete mode 100644 Resources/EDT_Base.ics delete mode 100644 Resources/EDT_Langues.ics delete mode 100644 Resources/colles.csv create mode 100644 Resources/colloscope-v2.ods delete mode 100644 Resources/eleves.csv diff --git a/Resources/Colloscope.ods b/Resources/Colloscope.ods deleted file mode 100644 index 3c62e222bd74150a1182073a249c81bd4c5e66bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39760 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 bw1R)CT!7Az!akl-)`*TI6j4lcnN+!+{n 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 E9|Z{;vH$=8 literal 0 HcmV?d00001 diff --git a/Resources/eleves.csv b/Resources/eleves.csv deleted file mode 100644 index 261d139..0000000 --- a/Resources/eleves.csv +++ /dev/null @@ -1,46 +0,0 @@ -Nom,Prénon,Groupe de coll,TD -ABOUJAIB,Alexandre,1,A -AJAN,George,1,A -AKRAD,Lina,5,A -AUBERT,Nicolas,3,A -BADR,Roman,3,A -BAZIRE,Aurélien,3,A -BOIT,Arthur,5,A -BOUBKER,Youssef,5,A -BOUDJEMA,Dylan,1,A -CHIRIAC,Mihnea,7,A -COURIER,Marine,7,A -DAGUIN,Joseph,7,A -DAUGUEN,Gabriel,9,A -DE WEER,Matthias,9,A -DESBOUIS,Katell,11,A -DUPOUY,Jérémie,11,A -HARIRI--GAUTIER-PICARD,Grégoire,11,A -JURICEVIC,Matteo,13,A -KNANOUA,Anas,13,A -LESENNE,Pierrick,13,A -LIN,Hao,9,A -MASBATIN,Lucas,15,A -MAYURAN,Mithushan,15,A -MESSAHLI,Yassine,2,B -MOGUÉROU,Valentin,2,B -MOHELLEBI,Mathéo,2,B -MOUISSET--FERRARA,Maël,4,B -OTTAVI,Corentin,4,B -PONCE,Alexian,4,B -PUJOL,Raphaël,6,B -PUSTETTO,Mathis,6,B -RADICE,Roman,6,B -RAT,Evelyn,8,B -ROUSSE,Louis,8,B -ROUX,Gaetan,8,B -ROUYRE--CROS,Célian,10,B -SOURBE,François-G,10,B -STOURBE,Simon,10,B -THAI,Dany,12,B -THÉODORE,Jonathan,12,B -VANDROUX,Benoit,12,B -VEYSSIERE,Thibaud,14,B -VIÉ,Adrien,14,B -YE,Luan,14,B -ZARKA,Amélie,15,A -- 2.45.2 From cf78271e3130171ac16a3fbd11b701166168413b Mon Sep 17 00:00:00 2001 From: joseph Date: Mon, 12 Feb 2024 15:22:15 +0100 Subject: [PATCH 06/11] fix smol bugs --- create_calendar.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/create_calendar.py b/create_calendar.py index dc60579..bc515d7 100644 --- a/create_calendar.py +++ b/create_calendar.py @@ -125,7 +125,6 @@ def creer_evenement(titre: str, debut: datetime.datetime, duree: datetime.timede new_event.add("uid", str(uuid.uuid4())) new_event.add("dtstamp", datetime.datetime.now()) - # print(f"\nNouvel évènement: \n - {titre} \n - {debut - duree} \n- {duree} \n- {localisation} \n - {rrule}") # nécessaire pour se conformer à la norme RFC 5545 return new_event @@ -139,8 +138,7 @@ def get_colles_groupe(np_colles, groupe, option_langue): option_langue: str, les options de langue """ liste_colles = [] - for row in np_colles[4:39]: - + for row in np_colles[4:40]: if pandas.isnull(row[1]) or row[1] == "pas de colle": # il n'y a pas de colle, on skip ! continue @@ -158,7 +156,11 @@ def get_colles_groupe(np_colles, groupe, option_langue): if pandas.isnull(colle): continue # les huit premières cases ne sont pas concernées - elif colle != groupe and ("," in list(colle) and groupe not in colle.split(",")): + + if "," in list(colle): + if groupe not in colle.split(","): + continue + elif colle != groupe: continue # dans le cas où plusieurs groupes de colles soient concernés @@ -166,7 +168,7 @@ def get_colles_groupe(np_colles, groupe, option_langue): # transforme la durée en timedelta date = debut_semaine_to_datetime(np_colles[1][index+8]) - # TODO + date += datetime.timedelta(days=jour_to_delta[row[2]]) date += heure_to_timedelta(row[3]) # génère la date à partir de la semaine, du jour et de l'heure @@ -175,7 +177,7 @@ def get_colles_groupe(np_colles, groupe, option_langue): new_colle = creer_evenement( titre=f"Colle {row[1]}", - description=f"{row[5]}", + description=f"{row[5]}" if not pandas.isnull(row[5]) else None, localisation=localisation, debut=date, duree=duree -- 2.45.2 From db5f6e318a98da149cafd1e82460283a1f7d1b75 Mon Sep 17 00:00:00 2001 From: joseph Date: Mon, 12 Feb 2024 15:32:16 +0100 Subject: [PATCH 07/11] re-fix --- Resources/colloscope-v2.csv | 4 ++-- Resources/colloscope-v2.ods | Bin 32398 -> 32389 bytes create_calendar.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Resources/colloscope-v2.csv b/Resources/colloscope-v2.csv index 47f761e..b2d07bd 100644 --- a/Resources/colloscope-v2.csv +++ b/Resources/colloscope-v2.csv @@ -41,8 +41,8 @@ colle;TP Info;mercredi;16h;2h;;;;6,11,9;7,14,10;4,5,8;12,13,15;; ;;;;;;;;;;;;; cours;TP Physique;lundi;8h30;1h30;Mme CHEVALIER;1;R417;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15 cours;TP Physique;lundi;10h;1h30;Mme CHEVALIER;1;R417;gr 1 à 8;gr 1 à 8;gr 1 à 8;gr 1 à 8;gr 1 à 8;gr 1 à 8 -cours;TP Info;lundi;10h;1h30;M. HALFON;2;C154;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15 -cours;TP Info;lundi;8h30;1h30;M. HALFON;2;C154;gr 4 à 8;gr 4 à 8;gr 4 à 8;gr 4 à 8;gr 4 à 8;gr 4 à 8 +cours;TP Info;lundi;10h;1h30;M. HALFON;1;C154;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15;gr 9 à 15 +cours;TP Info;lundi;8h30;1h30;M. HALFON;1;C154;gr 4 à 8;gr 4 à 8;gr 4 à 8;gr 4 à 8;gr 4 à 8;gr 4 à 8 cours;TD Maths;vendredi;11h;2h;Mme MULLAERT;2;M103;B+2+3;A+1;B+2+3;A+1;B+2+3;A+1 cours;TD Maths;vendredi;14h;2h;Mme MULLAERT;2;M103;A+1;B+2+3;A+1;B+2+3;A+1;B+2+3 cours;TP Info;vendredi;14h;2h;M. HALFON;2;;B;A;B;A;B;A diff --git a/Resources/colloscope-v2.ods b/Resources/colloscope-v2.ods index 13445f67692f78e8a6bbe9ca583996bbc6be3011..27a563bc900eb6e2a634b3ab19c4a25a9137dead 100644 GIT binary patch delta 2047 zcmZ8idpy(o8{d$_)LbH$BXYl`nlyw^ESFp&he*opg~M2yY8PM3Wk)0%#?K{k9l7PS zw2C1@r>Hh!y12GBEwy6~!ZGLkey?7?&+GMhp7;CxJfG+D{P(`G4o+VO@APsLmrw+O zq(Gq9OL;rJ#kS%FYf&tNiz3T>8*7tI!HU~lo7{kfkmJBoTa3&DYm*nTP{%CyNx zaXWudwwf$Oy?SDzQSE_ZSD>QIl(Pkk@@@s3n5dkmxDQ}onzod~zi)B=N-qHK)>o}h zGfFV9VD#%xg}c2G`+b0PlJsDf=Lf%8tW_izI=nD?^xzZPWjYI4#xI=ZwYdFs>$%np zkyMiX&4^+}cyb%AO)klP8CMDn;!HPD?oUI*x=HS)!zqrX35IDgJ;PyFdffKth3Z;g z&CWOcKm;gK@%s)+H#!D6)84w;(GKkB8NE`dk~i)iVVo8?6rp^*udc7pU`YRLjsN}# zLLIv{|J7K=F=0S^1?m{ZBy4P~rHRlOs>IGV^NJB{%GN#@$iJWX2HJ&ttom&Aqq;Qb zFPas5QkecWta_-%D)qWwW4Lf>?LqEumTDL4&7^=;=JOcMtO65FZEdr;Nwm;(AT#;P zl)o;)#-3KhC%gz&YChnZ5$9lD%=fhgmR7iew!c0?$jrW7U~-u)1=83+Y1_UER!M$$V|a!1R{#nLgg0F1C7063&3_0;&}X z>{pV+Y2Mw@dY1NEM9!XYj#H;kGWz=I?32mqe7a#UME-=6E9AXPx3b*TV2T5C;DCe;~2cPO5@$j}6pq-R;av>Ehj&kd+4x{LQn&}h55F&L$AXr+Hr zi6KN1k@``NbAib`AE|U*Dj;ztPH@8j#~<~3K@4f`9U-E!ZeGy1R~_3Lr|CjRPbVPr zFMRDhWcTM1Rk9=7U0TXt{28oixqCOc!oj0Wxs#ONl{HZLa1kq$>obLp3#+o4uH-(I z=nP(|Z*I@69#?J3EFs*C#I^HmY=zXYf3cKoiQq+02* zKv?$-UtOLx@Ma9C*@s}DFFCh&q&%qLzCJQ+-u1Rz8_J@BQVl&UPMg z%)|74M+^14&}mM#VQty4t2FRNMpGf;;d&wx$niP1t0Y2Wrv~bN%RAK^*TeZ}G;{F;8vVx0@|_nYsnMU59Ll}&|Js^zfR z$41p84!c&0!E7eB;6G8ntnPip)3LDlbjh85PN35Poo}^UDwPKt z%BS2O%d{8^-ivlt@+nXI^8G%Up|%%TuAJ$=7pWkOeNA_4k-QI=Ipc!o=pOD6|K#OW zmKNXl#j*$RXA??>x@O|JFm6WJ7GSbq+&v^qPdR#F3109r3cipq`OVJD?I)?jRa$9C zNf2nn8U*^$`%d{AR~ba5o&bSFR|NzDory%ph9EDt2mV}kLgZAd=M%OaEAB$8s>rdl zFd{=E`(fNf34&86Gcd*?xPWo|ui}CIS5YSyVhu$q1MB=x5%CXGCnItDMX(gN{c0K~ z@?EkTe%mz9;LUf%UOMIfzpcpycvDT0^8edzE&T5>B~RfEw*N>{2hWiWl5|DHeTxK; MqmwiwAsA8P-%HuLVgLXD delta 2053 zcmYk7c|6qlAIHDnAxF+(Sd1%2B_h%|3NhmtgB+0@V+s|aaSR!A$dO6p7~AGZwX7j_ zh-3y$6iTs?6>=p}jg=5#WVW&U`#tva$NTkuzh3Y65=q=RhrbF{t=&Jh&bIFwF&-E<|wF z;15ZV7U-X{R-i!TPiBN(oq6mTM8x%8msAp#?JR9%UWHMrdI` zXqN5tCT8~hdM(CMU0dRMM0ldK&bt!it`K?3?iP7${a$75k@nzn6zE88MI{R*qJ4F_ zcJ=c<8}|r$vJW^79kd>%iPx?%PehBafwh4(<#t5AcV_2l#Kq=FXFYP%$KcvS5-J~J z*>>^d?_-uMOP_nadxbg?d_Jxyr*P@D^yt(tMrOe$`6b$*+9cv^@hGRRI_o&w)DgcJ z(b&VG*nBgFI%-RLi%{E>n+xZW_hM#{C{#sBOAkjlQ64XP&EDkMw`Yn2S0=&i0*0I5d+Y}+ga?saHvRzCCJ=uBquviDjW7NGt1^6!9cTRrS9mk zhDwV0SAv=>>%;8SmzWy^%Zqqo#}|??BPgJ}e2bA!ocdU^FLb3~(90($d(fuq3HNz_ zV^?vQl}4V5ryqaie(5Y%ubNS_wN-OY@1&T)nD2N4ckRQq$Lhs}8*7 z2RaSg)qW%#J&K#O&X1ex_%OD&{T<;H zYJiECuu$ z;903!L+H>66Ld(yZ3f=R^9I>3Us-;UvYsE2i=; z>r$5R=EO2hw^h@9kJiV)o%P?Gsd4hPUGGC~DKq!WXZVL_qaQy?ZPumGn zB#MTIBrIvAr8mYmj&3k25ZSBaXcJ;vdQE$!_QUScap5b`21!$3#w`g2RB{$#=EBw2 zlP703ns4bp(1`J~_v)EzM}3dvZ)A>`l?DWweI^pid>7yks^IBl*9Gqts?SaGqp0fa zJG-c7%Q$zrZqTq^htD1-e)0A^d5L$7J%wyJ*MpDDExy)BEDKd(`4cji3O|k1?`Ihi ztr|?4Xb*_3PuX{4&6USyL> z{G$4+sx~*!Gfj7S3ws}xQ2no6{{6Z`QfhouwpV~u@fr28$*GB>4~9u79YrRH06_m?0QfHn8!X@tkOE{aVq>?_bp}_bEI^kM zQ9w4j8xbQAkfcg)BJLBk(MhUwK5_5=T>GSdU6jB<|JWNyGWaKS_{VV)h~TQ0w0$)~ z5&)MDC2tcHLpGI4#=H3b|AX`_@_s?yLRJM4^kMQI!2nWJA)m2yFz6?JcMJ%D0Wd&J jOza2AU3~Lz>thp?0pR@r1dss!`-17GDC#2eM1l7=^-{Mx diff --git a/create_calendar.py b/create_calendar.py index bc515d7..e43264e 100644 --- a/create_calendar.py +++ b/create_calendar.py @@ -283,7 +283,7 @@ def get_langues(langues): if row[1] in langues: - debut = debut_semaine_to_datetime(np_colles[1][9]) + debut = debut_semaine_to_datetime(np_colles[1][8]) debut += heure_to_timedelta(row[3]) debut += datetime.timedelta(days=jour_to_delta[row[2]]) -- 2.45.2 From 78675c72c2a11599b557eef01c354821f2ebcfd9 Mon Sep 17 00:00:00 2001 From: joseph Date: Sat, 30 Mar 2024 15:14:22 +0100 Subject: [PATCH 08/11] =?UTF-8?q?ajout=20d'un=20d=C3=A9tecteur=20de=20coll?= =?UTF-8?q?isions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- check_collisions.py | 106 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 check_collisions.py diff --git a/check_collisions.py b/check_collisions.py new file mode 100644 index 0000000..ae8245c --- /dev/null +++ b/check_collisions.py @@ -0,0 +1,106 @@ +""" + Objectif: déterminer les collisions dans un fichier .ics généré, afin de pouvoir + 'valider' un colloscope. Pour cela, ce programme génère les colloscopes associés + à chaque groupe de colle puis regarde s'il y a collision entre les évènements + en faisant partie. +""" + +from typing import List + +from attr import dataclass +import icalendar +import datetime +from dateutil import rrule # https://dateutil.readthedocs.io/en/stable/rrule.html +import recurring_ical_events +from io import BytesIO + +import create_calendar + +@dataclass +class DatesEvent: + nom: str + start: datetime.date + end: datetime.date + + +def recurring_events_to_events(cal: icalendar.Calendar) -> DatesEvent: + at_date = 2024 + events = recurring_ical_events.of(cal).at(at_date) + return events + +def ical_to_dates(events: List[icalendar.Event]) -> DatesEvent: + """ + Renvoie la liste de dates et de durées de l'ensemble des évènements (SANS EVENEMENTS RECURSIFS, ecurring_events_to_events s'en étant déjà occupé !) + """ + output = [] + + for event in events: + if not event.get("RRULE"): + new_event = DatesEvent( + nom=str(event.get("SUMMARY")) + " - " + str(event.get("DESCRIPTION")), + start=event.get("DTSTART").dt, + end=event.get("DTEND").dt + ) + + output.append(new_event) + + return output + + +def check_dates_collision(start1: datetime.date, start2: datetime.date, end1: datetime.timedelta, end2: datetime.timedelta): + if start1 <= start2: + if start2 < end1: + return True + elif start1 <= start2: + # cas où dt1 commence après dt2 mais avant dt2+td2 + if end2 > end2: + return True + return False + +def check_collisions(dates: DatesEvent): + """ + Fonction qui réalise réellement le check. + Itère brutalement sur toutes les dates, par souci d'efficacité d'écriture de code, + et surtout parce que ça marche ! + """ + for date_event1 in dates: + for date_event2 in dates: + if date_event1.nom != date_event2.nom: + if check_dates_collision(date_event1.start, date_event2.start, date_event1.end, date_event2.end): + print( + f""" + ---- + Colision entre {date_event1.nom} et {date_event2.nom} + {date_event1.nom}: {date_event1.start.strftime('%d-%m-%Y: %H:%M')} à {date_event1.end.strftime('%d-%m-%Y: %H:%M')} + {date_event2.nom}: {date_event2.start.strftime('%d-%m-%Y: %H:%M')} à {date_event2.end.strftime('%d-%m-%Y: %H:%M')}""") + + +def generate_calendars(): + for groupe in range(1, 16): + + print( + f""" + ┌────────────────────────── + │ + │ GROUPE {groupe} + """ + ) + + generated_ical = create_calendar.get_calendar(str(groupe), "EN")[0] + + generated_ical = icalendar.Calendar.from_ical(generated_ical) + + + events = list(generated_ical.walk("VEVENT")) + events += recurring_events_to_events(generated_ical) + + check_collisions(ical_to_dates(events)) + + print( + f""" + │ + └────────────────────────── + """ + ) + +generate_calendars() \ No newline at end of file -- 2.45.2 From 7675b24af2a05a26beb5c8d5d00b0c58d7e83ecb Mon Sep 17 00:00:00 2001 From: voXrey <72698969+voXrey@users.noreply.github.com> Date: Sat, 1 Jun 2024 19:54:50 +0200 Subject: [PATCH 09/11] Multiple guilds support --- main.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index 35b4e7c..dbb075f 100644 --- a/main.py +++ b/main.py @@ -19,7 +19,7 @@ class MyClient(commands.Bot): intents.message_content = True super().__init__(intents=intents, command_prefix=".") - self.MY_GUILD = discord.Object(id=getenv("GUILD_ID")) + self.MY_GUILDS = [discord.Object(id=int(guild_id)) for guild_id in getenv("GUILD_ID").split(',')] self.initial_extensions = ["cogs." + f[:-3] for f in listdir("./cogs") if f.endswith(".py") and f.__str__() != "__init__.py"] @@ -30,8 +30,9 @@ class MyClient(commands.Bot): for extension in self.initial_extensions: await self.load_extension(extension) - self.tree.copy_global_to(guild=self.MY_GUILD) - await self.tree.sync(guild=self.MY_GUILD) + for guild in self.MY_GUILDS: + self.tree.copy_global_to(guild=guild) + await self.tree.sync(guild=guild) async def on_ready(self): print(f'Logged in as {self.user} (ID: {self.user.id})') -- 2.45.2 From dfe9d3da74af2e4893c87d7fbb8f58b7b7b6e973 Mon Sep 17 00:00:00 2001 From: voXrey <72698969+voXrey@users.noreply.github.com> Date: Sat, 1 Jun 2024 20:03:20 +0200 Subject: [PATCH 10/11] Owner verification for Admin cog --- cogs/admin.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cogs/admin.py b/cogs/admin.py index 36a2ba2..7cb8c19 100644 --- a/cogs/admin.py +++ b/cogs/admin.py @@ -111,6 +111,10 @@ class Admin(MyCog): # Add cogs commands group to cog self.bot.tree.add_command(CogGroup(self.bot)) + async def cog_check(self, ctx): + admins = self.bot.owner_ids + return ctx.author.id in admins + async def setup(bot): await bot.add_cog(Admin(bot)) -- 2.45.2 From b82d1bbf86425b4ac734d70857f4cfca2c707811 Mon Sep 17 00:00:00 2001 From: voXrey <72698969+voXrey@users.noreply.github.com> Date: Sun, 2 Jun 2024 14:17:48 +0200 Subject: [PATCH 11/11] Fix admin check --- cogs/admin.py | 11 ++++++----- main.py | 8 ++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/cogs/admin.py b/cogs/admin.py index 7cb8c19..b36f7dc 100644 --- a/cogs/admin.py +++ b/cogs/admin.py @@ -1,7 +1,8 @@ import discord -from discord import app_commands +from discord import app_commands, Interaction from discord.app_commands import Choice from discord.ext import commands +from typing import cast from classes.my_cog import MyCog @@ -11,6 +12,10 @@ class CogGroup(app_commands.Group, name="cog", description="Gérer les cogs"): super().__init__() self.bot = bot + async def interaction_check(self, interaction: Interaction, /) -> bool: + team = cast(discord.Team, self.bot.application.team) + return any(interaction.user.id == team_member.id for team_member in team.members) + @app_commands.command(name="load") async def cog_load(self, interaction: discord.Interaction, extension: str): """ @@ -111,10 +116,6 @@ class Admin(MyCog): # Add cogs commands group to cog self.bot.tree.add_command(CogGroup(self.bot)) - async def cog_check(self, ctx): - admins = self.bot.owner_ids - return ctx.author.id in admins - async def setup(bot): await bot.add_cog(Admin(bot)) diff --git a/main.py b/main.py index dbb075f..8177789 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,8 @@ -from typing import Optional, List from os import getenv, listdir import re import discord +from typing import cast from discord import app_commands from discord.app_commands import Choice from discord.ext import commands @@ -23,7 +23,7 @@ class MyClient(commands.Bot): self.initial_extensions = ["cogs." + f[:-3] for f in listdir("./cogs") if f.endswith(".py") and f.__str__() != "__init__.py"] - #self.add_listener(self.on_message) + # self.add_listener(self.on_message) async def setup_hook(self): # cogs @@ -35,8 +35,11 @@ class MyClient(commands.Bot): await self.tree.sync(guild=guild) async def on_ready(self): + team = cast(discord.Team, self.application.team) + print(f'Logged in as {self.user} (ID: {self.user.id})') print(f"Discord version : {discord.__version__}") + print(f"Admins : {', '.join([m.name for m in team.members])}") print('------') async def on_message(self, msg): @@ -45,6 +48,7 @@ class MyClient(commands.Bot): if p.search(msg.content) is not None: await msg.reply("Quoicoubeh !") + if __name__ == "__main__": client = MyClient() client.run(getenv("TOKEN")) -- 2.45.2