Messagerie — détails techniques
Description et fonctionnalités de ce module : Messagerie.
Couverture de tests
6 scénario(s) e2e couvrent ce module — dossier apps/open-ent-e2e/src/modules/26_messagerie.
6 test(s) e2e dans 6 scénario(s) — voir le détail
Messagerie 01_acces_au_module.spec.ts
- accès au module
Messagerie 02_envoi_message.spec.ts
- envoi de message
Messagerie — conversation enseignant ↔ élève 03_conversation_prof_eleve.spec.ts
- échange en 3 messages sur un devoir non rendu
Messagerie — signaler un abus 04_signalement_abus.spec.ts
- signaler un message reçu comme abusif (modération ADML dans le dashboard)
Messagerie — horaires (lecture seule) 05_horaires_lecture_seule.spec.ts
- hors plage, l'élève voit le bandeau de fermeture et le bouton « Envoyer » est désactivé
Messagerie — envoi différé 06_envoi_differe.spec.ts
- programmer un envoi de message (composer → Programmer l'envoi → date/heure → dossier Programmés)
➡️ Statut dans le dashboard E2E · Résultats détaillés
Restrictions de communication (exclusion élève · coupure justice)
Deux mesures d'encadrement ciblées, administrées depuis le dashboard et appliquées côté serveur.
Exclusion temporaire d'un élève
- Stockage : collection Mongo
messaging.exclusions, un document par exclusion{ _id: "<structureId>:<userId>", userId, userName, structureId, blockedUntil (epoch ms), reason, createdBy, createdByName, createdAt }. - Backend conversation : util
StudentMessagingExclusions(cache rafraîchi,isExcluded(userId, now)) +StudentMessagingExclusionsController. L'envoi est refusé dansConversationController#send(403 conversation.error.messaging.excluded) et le workerScheduledMessageSenderretient les messages programmés d'un élève exclu. - Backend chat-nats : util miroir
StudentMessagingExclusions(même collection, lecture seule) ; blocage dansChatWebSocketHandler(trame{event:error, code:"messaging-excluded"}). - API (routes
AUTHENTICATED+ contrôle manuel) :GET|POST /conversation/messaging-exclusions/:structureId,DELETE /conversation/messaging-exclusions/:structureId/:userId,GET /conversation/messaging-exclusions(statut/bandeau).
Coupure de communication ciblée (justice)
- Graphe : relation Neo4j bidirectionnelle
(:User)-[:BLOCKED_COMMUNICATION {reason, createdBy, structureId, createdAt}]-(:User). - Backend communication (
DefaultCommunicationService) : la clauseAND NOT (n)-[:BLOCKED_COMMUNICATION]-(m)est ajoutée aux requêtes de visibilité (visibleUsersForShare,visibleUsers) etverify()renvoiecanCommunicate=falsepour une paire bloquée. Les deux personnes disparaissent mutuellement des destinataires (l'envoi est alors refusé parVisiblesFilter). - API (routes
AUTHENTICATED+ contrôle manuel) :GET|POST /communication/block/:structureId,DELETE /communication/block/:structureId/:userA/:userB.
Sécurité & délégation
Les contrôleurs autorisent SUPER_ADMIN, l'ADML de la structure, ou un personnel possédant
l'action workflow communication.restriction.manage (déléguée par le chef via les rôles
d'application). Côté dashboard, l'accès est ouvert par les sujets CASL messaging-exclusion /
communication-block (super-admin + ADML), et /api/me expose canManageCommunicationRestrictions
pour les personnels délégués.
Horaires d'utilisation : le mécanisme partagé
Les horaires ne valaient que pour les deux messageries ; ils portent désormais la liste des espaces auxquels ils s'appliquent.
- Stockage : collection Mongo
messaging.hours, inchangée — un document_id: "global"pour le défaut de plate-forme, un document_id: <structureId>par surcharge{ enabled, days: [1..7], start: "HH:mm", end: "HH:mm", scopes: [...], updatedAt, updatedBy }. Le nom de la collection et les chemins/conversation/messaging-hours*sont conservés : les renommer perdrait les horaires déjà enregistrés, pour un gain cosmétique. - Compatibilité ascendante par le défaut : un document sans champ
scopesne vaut que pourmessaging. C'est ce qui rend la montée de version sans effet sur l'existant — un horaire ne s'étend au blog ou au forum que si la case est cochée. - Lecture :
org.entcore.common.utils.SpaceOpeningHours(entcore common) — cache rafraîchi périodiquement,isWriteAllowed(scope, profile, structures). Le chemin d'écriture d'un message ou d'un billet ne doit pas dépendre d'un aller-retour Mongo.init()est idempotent : plusieurs modules du même processus l'appellent. - Application :
org.entcore.common.utils.OpeningHoursGuard#ifWriteAllowed(eb, request, scope, handler), à poser à l'entrée d'une route d'écriture. Refus en 403opening.hours.closedavec l'horaire applicable, de quoi afficher « fermé jusqu'à telle heure » plutôt qu'une erreur muette. La lecture n'est jamais gardée. - Administration : le module
conversationreste la source d'administration (MessagingHoursController) ; sa classeMessagingHoursn'est plus qu'une façade qui délègue àSpaceOpeningHoursavec la portéemessaging, signatures inchangées.chat-natsgarde sa propre copie de lecture et n'a rien à changer : son comportement est le défaut.
Deux règles invariantes d'un espace à l'autre : seuls les élèves sont restreints, et une personne rattachée à plusieurs établissements est autorisée dès qu'au moins un est ouvert — on ne pénalise personne pour un rattachement qu'elle n'a pas choisi.
Conformité
Évaluation au référentiel Open ENT NG (module conversation).
| Maillon de la chaîne qualité | Référence |
|---|---|
| 🎯 Fonctionnalités attendues | fiche fonctionnelle |
| 🧪 Tests réalisés | couverture e2e |
| ✅ Tests de conformité | tableau de conformité |