Module de Communication : Publication d'Annonces

Retour à l'organigramme
SQLite / backend/server.js

Structure Relationnelle (Table Annonces)

  • Traçabilité : Le champ auteur_id enregistre de manière immuable quel enseignant a publié l'annonce, empêchant toute usurpation d'identité.
  • Ciblage : Le champ classe_cible permet de restreindre la visibilité du message. Si un enseignant choisit "MMI-A1", seuls les étudiants de cette classe verront l'alerte sur leur dashboard.
  • Contextualisation : Le champ optionnel sae_id permet d'attacher une annonce à une projet spécifique (SAE), créant un raccourci direct et cliquable pour l'étudiant.
/* Initialisation de la table des annonces */
CREATE TABLE IF NOT EXISTS Annonces (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    auteur_id INTEGER NOT NULL,     -- Lien vers l'enseignant (Table Comptes)
    message TEXT NOT NULL,          -- Contenu du communiqué
    classe_cible TEXT NOT NULL,     -- Filtre de visibilité (ex: 'MMI-A1')
    sae_id INTEGER,                 -- Lien optionnel vers une SAE
    date_creation TEXT NOT NULL,    -- Horodatage
    
    FOREIGN KEY (auteur_id) REFERENCES Comptes(id) ON DELETE CASCADE,
    FOREIGN KEY (sae_id) REFERENCES SAE(id) ON DELETE CASCADE
);
Node.js / backend/server.js

Insertion Sécurisée (Route POST)

  • Contrôle d'accès (RBAC) : Le serveur vérifie que l'utilisateur tentant de publier l'annonce possède bien le rôle enseignant ou admin. Les étudiants reçoivent une erreur 403 (Forbidden).
  • Extraction d'identité : L'auteur_id n'est pas fourni par le formulaire client (ce qui serait vulnérable), mais extrait directement du Token JWT sécurisé (req.user.id).
  • Horodatage Serveur : La date de création est générée par le backend (new Date().toISOString()) pour garantir une chronologie exacte, indépendante de l'horloge locale de l'ordinateur de l'enseignant.
app.post('/api/annonces', verifierToken, async (req, res) => {
    // 1. Barrière de sécurité sur les rôles
    if (req.user.role !== 'enseignant' && req.user.role !== 'admin') {
        return res.status(403).json({ message: "Refusé" });
    }
    
    // 2. Extraction des données du corps de la requête
    const { message, classe_cible, sae_id } = req.body;
    
    // 3. Horodatage côté serveur
    const date_creation = new Date().toISOString();
    
    try {
        // 4. Insertion en base de données
        await db.run(
            'INSERT INTO Annonces (auteur_id, message, classe_cible, sae_id, date_creation) VALUES (?, ?, ?, ?, ?)', 
            [req.user.id, message, classe_cible || 'Toutes', sae_id || null, date_creation]
        );
        res.status(201).json({ message: "Annonce publiée !" });
    } catch (error) { 
        res.status(500).json({ message: "Erreur serveur" }); 
    }
});
React / frontend/src/App.jsx

Gestion de l'État du Formulaire

  • State Management : Le contenu du message est lié à la variable d'état messageAnnonce via un événement onChange sur le composant Textarea, permettant un contrôle absolu du formulaire en temps réel.
  • Transmission API : À la soumission, la fonction handleCreateAnnonce compile ces états et les transmet au service réseau.
  • Rafraîchissement automatique : Une fois le succès confirmé par le serveur, l'application recharge la liste des annonces (setAnnonces(data)), vide le formulaire, et redirige l'enseignant vers son tableau de bord avec une notification de succès.
/* 1. Fonction de soumission asynchrone (App.jsx) */
const handleCreateAnnonce = async (e) => {
    e.preventDefault(); 
    setErreur(null);
    try {
        // Envoi au service API
        await saeService.createAnnonce({ 
            message: messageAnnonce, 
            classe_cible: classeCibleAnnonce, 
            sae_id: saeLieeAnnonce || null 
        }, token);
        
        // Rafraîchissement des données locales
        const data = await saeService.getAnnonces(token);
        setAnnonces(data);
        
        // Nettoyage et redirection
        setMessageAnnonce(''); 
        setSaeLieeAnnonce(''); 
        setVueActuelle('dashboard'); 
        setSucces("Annonce envoyée !");
    } catch (err) { 
        setErreur(err.message); 
    }
};

/* 2. Liaison dans l'interface (JSX) */