Lenylvt commited on
Commit
a01c266
1 Parent(s): dab24b9

Upload 10 files

Browse files
Files changed (10) hide show
  1. app.py +110 -0
  2. pages/accueil.py +59 -0
  3. pages/contenu.py +27 -0
  4. pages/conv.py +50 -0
  5. pages/devoirs.py +50 -0
  6. pages/edt.py +72 -0
  7. pages/info.py +66 -0
  8. pages/notes.py +80 -0
  9. pages/vie_scolaire.py +143 -0
  10. requirements.txt +2 -0
app.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pronotepy
3
+ from pronotepy import ENTLoginError
4
+ from pronotepy.ent import *
5
+
6
+ # Importez vos pages ici
7
+ from pages import accueil, devoirs, notes, edt, contenu, info, vie_scolaire, conv
8
+
9
+ def main():
10
+ # Configuration initiale de la page
11
+ st.set_page_config(page_title="Application Pronote", initial_sidebar_state="collapsed", layout="centered")
12
+
13
+ # Initialiser 'current_page' dans st.session_state
14
+ if 'current_page' not in st.session_state:
15
+ st.session_state.current_page = 'accueil'
16
+
17
+ # Définition des options du menu déroulant
18
+ colleges = {
19
+ 'Autre': ('', ''),
20
+ 'Louise Weiss': ('https://0952236p.index-education.net/pronote/eleve.html', 'val_doise'),
21
+ }
22
+
23
+ cas_options = [
24
+ 'Aucune', 'ac_orleans_tours', 'ac_poitiers', 'ac_reunion', 'ac_reims',
25
+ 'ac_rennes', 'atrium_sud', 'cas_agora06', 'cas_arsene76_edu', 'cas_cybercolleges42_edu',
26
+ 'cas_kosmos', 'cas_seinesaintdenis_edu', 'eclat_bfc', 'ecollege_haute_garonne_edu',
27
+ 'ent_94', 'ent_auvergnerhonealpe', 'ent_creuse', 'ent_creuse_educonnect', 'ent_elyco',
28
+ 'ent_essonne', 'ent_hdf', 'ent_mayotte', 'ent_somme', 'ent_var', 'ent77',
29
+ 'ent_ecollege78', 'extranet_colleges_somme', 'ile_de_france', 'laclasse_educonnect',
30
+ 'laclasse_lyon', 'l_normandie', 'lyceeconnecte_aquitaine', 'lyceeconnecte_edu',
31
+ 'monbureaunumerique', 'neoconnect_guadeloupe', 'occitanie_montpellier',
32
+ 'occitanie_montpellier_educonnect', 'occitanie_toulouse_edu', 'paris_classe_numerique',
33
+ 'val_de_marne', 'val_doise'
34
+ ]
35
+
36
+ if 'client' not in st.session_state or not st.session_state.client.logged_in:
37
+ # Page de connexion
38
+ st.title("Connexion à Pronote")
39
+ college_choice = st.selectbox("🎒 Sélectionnez votre collège", list(colleges.keys()))
40
+ url, cas_key = colleges[college_choice]
41
+
42
+ if college_choice == 'Autre':
43
+ url = st.text_input("🧷 URL de Pronote")
44
+ cas = st.selectbox("📍 CAS", cas_options)
45
+ else:
46
+ cas = cas_key
47
+
48
+ username = st.text_input("1️⃣ Identifiant")
49
+ password = st.text_input("2️⃣ Mot de Passe", type="password")
50
+
51
+ if st.button('Connexion'):
52
+ try:
53
+ #client = pronotepy.Client(url, username, password, getattr(pronotepy.ent, cas, None))
54
+ client = pronotepy.Client("https://0952236p.index-education.net/pronote/eleve.html", "leny.levant", "Leny15@0", val_doise)
55
+ if client.logged_in:
56
+ st.session_state.client = client
57
+ st.experimental_rerun()
58
+ else:
59
+ st.error("Connexion impossible. Veuillez vérifier vos informations.")
60
+ except ENTLoginError:
61
+ st.error("Connexion impossible. Vérifiez vos informations de connexion.")
62
+ else:
63
+ client = st.session_state.client
64
+ st.sidebar.title("Navigation")
65
+
66
+ # Navigation
67
+ page_buttons = {
68
+ "🏠 Accueil": "accueil",
69
+ "📅 Emploi du temps": "edt",
70
+ "📚 Devoirs": "devoirs",
71
+ "📝 Notes": "notes",
72
+ "📧 Messagerie": "conv",
73
+ "i️ Informations": "info",
74
+ "🕒 Vie Scolaire": "vie_scolaire"
75
+ }
76
+
77
+ for button_label, page_name in page_buttons.items():
78
+ if st.sidebar.button(button_label, key=page_name, use_container_width=True):
79
+ st.session_state.current_page = page_name
80
+ st.rerun() # Force le rechargement de l'application avec le nouvel état
81
+
82
+ if 'current_page' not in st.session_state:
83
+ st.session_state.current_page = 'accueil' # Défaut à accueil si non défini
84
+
85
+ # Affichage conditionnel basé sur la page actuelle
86
+ if st.session_state.current_page == 'accueil':
87
+ accueil.app(client)
88
+ elif st.session_state.current_page == 'devoirs':
89
+ devoirs.app(client)
90
+ elif st.session_state.current_page == 'notes':
91
+ notes.app(client)
92
+ elif st.session_state.current_page == 'edt':
93
+ edt.app(client)
94
+ elif st.session_state.current_page == 'contenu':
95
+ contenu.show_lesson_content()
96
+ elif st.session_state.current_page == 'info':
97
+ info.app(client)
98
+ elif st.session_state.current_page == 'vie_scolaire':
99
+ vie_scolaire.app(client)
100
+ elif st.session_state.current_page == 'conv':
101
+ conv.app(client)
102
+
103
+ if st.sidebar.button('🚪 Déconnexion'):
104
+ del st.session_state.client
105
+ del st.session_state.current_page
106
+ st.rerun()
107
+
108
+ if __name__ == "__main__":
109
+ main()
110
+
pages/accueil.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import datetime
3
+ import pronotepy
4
+
5
+ from pages import accueil, devoirs, edt, contenu
6
+
7
+ def app(client):
8
+ st.title('Accueil')
9
+ st.write("Bienvenue sur la page d'accueil.")
10
+
11
+ # Configuration des colonnes pour Emploi du temps et Devoirs
12
+ col1, col2 = st.columns([3, 2]) # Donner plus d'espace à l'emploi du temps
13
+
14
+ with col1:
15
+ st.subheader("Emploi du temps")
16
+ today = datetime.date.today()
17
+ if not display_timetable_for_date(client, today):
18
+ # Si aucun cours aujourd'hui, afficher pour le jour suivant
19
+ next_day = today + datetime.timedelta(days=1)
20
+ st.warning(f"Aucun cours prévu pour aujourd'hui. Affichage pour le {next_day.strftime('%A %d %B')}.")
21
+ display_timetable_for_date(client, next_day)
22
+ # Bouton pour ouvrir la page détaillée de l'emploi du temps
23
+ if st.button('Voir l\'emploi du temps complet'):
24
+ st.session_state.current_page = 'edt'
25
+ st.rerun()
26
+
27
+ with col2:
28
+ st.subheader("Devoirs pour demain")
29
+ tomorrow = datetime.date.today() + datetime.timedelta(days=1)
30
+ homeworks = client.homework(tomorrow, tomorrow)
31
+ if homeworks:
32
+ for homework in homeworks:
33
+ with st.expander(f"{'✅' if homework.done else '❌'} | {homework.subject.name}", expanded=False):
34
+ st.markdown(f"**Description:** {homework.description}")
35
+ st.markdown(f"**Statut:** {'✅ Fait' if homework.done else '❌ À faire'}")
36
+ else:
37
+ st.write("Pas de devoirs prévus pour demain.")
38
+ # Bouton pour ouvrir la page dédiée aux devoirs
39
+ if st.button('Voir tous les devoirs'):
40
+ st.session_state.current_page = 'devoirs'
41
+ st.rerun()
42
+
43
+ def display_timetable_for_date(client, date):
44
+ timetable = client.lessons(datetime.datetime.combine(date, datetime.datetime.min.time()),
45
+ datetime.datetime.combine(date, datetime.datetime.min.time()) + datetime.timedelta(days=1))
46
+ sorted_timetable = sorted(timetable, key=lambda lesson: lesson.start)
47
+
48
+ if sorted_timetable:
49
+ for lesson in sorted_timetable:
50
+ with st.container():
51
+ st.markdown(f"**{lesson.subject.name}** ({lesson.start.strftime('%H:%M')} - {lesson.end.strftime('%H:%M')}) - Salle: {lesson.classroom}")
52
+ if lesson.status:
53
+ st.caption(f"**Statut**: {lesson.status}")
54
+ return True
55
+ return False
56
+
57
+ if __name__ == "__main__":
58
+ client = pronotepy.Client(...)
59
+ app(client)
pages/contenu.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # contenu.py
2
+ import streamlit as st
3
+
4
+ def show_lesson_content():
5
+ if st.button("◀️ Retour"):
6
+ st.session_state.current_page = 'edt'
7
+ st.rerun()
8
+
9
+ content = st.session_state.get('selected_content', None)
10
+ if content:
11
+ st.title("📜 Contenu du cours")
12
+ st.write(f"🔠 **Titre :** {content.title if content.title else 'Non spécifié'}")
13
+ st.write(f"🧷 **Description :** {'' if content.description else 'Non spécifiée'}")
14
+ st.markdown(content.description if content.description else '')
15
+
16
+ if content.files:
17
+ st.write("**📂 Fichiers attachés :**")
18
+ for file in content.files:
19
+ st.write(f"- [{file.name}]({file.url})")
20
+ else:
21
+ st.write("📁 Aucun fichier attaché.")
22
+ else:
23
+ st.write("⚠️ Sélectionnez un cours pour voir son contenu.")
24
+ if st.button("◀️ Retour"):
25
+ st.session_state.current_page = 'edt'
26
+ st.rerun()
27
+
pages/conv.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pronotepy
3
+
4
+ def load_discussions(client):
5
+ # Charger toutes les discussions
6
+ return client.discussions()
7
+
8
+ def display_discussion(discussion):
9
+ # Afficher les messages d'une discussion
10
+ for message in discussion.messages:
11
+ author = "Vous" if message.author is None else message.author
12
+ st.markdown(f"##### **{author}**:")
13
+ st.markdown(f"> {message.content}")
14
+ st.caption(f"*Envoyé le {message.date.strftime('%d/%m/%Y à %H:%M')}*")
15
+ st.markdown("---")
16
+
17
+ def app(client):
18
+ st.title('📧 Messagerie Pronote')
19
+
20
+ if not client.logged_in:
21
+ st.error("🔴 Veuillez vous connecter pour accéder à la messagerie.")
22
+ return
23
+
24
+ discussions = load_discussions(client)
25
+
26
+ # Sélection d'une discussion
27
+ discussion_subjects = [d.subject for d in discussions]
28
+ choice = st.selectbox("💬 Choisissez une discussion", ["Nouvelle discussion..."] + discussion_subjects)
29
+
30
+ if choice == "Nouvelle discussion...":
31
+ # Créer une nouvelle discussion
32
+ subject = st.text_input("#️⃣ Sujet")
33
+ message = st.text_area("📟 Message")
34
+ recipients = client.get_recipients()
35
+ recipient_names = [f"{r.name} ({r.type})" for r in recipients]
36
+ selected_recipient = st.selectbox("🧷 Destinataire", recipient_names)
37
+ if st.button("📤 Envoyer"):
38
+ selected_index = recipient_names.index(selected_recipient)
39
+ client.new_discussion(subject, message, [recipients[selected_index]])
40
+ st.success("📨 Discussion créée avec succès.")
41
+ else:
42
+ # Afficher la discussion sélectionnée
43
+ selected_discussion = discussions[discussion_subjects.index(choice)]
44
+ display_discussion(selected_discussion)
45
+
46
+ # Répondre à une discussion
47
+ reply_message = st.text_area("📟 Votre message")
48
+ if st.button("📤 Répondre"):
49
+ selected_discussion.reply(reply_message)
50
+ st.success("📨 Message envoyé.")
pages/devoirs.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import datetime
3
+ import pronotepy
4
+ import uuid
5
+
6
+ def app(client):
7
+ st.title('📚 Devoirs')
8
+
9
+ # Sélection de la semaine
10
+ selected_week = st.date_input("Sélectionnez une semaine", value=datetime.date.today())
11
+ start_week = selected_week - datetime.timedelta(days=selected_week.weekday())
12
+ end_week = start_week + datetime.timedelta(days=4) # Fin de la semaine au vendredi
13
+
14
+ # Récupération des devoirs pour la semaine sélectionnée
15
+ homeworks = client.homework(start_week, end_week)
16
+
17
+ # Création des onglets par jour de la semaine + À faire et Déjà fait
18
+ tabs = st.tabs(["🔴 À faire durant la semaine", "1️⃣ Lundi", "2️⃣ Mardi", "3️⃣ Mercredi", "4️⃣ Jeudi", "5️⃣ Vendredi", "🟢 Déjà fait durant la semaine"])
19
+ days = [start_week + datetime.timedelta(days=i) for i in range(5)]
20
+
21
+ with tabs[0]: # À faire durant la semaine
22
+ homeworks_to_do = [hw for hw in homeworks if not hw.done]
23
+ display_homework_list(homeworks_to_do, client)
24
+
25
+ with tabs[6]: # Déjà fait durant la semaine
26
+ homeworks_done = [hw for hw in homeworks if hw.done]
27
+ display_homework_list(homeworks_done, client)
28
+
29
+ for i, tab in enumerate(tabs[1:5]): # Boucle sur les jours de la semaine
30
+ with tab:
31
+ daily_homeworks = [hw for hw in homeworks if hw.date == days[i]]
32
+ display_homework_list(daily_homeworks, client)
33
+
34
+ def display_homework_list(homeworks, client):
35
+ for homework in homeworks:
36
+ with st.expander(f"{"✅" if homework.done else "❌"} | {homework.subject.name} - *pour le {homework.date.strftime('%d/%m/%Y')}*"):
37
+ st.markdown(f"""
38
+ - **Statut :** {"✅ Fait" if homework.done else "❌ À faire"}
39
+ - **Description :** {homework.description}
40
+ """, unsafe_allow_html=True)
41
+
42
+ # Generate a unique key for each button using uuid
43
+ unique_key = str(uuid.uuid4()) # Generate a unique key
44
+
45
+ # Use the unique key for the button to avoid DuplicateWidgetID error
46
+ st.button("✅ Marquer comme fait" if not homework.done else "❌ Marquer comme à faire", key=unique_key, on_click=update_homework_status, args=(homework, client))
47
+
48
+ def update_homework_status(homework, client):
49
+ new_status = not homework.done
50
+ homework.set_done(new_status)
pages/edt.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pronotepy
3
+ from datetime import datetime, timedelta
4
+
5
+ # A simple mapping of subjects to emojis. Add more subjects and emojis as needed.
6
+ subject_emojis = {
7
+ 'ANGLAIS LV SECTION': '🇬🇧',
8
+ 'FRANCAIS': '🇫🇷',
9
+ 'EPS': '🏃‍♂️',
10
+ 'Sport': '🏃‍♂️',
11
+ 'Histoire/Géographie': '🌍',
12
+ 'HIST/GEO': '🌍',
13
+ 'Mathématiques': '🔢',
14
+ 'MATHS': '🔢',
15
+ 'PH-CHIMIE': '🧪',
16
+ 'Physique-Chimie': '🧪',
17
+ 'ANGLAIS LV1': '🇬🇧',
18
+ 'ESPAGNOL LV2': '🇪🇸',
19
+ 'SVT': '🌿',
20
+ 'Technologie': '🔧',
21
+ 'TECHNO': '🔧',
22
+ 'TECHNOLOGIE': '🔧',
23
+ 'Arts Plastiques': '🎨',
24
+ 'ARTS PLASTIQUES': '🎨',
25
+ 'Musique': '🎵',
26
+ 'MUSIQUE': '🎵',
27
+ 'ED MUSICALE': '🎵'
28
+ }
29
+
30
+ # A function to get emoji by subject
31
+ def get_emoji(subject_name):
32
+ return subject_emojis.get(subject_name, '📚') # Return a default book emoji if subject not found
33
+
34
+ def app(client):
35
+ st.title("📅 Emploi du temps")
36
+
37
+ # Sélection de la semaine
38
+ selected_week = st.date_input("✨ Sélectionnez une semaine", value=datetime.today())
39
+ start_of_week = selected_week - timedelta(days=selected_week.weekday()) # Adjust for selected week
40
+ week_dates = [start_of_week + timedelta(days=i) for i in range(5)] # List of dates for the selected workweek
41
+
42
+ # Create tabs for each day of the week in French
43
+ tabs = st.tabs(["1️⃣ Lundi", "2️⃣ Mardi", "3️⃣ Mercredi", "4️⃣ Jeudi", "5️⃣ Vendredi"])
44
+
45
+ for i, tab in enumerate(tabs):
46
+ with tab:
47
+ date_for_pronote = datetime.combine(week_dates[i], datetime.min.time())
48
+
49
+ # Récupération de l'emploi du temps pour la journée sélectionnée
50
+ timetable = client.lessons(date_for_pronote, date_for_pronote + timedelta(days=1))
51
+
52
+ # Tri des cours du plus tôt au plus tard
53
+ sorted_timetable = sorted(timetable, key=lambda lesson: lesson.start)
54
+
55
+ if sorted_timetable:
56
+ # Affichage de l'emploi du temps avec emojis et bouton pour chaque leçon ayant un contenu
57
+ for lesson in sorted_timetable:
58
+ emoji = get_emoji(lesson.subject.name)
59
+ with st.expander(f"{emoji} {lesson.status if lesson.status else ""} {lesson.subject.name} ({lesson.start.strftime('%H:%M')} - {lesson.end.strftime('%H:%M')})"):
60
+ st.write(f"🎭 **Salle :** {lesson.classroom}")
61
+ st.write(f"🧑‍🏫 **Professeur :** {lesson.teacher_name}")
62
+ if lesson.status:
63
+ st.write(f"🔦 **Statut :** {lesson.status}")
64
+ if lesson.content:
65
+ # Bouton pour afficher le contenu de la leçon dans une nouvelle page
66
+ if st.button(f"📜 Afficher le contenu pour {lesson.subject.name}", key=lesson.id):
67
+ # Utilisation du session state de Streamlit pour stocker l'objet contenu
68
+ st.session_state['selected_content'] = lesson.content
69
+ st.session_state.current_page = 'contenu'
70
+ st.rerun()
71
+ else:
72
+ st.write("🔴 Aucun cours pour cette journée.")
pages/info.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from pronotepy import Client
3
+ import datetime
4
+
5
+ def app(client: Client):
6
+ st.title('ℹ️ Informations et Enquêtes')
7
+
8
+ # Barre de recherche au-dessus des onglets
9
+ search_query = st.text_input("🔍 Recherche", "")
10
+
11
+ try:
12
+ # Récupérer toutes les informations
13
+ informations = client.information_and_surveys()
14
+
15
+ # Définir les noms des onglets, avec "Toutes les infos" en premier
16
+ mois_annee_scolaire_noms = ["✨ Toutes les infos", "1️⃣ Septembre", "2️⃣ Octobre", "3️⃣ Novembre", "4️⃣ Décembre",
17
+ "5️⃣ Janvier", "6️⃣ Février", "7️⃣ Mars", "8️⃣ Avril", "9️⃣ Mai", "🔟 Juin", "🔟 Juillet"]
18
+
19
+ # Créer dynamiquement les onglets
20
+ tabs = st.tabs(mois_annee_scolaire_noms)
21
+
22
+ for i, tab in enumerate(tabs):
23
+ with tab:
24
+ if i == 0: # Pour l'onglet "Toutes les infos"
25
+ display_monthly_info(informations, search_query)
26
+ else: # Pour les mois de septembre à juillet
27
+ mois = i + 8 if i < 5 else i - 4 # Ajustement pour l'année scolaire
28
+ infos_du_mois = [info for info in informations if info.creation_date and info.creation_date.month == mois]
29
+ display_monthly_info(infos_du_mois, search_query)
30
+
31
+ except Exception as e:
32
+ st.error("⚠️ Une erreur s'est produite lors de la récupération des informations.")
33
+ st.error(str(e))
34
+
35
+
36
+ def display_monthly_info(informations, search_query):
37
+ filtered_infos = search_informations(informations, search_query)
38
+ sorted_infos = sorted(filtered_infos, key=lambda x: x.creation_date, reverse=True)
39
+
40
+ if not sorted_infos: # Vérifier si la liste filtrée est vide
41
+ st.info("🔴 Aucune information trouvée.")
42
+ else:
43
+ for info in sorted_infos:
44
+ display_information(info)
45
+
46
+ def search_informations(informations, query):
47
+ return [info for info in informations if query.lower() in (info.content or '').lower()
48
+ or query.lower() in (info.category or '').lower()
49
+ or query.lower() in (info.author or '').lower()
50
+ or query in (info.creation_date.strftime('%Y-%m-%d') if info.creation_date else '')]
51
+
52
+
53
+ def display_information(info):
54
+ creation_date = info.creation_date.strftime('%Y-%m-%d') if info.creation_date else 'Inconnue'
55
+ content_formatted = info.content.replace('\n', '<br>')
56
+
57
+ with st.expander(f"{info.title} - {info.author}", expanded=not info.read):
58
+ st.markdown(f"""
59
+ - _**Auteur**: {info.author} | **Date de Création**: {creation_date} | **Catégorie**: {info.category}_
60
+ ---
61
+ {content_formatted}
62
+ """, unsafe_allow_html=True)
63
+ if not info.read:
64
+ if st.button('Marquer comme lu', key=info.id):
65
+ info.mark_as_read(True)
66
+ st.rerun()
pages/notes.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from collections import defaultdict
3
+
4
+ def calculate_average(grades):
5
+ total_points, total_coefficients = 0, 0
6
+ for grade in grades:
7
+ try:
8
+ if grade.grade.lower() != 'absent':
9
+ numeric_grade = float(grade.grade)
10
+ grade_out_of = float(grade.out_of)
11
+ coefficient = float(grade.coefficient)
12
+ normalized_grade = (numeric_grade / grade_out_of) * 20
13
+ total_points += normalized_grade * coefficient
14
+ total_coefficients += coefficient
15
+ except ValueError:
16
+ continue
17
+ return total_points / total_coefficients if total_coefficients > 0 else "Aucune Note"
18
+
19
+ def app(client):
20
+ st.title('📝 Notes')
21
+
22
+ # Dropdown pour sélectionner la période
23
+ selected_period = st.selectbox("🧷 Sélectionner la période", ["Trimestre 1", "Trimestre 2", "Trimestre 3", "Année"])
24
+
25
+ # Filtrer les périodes en fonction de la sélection
26
+ if selected_period == "Année":
27
+ periods_to_display = client.periods
28
+ else:
29
+ periods_to_display = [period for period in client.periods if period.name == selected_period]
30
+
31
+ # Créer une liste des matières pour les onglets
32
+ tab_labels = sorted({grade.subject.name for period in periods_to_display for grade in period.grades})
33
+
34
+ # Créer des onglets pour les matières
35
+ tabs = st.tabs(tab_labels)
36
+
37
+ for tab, subject in zip(tabs, tab_labels):
38
+ with tab:
39
+ # Afficher les notes pour toutes les périodes sélectionnées
40
+ for period in periods_to_display:
41
+ # Organiser les notes par matière
42
+ grades_by_subject = defaultdict(list)
43
+ for grade in period.grades:
44
+ grades_by_subject[grade.subject.name].append(grade)
45
+
46
+ # Afficher les notes pour la matière de l'onglet actuel
47
+ if subject in grades_by_subject:
48
+ for grade in grades_by_subject[subject]:
49
+ with st.expander(f"📝 {grade.grade}/{grade.out_of} | {"📎 " + grade.comment if grade.comment else "Et voilà, ça ne donne pas de nom !"} (📅 {grade.date})"):
50
+ st.markdown("### Information")
51
+ st.write(f"**Commentaire** : {grade.comment}")
52
+ st.write(f"**Date** : {grade.date}")
53
+ st.write(f"**Coefficient** : {grade.coefficient}")
54
+ if grade.is_bonus:
55
+ st.write(f"**Note Bonus** (*Est pris en compte seulement les points au-dessus de 10*)")
56
+ if grade.is_optionnal:
57
+ st.write(f"**Note Optionnelle** (*Est pris en compte seulement si la note augmente la moyenne*)")
58
+ st.markdown("### Eleve")
59
+ st.write(f"{grade.grade}/{grade.out_of}")
60
+ st.markdown("### Classe")
61
+ st.write(f"**Moyenne** : {grade.average}")
62
+ st.write(f"**Minimum** : {grade.min}")
63
+ st.write(f"**Maximum** : {grade.max}")
64
+
65
+ # Instead of directly calculating the overall average, gather all grades
66
+ all_grades = []
67
+ for period in periods_to_display:
68
+ for grade in period.grades:
69
+ all_grades.append(grade)
70
+
71
+ # Use the calculate_average function to calculate the overall average
72
+ overall_average = calculate_average(all_grades)
73
+
74
+ st.subheader("⭐ Moyenne Générale")
75
+ if isinstance(overall_average, str):
76
+ st.write(overall_average)
77
+ else:
78
+ st.write(f"### {overall_average:.2f}/20")
79
+
80
+
pages/vie_scolaire.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from pronotepy import Client
3
+ import datetime
4
+
5
+ def afficher_details_periode(client: Client, nom_periode: str):
6
+ if nom_periode == "Année entière":
7
+ absences = [absence for periode in client.periods for absence in periode.absences]
8
+ retards = [retard for periode in client.periods for retard in periode.delays]
9
+ punitions = [punition for periode in client.periods for punition in periode.punishments]
10
+ else:
11
+ periode = next((p for p in client.periods if p.name == nom_periode), None)
12
+ if periode:
13
+ absences = periode.absences
14
+ retards = periode.delays
15
+ punitions = periode.punishments
16
+ rapports = [periode.report] if periode.report else []
17
+ else:
18
+ absences, retards, punitions, rapports = [], [], [], []
19
+
20
+ # Affichage des informations
21
+ afficher_absences(absences)
22
+ afficher_retards(retards)
23
+ afficher_punitions(punitions)
24
+ if rapports:
25
+ afficher_rapports(rapports)
26
+ else:
27
+ st.info("🔴 Aucun rapport disponible pour cette période.")
28
+
29
+ def afficher_absences(absences):
30
+ if absences:
31
+ for absence in absences:
32
+ with st.expander(f"🚫 Absence du {absence.from_date.strftime('%d/%m/%Y')} au {absence.to_date.strftime('%d/%m/%Y')}"):
33
+ st.write(f"🕒 Heures manquées: {absence.hours}")
34
+ st.write(f"📆 Jours manqués: {absence.days}")
35
+ st.write(f"✅ Justifiée: {'Oui' if absence.justified else 'Non'}")
36
+ st.write(f"📝 Raisons: {', '.join(absence.reasons)}")
37
+ else:
38
+ st.info("🔴 Aucune absence enregistrée pour cette période.")
39
+
40
+ def afficher_retards(retards):
41
+ if retards:
42
+ for retard in retards:
43
+ with st.expander(f"⏰ Retard le {retard.date.strftime('%d/%m/%Y')}"):
44
+ st.write(f"⏳ Minutes manquées: {retard.minutes}")
45
+ st.write(f"✅ Justifié: {'Oui' if retard.justified else 'Non'}")
46
+ st.write(f"📜 Justification: {retard.justification}")
47
+ st.write(f"📝 Raisons: {', '.join(retard.reasons)}")
48
+ else:
49
+ st.info("🔴 Aucun retard enregistré pour cette période.")
50
+
51
+ def afficher_punitions(punitions):
52
+ if punitions:
53
+ for punition in punitions:
54
+ with st.expander(f"🚨 Punition: {punition.nature} le {punition.given.strftime('%d/%m/%Y')}"):
55
+ st.write(f"🔹 Donnée par: {punition.giver}")
56
+ st.write(f"🔸 Raisons: {', '.join(punition.reasons)}")
57
+ else:
58
+ st.info("🔴 Aucune punition enregistrée pour cette période.")
59
+
60
+ subject_emojis = {
61
+ 'ANGLAIS LV SECTION': '🇬🇧',
62
+ 'FRANCAIS': '🇫🇷',
63
+ 'EPS': '🏃‍♂️',
64
+ 'Sport': '🏃‍♂️',
65
+ 'Histoire/Géographie': '🌍',
66
+ 'HIST/GEO': '🌍',
67
+ 'Mathématiques': '🔢',
68
+ 'MATHS': '🔢',
69
+ 'PH-CHIMIE': '🧪',
70
+ 'Physique-Chimie': '🧪',
71
+ 'ANGLAIS LV1': '🇬🇧',
72
+ 'ESPAGNOL LV2': '🇪🇸',
73
+ 'SVT': '🌿',
74
+ 'Technologie': '🔧',
75
+ 'TECHNO': '🔧',
76
+ 'TECHNOLOGIE': '🔧',
77
+ 'Arts Plastiques': '🎨',
78
+ 'ARTS PLASTIQUES': '🎨',
79
+ 'Musique': '🎵',
80
+ 'MUSIQUE': '🎵',
81
+ 'ED MUSICALE': '🎵'
82
+ }
83
+
84
+ def afficher_rapports(rapports):
85
+ if rapports:
86
+ for rapport in rapports:
87
+ if rapport.subjects:
88
+ for sujet in rapport.subjects:
89
+ with st.expander(f"{subject_emojis.get(sujet.name, '📚')} Matière: {sujet.name} ({', '.join(sujet.teachers) if sujet.teachers else ''})", expanded=False):
90
+ st.subheader("🧷 Information")
91
+ st.markdown(f"""
92
+ - 📋 **Moyenne de l'élève**: `{sujet.student_average if sujet.student_average else 'Pas visible'}`
93
+ - 📊 **Moyenne de la classe**: `{sujet.class_average if sujet.class_average else 'Bizarement invisible'}`
94
+ - 📈 **Moyenne minimale**: `{sujet.min_average if sujet.min_average else 'On ne sait pas'}`
95
+ - 📉 **Moyenne maximale**: `{sujet.max_average if sujet.max_average else 'Inconnu'}`
96
+ - 🧑‍🏫 **Enseignants**: `{', '.join(sujet.teachers) if sujet.teachers else 'Apparemment, il accun enseignants, étrange ?'}`""")
97
+ if sujet.comments:
98
+ st.subheader("📃 Commentaires")
99
+ for commentaire in sujet.comments:
100
+ st.write(f"- {commentaire}")
101
+ if rapport.comments:
102
+ st.subheader("📄 Commentaires globaux")
103
+ for commentaire in rapport.comments:
104
+ st.write(f"- {commentaire}")
105
+ else:
106
+ st.info("🔴 Aucun rapport disponible pour cette période.")
107
+
108
+ def app(client: Client):
109
+ st.title('📍 Vie Scolaire')
110
+
111
+ options_periode = ["Trimestre 1", "Trimestre 2", "Trimestre 3"]
112
+ nom_periode_selectionnee = st.selectbox("📅 Sélectionner la période", options_periode)
113
+
114
+ tabs = st.tabs(["Tout", "🚫 Absences", "⏰ Retards", "🚨 Punitions", "📊 Bulletin"])
115
+
116
+ if nom_periode_selectionnee:
117
+ with tabs[0]:
118
+ afficher_details_periode(client, nom_periode_selectionnee)
119
+ with tabs[1]:
120
+ afficher_absences([absence for periode in client.periods for absence in periode.absences] if nom_periode_selectionnee == "Année entière" else [absence for periode in client.periods if periode.name == nom_periode_selectionnee for absence in periode.absences])
121
+ with tabs[2]:
122
+ afficher_retards([retard for periode in client.periods for retard in periode.delays] if nom_periode_selectionnee == "Année entière" else [retard for periode in client.periods if periode.name == nom_periode_selectionnee for retard in periode.delays])
123
+ with tabs[3]:
124
+ afficher_punitions([punition for periode in client.periods for punition in periode.punishments] if nom_periode_selectionnee == "Année entière" else [punition for periode in client.periods if periode.name == nom_periode_selectionnee for punition in periode.punishments])
125
+ with tabs[4]:
126
+ if nom_periode_selectionnee == "Année entière":
127
+ rapports = [periode.report for periode in client.periods if periode.report]
128
+ if rapports:
129
+ afficher_rapports(rapports)
130
+ else:
131
+ st.info("🔴 Aucun rapport disponible pour cette période.")
132
+ else:
133
+ periode = next((p for p in client.periods if p.name == nom_periode_selectionnee), None)
134
+ if periode and periode.report:
135
+ afficher_rapports([periode.report])
136
+ else:
137
+ st.info("🔴 Aucun rapport disponible pour cette période.")
138
+
139
+ if __name__ == "__main__":
140
+ client = Client() # Assurez-vous d'initialiser correctement votre client ici
141
+ app(client)
142
+
143
+
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ pronotepy
2
+ streamlit