Upload 10 files
Browse files- app.py +110 -0
- pages/accueil.py +59 -0
- pages/contenu.py +27 -0
- pages/conv.py +50 -0
- pages/devoirs.py +50 -0
- pages/edt.py +72 -0
- pages/info.py +66 -0
- pages/notes.py +80 -0
- pages/vie_scolaire.py +143 -0
- 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
|