245 lines
9.5 KiB
Python
245 lines
9.5 KiB
Python
"""
|
|
Pronote Routes - GMAO Collège
|
|
Intégration Pronote
|
|
"""
|
|
import logging
|
|
from flask import Blueprint, render_template, redirect, url_for, request, flash, jsonify
|
|
from flask_login import login_required, current_user
|
|
from app_new.extensions import db, csrf
|
|
from ..pronote.models import PronoteSession
|
|
from ..core.models.college import Room, RoomSchedule
|
|
import os
|
|
import json
|
|
from datetime import datetime, date, timedelta
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
pronote_bp = Blueprint('pronote', __name__, template_folder='templates')
|
|
|
|
|
|
@pronote_bp.route('/')
|
|
@login_required
|
|
def index():
|
|
"""Page principale Pronote."""
|
|
session = PronoteSession.get()
|
|
return render_template('pronote/index.html', session=session)
|
|
|
|
|
|
@pronote_bp.route('/connect', methods=['GET', 'POST'])
|
|
@login_required
|
|
def connect():
|
|
"""Connexion à Pronote via QR Code."""
|
|
if request.method == 'POST':
|
|
qr_code = request.form.get('qr_code', '').strip()
|
|
pin = request.form.get('pin', '').strip()
|
|
account_pin = request.form.get('account_pin', '').strip() or None
|
|
|
|
if not qr_code or not pin:
|
|
flash('QR Code et PIN sont requis.', 'danger')
|
|
return redirect(url_for('pronote.connect'))
|
|
|
|
try:
|
|
from app_new.lib_ext.pronote_client import connect_with_qr, save_session_to_db
|
|
client = connect_with_qr(qr_code, pin, account_pin)
|
|
|
|
if client:
|
|
try:
|
|
creds = client.export_credentials()
|
|
session_data = {
|
|
'token': creds.get('password') or creds.get('token'),
|
|
'url': creds.get('pronote_url') or creds.get('url'),
|
|
'username': creds.get('username'),
|
|
'device_uuid': str(client.uuid) if hasattr(client, 'uuid') else None,
|
|
'account_pin': account_pin # Sauvegarder le PIN
|
|
}
|
|
except Exception as ex:
|
|
logger.warning(f"export_credentials a échoué: {ex}")
|
|
session_data = {'url': getattr(client, 'url', None)}
|
|
|
|
save_session_to_db(session_data)
|
|
flash('Connexion PRONOTE réussie !', 'success')
|
|
return redirect(url_for('pronote.index'))
|
|
else:
|
|
flash('Échec de la connexion PRONOTE.', 'danger')
|
|
|
|
except Exception as e:
|
|
flash(f'Erreur de connexion: {str(e)}', 'danger')
|
|
|
|
return redirect(url_for('pronote.connect'))
|
|
|
|
return render_template('pronote/connect.html')
|
|
|
|
|
|
@pronote_bp.route('/planning')
|
|
@pronote_bp.route('/planning_index')
|
|
@login_required
|
|
def planning():
|
|
"""Page principale des plannings."""
|
|
teaching_rooms = Room.query.filter(Room.room_type.has(is_teaching=True)).order_by(
|
|
Room.building_id, Room.name
|
|
).all()
|
|
return render_template('pronote/planning_index.html', rooms=teaching_rooms)
|
|
|
|
|
|
@pronote_bp.route('/rooms')
|
|
@login_required
|
|
def rooms():
|
|
"""Liste des salles."""
|
|
rooms_list = Room.query.order_by(Room.name).all()
|
|
return render_template('pronote/rooms.html', rooms=rooms_list)
|
|
|
|
|
|
@pronote_bp.route('/sync-salles', methods=['POST'])
|
|
@login_required
|
|
def sync_salles():
|
|
"""Synchroniser les salles depuis Pronote."""
|
|
from app_new.lib_ext.pronote_client import get_client, get_all_salles
|
|
client = get_client()
|
|
if not client:
|
|
flash('Non connecté à Pronote.', 'warning')
|
|
return redirect(url_for('pronote.connect'))
|
|
|
|
try:
|
|
salles_data = get_all_salles(client)
|
|
created = 0
|
|
for salle in salles_data:
|
|
salle_nom = salle.get('L', '')
|
|
if not Room.query.filter_by(name=salle_nom).first():
|
|
from app_new.core.models.college import Building, RoomType
|
|
building = Building.query.filter_by(name='Collège').first()
|
|
if not building:
|
|
building = Building(name='Collège', description='Bâtiment principal')
|
|
db.session.add(building)
|
|
db.session.commit()
|
|
|
|
cours_type = RoomType.query.filter_by(name='cours').first()
|
|
if not cours_type:
|
|
cours_type = RoomType(name='cours', is_teaching=True)
|
|
db.session.add(cours_type)
|
|
db.session.commit()
|
|
|
|
room = Room(name=salle_nom, code=salle_nom, floor=0, building_id=building.id, room_type_id=cours_type.id)
|
|
db.session.add(room)
|
|
created += 1
|
|
db.session.commit()
|
|
flash(f'{created} nouvelles salles synchronisées depuis Pronote.', 'success')
|
|
except Exception as e:
|
|
flash(f'Erreur synchronisation: {str(e)}', 'danger')
|
|
|
|
return redirect(url_for('pronote.rooms'))
|
|
|
|
|
|
@pronote_bp.route('/planning/<int:room_id>')
|
|
@login_required
|
|
def room_planning(room_id):
|
|
"""Emploi du temps d'une salle spécifique."""
|
|
from app_new.lib_ext.pronote_client import get_client
|
|
room = Room.query.get_or_404(room_id)
|
|
week_start = request.args.get("week", date.today().isoformat())
|
|
try:
|
|
monday = date.fromisoformat(week_start)
|
|
if monday.weekday() != 0:
|
|
monday = monday - timedelta(days=monday.weekday())
|
|
except:
|
|
monday = date.today() - timedelta(days=date.today().weekday())
|
|
|
|
week_end = monday + timedelta(days=6)
|
|
|
|
# Vérifier la connexion PRONOTE
|
|
client = get_client()
|
|
pronote_connected = client is not None
|
|
|
|
# Récupérer les cours depuis PRONOTE si connecté
|
|
pronote_by_day = {}
|
|
if client and pronote_connected:
|
|
from app_new.lib_ext.pronote_client import get_lessons_for_room
|
|
lessons = get_lessons_for_room(client, room.name, monday, week_end)
|
|
# Grouper par jour (les données sont déjà groupées par 'day')
|
|
for lesson in lessons:
|
|
lesson_day = lesson.get('day_of_week', lesson.get('day', 0))
|
|
if lesson_day not in pronote_by_day:
|
|
pronote_by_day[lesson_day] = []
|
|
pronote_by_day[lesson_day].append({
|
|
'heure': lesson.get('start_time', lesson.get('heure', '')),
|
|
'matiere': lesson.get('subject', lesson.get('matiere', '')),
|
|
'prof': lesson.get('teacher', lesson.get('prof', '')),
|
|
'classe': lesson.get('class_name', lesson.get('classe', ''))
|
|
})
|
|
|
|
# Récupérer les cours importés depuis la base de données
|
|
db_schedules = RoomSchedule.query.filter(
|
|
RoomSchedule.room_id == room_id,
|
|
RoomSchedule.week_start == monday
|
|
).order_by(RoomSchedule.day_of_week, RoomSchedule.start_time).all()
|
|
|
|
db_by_day = {}
|
|
for schedule in db_schedules:
|
|
if schedule.day_of_week not in db_by_day:
|
|
db_by_day[schedule.day_of_week] = []
|
|
db_by_day[schedule.day_of_week].append({
|
|
'start_time': schedule.start_time.strftime('%H:%M') if schedule.start_time else '',
|
|
'end_time': schedule.end_time.strftime('%H:%M') if schedule.end_time else '',
|
|
'subject': schedule.subject or '',
|
|
'teacher': schedule.teacher or '',
|
|
'class_name': schedule.class_name or ''
|
|
})
|
|
|
|
return render_template('pronote/room_planning.html', room=room, week_start=monday, week_end=week_end,
|
|
prev_week=monday - timedelta(days=7), next_week=monday + timedelta(days=7),
|
|
today=date.today(), pronote_connected=pronote_connected, pronote_by_day=pronote_by_day,
|
|
db_by_day=db_by_day, timedelta=timedelta)
|
|
|
|
|
|
@pronote_bp.route('/planning/<int:room_id>/import', methods=['POST'])
|
|
@login_required
|
|
def import_room_planning(room_id):
|
|
"""Importer l'emploi du temps d'une salle depuis Pronote."""
|
|
room = Room.query.get_or_404(room_id)
|
|
flash(f'Import planning pour {room.name} non implémenté.', 'info')
|
|
return redirect(url_for('pronote.room_planning', room_id=room_id))
|
|
|
|
|
|
@pronote_bp.route('/disconnect', methods=['POST'])
|
|
@login_required
|
|
def disconnect():
|
|
"""Déconnexion de Pronote."""
|
|
session = PronoteSession.get()
|
|
if session:
|
|
session.session_token = None
|
|
db.session.commit()
|
|
flash('Déconnexion Pronote réussie.', 'info')
|
|
return redirect(url_for('pronote.index'))
|
|
|
|
|
|
@pronote_bp.route('/personnels')
|
|
@login_required
|
|
def personnels():
|
|
"""Liste des personnels depuis Pronote."""
|
|
from app_new.lib_ext.pronote_client import get_client
|
|
client = get_client()
|
|
if not client:
|
|
flash('Non connecté à Pronote.', 'warning')
|
|
return redirect(url_for('pronote.connect'))
|
|
try:
|
|
personnels = [{'name': 'Simulation Personnel 1', 'role': 'Admin'}, {'name': 'Simulation Personnel 2', 'role': 'Tech'}]
|
|
return render_template('pronote/personnels.html', personnels=personnels)
|
|
except Exception as e:
|
|
flash(f'Erreur: {str(e)}', 'danger')
|
|
return redirect(url_for('pronote.index'))
|
|
|
|
|
|
@pronote_bp.route('/professeurs')
|
|
@login_required
|
|
def professeurs():
|
|
"""Liste des professeurs depuis Pronote."""
|
|
from app_new.lib_ext.pronote_client import get_client
|
|
client = get_client()
|
|
if not client:
|
|
flash('Non connecté à Pronote.', 'warning')
|
|
return redirect(url_for('pronote.connect'))
|
|
try:
|
|
profs = [{'name': 'Simulation Prof 1', 'matiere': 'Maths'}, {'name': 'Simulation Prof 2', 'matiere': 'Physique'}]
|
|
return render_template('pronote/professeurs.html', profs=profs)
|
|
except Exception as e:
|
|
flash(f'Erreur: {str(e)}', 'danger')
|
|
return redirect(url_for('pronote.index'))
|