Module Dashboard : Ciblage et Filtrage des SAEs

Retour à l'organigramme
Architecture Data

Relations et Contraintes

  • Isolation de l'espace de travail : Un étudiant ne doit pas être pollué par les sujets des autres promotions. Le système repose sur la correspondance entre la classe de l'étudiant et la classe_cible de la SAE.
  • Le cas "Toutes" : Les enseignants ont la possibilité de publier des SAEs transversales (ex: un projet d'école) ciblant la chaîne de caractères spéciale "Toutes".
  • Vérification asynchrone : Pour chaque SAE affichée, le système doit aussi vérifier instantanément si l'étudiant a déjà soumis un fichier, afin de modifier le bouton d'action ("Déposer" vs "Mettre à jour").
/* Le schéma de correspondance (Concept) */

Table COMPTES (Étudiant)
- id: 42
- classe: 'MMI-A1'

Table SAE (Sujets)
- id: 101 | classe_cible: 'MMI-A1' (Match !)
- id: 102 | classe_cible: 'MMI-B2' (Rejeté)
- id: 103 | classe_cible: 'Toutes' (Match !)
Node.js / backend/server.js

Exécution de la Route Sécurisée

  • Identification fiable : Le serveur ne fait pas confiance au client. Il utilise l'ID extrait du Token JWT (req.user.id) pour interroger la base et récupérer la vraie classe de l'étudiant.
  • Jointure Externe (LEFT JOIN) : La requête fusionne la table SAE et la table Rendus. Le LEFT JOIN est crucial : il renvoie la SAE même si aucun rendu n'existe (les colonnes de rendu seront simplement nulles).
  • Double condition (WHERE) : Sélectionne la classe spécifique OU la valeur globale 'Toutes', en s'assurant que le statut est validé.
app.get('/api/sae', verifierToken, async (req, res) => {
    try {
        // ... (Logique admin / enseignant gérée plus haut)
        
        // 1. Récupération de la classe depuis la BDD (Sécurité)
        const userDb = await db.get('SELECT classe FROM Comptes WHERE id = ?', [req.user.id]);
        
        // 2. Requête combinée (Sujets + État du rendu de l'étudiant)
        const rows = await db.all(`
            SELECT SAE.*, Rendus.id AS rendu_id, Rendus.date_soumission 
            FROM SAE 
            /* On attache le rendu UNIQUEMENT s'il appartient à cet étudiant */
            LEFT JOIN Rendus ON SAE.id = Rendus.sae_id AND Rendus.etudiant_id = ?
            
            /* Filtre de classe et statut */
            WHERE (SAE.classe_cible = ? OR SAE.classe_cible = 'Toutes') 
            AND SAE.statut = 'validee'
        `, [req.user.id, userDb.classe]);
        
        return res.json(rows);
    } catch (error) { /* ... */ }
});
React / frontend/src/App.jsx

Moteur de Tri Client

  • Traitement local : Pour éviter de surcharger le serveur, le tri et le filtrage se font directement dans le navigateur de l'utilisateur via JavaScript (Fonction getSaesTriees).
  • Filtres cumulatifs : Utilisation de Array.prototype.filter() pour vérifier si le statut calculé de la SAE correspond aux cases cochées (En cours, Terminée, En retard).
  • Tri chronologique : Utilisation de Array.prototype.sort() pour convertir les dates en Millisecondes (getTime()) et les ordonner de manière ascendante ou descendante.
/* Fonction pure exécutée avant l'affichage */
const getSaesTriees = (listeASorter) => {
    return [...listeASorter]
      // 1. FILTRAGE PAR STATUT
      .filter(sae => {
         if (role !== 'etudiant') return true;
         const statut = determinerStatut(sae).texte; // 'En cours', 'Terminée'...
         return filtresStatut.includes(statut);
      })
      // 2. TRI PAR DATE
      .sort((a, b) => {
        // Gestion des SAEs sans date limite (placées à la fin)
        if (!a.date_rendu) return 1;
        if (!b.date_rendu) return -1;
        
        const dateA = new Date(a.date_rendu).getTime();
        const dateB = new Date(b.date_rendu).getTime();
        
        // Tri dynamique selon le select (asc/desc)
        return triDate === 'asc' ? dateA - dateB : dateB - dateA;
      });
};

/* Dans le JSX */
{getSaesTriees(saes).map(sae => (
    
...
))}