""" Training Routes - GMAO Collège Gestion des formations """ from flask import Blueprint, render_template, request, flash, redirect, url_for from flask_login import login_required, current_user from datetime import datetime from app_new.extensions import db from ..core.models.planning import Training, TrainingParticipant training_bp = Blueprint('trainings', __name__) @training_bp.route('/') @login_required def index(): """Liste des formations.""" trainings = Training.query.order_by(Training.start_date).all() return render_template('training/index.html', trainings=trainings) @training_bp.route('/new', methods=['GET', 'POST']) @login_required def create(): """Créer une formation.""" if request.method == 'POST': start_date = _parse_date(request.form.get('start_date')) end_date = _parse_date(request.form.get('end_date')) or start_date if not start_date or end_date < start_date: flash('La période de formation est invalide.', 'danger') return render_template('training/new.html'), 400 title = (request.form.get('title') or '').strip() if not title: flash('Le titre est obligatoire.', 'danger') return render_template('training/new.html'), 400 training = Training( name=title, description=request.form.get('description'), start_date=start_date, end_date=end_date, start_time=_parse_time(request.form.get('start_time')), end_time=_parse_time(request.form.get('end_time')), location=request.form.get('location'), ) db.session.add(training) db.session.flush() db.session.add(TrainingParticipant( training_id=training.id, user_id=current_user.id, is_confirmed=True, notes='Créateur de la formation', )) db.session.commit() flash('Formation créée avec succès.', 'success') return redirect(url_for('trainings.index')) return render_template('training/new.html') @training_bp.route('//register', methods=['POST']) @login_required def register(id): """S'inscrire à une formation.""" training = Training.query.get_or_404(id) participant = TrainingParticipant.query.filter_by( training_id=id, user_id=current_user.id ).first() if participant: flash('Déjà inscrit.', 'warning') else: participant = TrainingParticipant( training_id=id, user_id=current_user.id, is_confirmed=True, ) db.session.add(participant) db.session.commit() flash('Inscription réussie.', 'success') return redirect(url_for('trainings.index')) @training_bp.route('/my-trainings') @login_required def my_trainings(): """Mes formations.""" participations = TrainingParticipant.query.filter_by(user_id=current_user.id).all() return render_template('training/my_trainings.html', participations=participations) def _parse_date(value): try: return datetime.strptime(value, '%Y-%m-%d').date() if value else None except (TypeError, ValueError): return None def _parse_time(value): try: return datetime.strptime(value, '%H:%M').time() if value else None except (TypeError, ValueError): return None @training_bp.route('/import/outlook/', methods=['GET', 'POST']) @login_required def import_outlook(interpretation_id): """Confirme une formation détectée dans un mail Outlook sans effacer le mail source.""" from app_new.outlook.models import OutlookMailInterpretation interpretation = OutlookMailInterpretation.query.get_or_404(interpretation_id) if interpretation.user_id != current_user.id: return 'Non autorisé', 403 if interpretation.analysis_type != 'formation': flash("Ce mail n'a pas été identifié comme une formation.", 'danger') return redirect(url_for('outlook_dashboard.interpretations')) existing = Training.query.filter_by(source_type='outlook', source_id=str(interpretation.id)).first() if existing: flash('Cette formation a déjà été importée.', 'warning') return redirect(url_for('trainings.detail', id=existing.id)) mail = interpretation.mail suggested_date = interpretation.suggested_date.date() if interpretation.suggested_date else None prefill = Training( name=interpretation.suggested_title or (mail.subject if mail else '') or 'Formation', description=interpretation.suggested_description or (mail.body_preview if mail else ''), start_date=suggested_date, end_date=suggested_date, location=interpretation.suggested_location, ) if request.method == 'POST': start_date = _parse_date(request.form.get('start_date')) end_date = _parse_date(request.form.get('end_date')) or start_date title = (request.form.get('title') or '').strip() if not title or not start_date or end_date < start_date: flash('Le titre et une période valide sont obligatoires.', 'danger') return render_template('training/new.html', training=prefill, source_interpretation=interpretation), 400 training = Training( name=title, description=request.form.get('description'), start_date=start_date, end_date=end_date, start_time=_parse_time(request.form.get('start_time')), end_time=_parse_time(request.form.get('end_time')), location=request.form.get('location'), source_type='outlook', source_id=str(interpretation.id), source_subject=mail.subject if mail else None, source_sender=(mail.sender or mail.sender_email) if mail else None, ) db.session.add(training) db.session.flush() db.session.add(TrainingParticipant(training_id=training.id, user_id=current_user.id, is_confirmed=True, notes='Importée depuis Outlook')) interpretation.status = 'accepted' db.session.commit() flash('Formation importée. Toute maintenance est bloquée sur cette période.', 'success') return redirect(url_for('trainings.detail', id=training.id)) return render_template('training/new.html', training=prefill, source_interpretation=interpretation) @training_bp.route('/') @login_required def detail(id): training = Training.query.get_or_404(id) participants = TrainingParticipant.query.filter_by(training_id=id).all() participant_users = {participant.user_id: participant for participant in participants} return render_template('training/detail.html', training=training, participants=participants, participant_users=participant_users) @training_bp.route('//edit', methods=['GET', 'POST']) @login_required def edit(id): training = Training.query.get_or_404(id) if request.method == 'POST': start_date = _parse_date(request.form.get('start_date')) end_date = _parse_date(request.form.get('end_date')) or start_date if not start_date or end_date < start_date: flash('La période de formation est invalide.', 'danger') return render_template('training/new.html', training=training), 400 training.name = (request.form.get('title') or '').strip() training.description = request.form.get('description') training.start_date = start_date training.end_date = end_date training.start_time = _parse_time(request.form.get('start_time')) training.end_time = _parse_time(request.form.get('end_time')) training.location = request.form.get('location') db.session.commit() flash('Formation mise à jour.', 'success') return redirect(url_for('trainings.detail', id=id)) return render_template('training/new.html', training=training) @training_bp.route('//unregister', methods=['POST']) @login_required def unregister(id): participant = TrainingParticipant.query.filter_by( training_id=id, user_id=current_user.id ).first_or_404() db.session.delete(participant) db.session.commit() flash('Inscription annulée.', 'success') return redirect(url_for('trainings.detail', id=id))