Les modifications de la période de grâce contournent la vérification des médias `skip_review_media_groups`

Résumé

La vérification « review media » (paramètre de site skip_review_media_groups) n’est appliquée qu’au moment de la création du message, dans NewPostManager. Les modifications passent par PostRevisor, qui n’exécute jamais la vérification des médias. Un utilisateur peut donc publier du texte brut en premier (passant la revue), puis ajouter des images via une modification — et le message n’entre jamais dans la file d’attente de modération.

Pire encore, si la modification intervient dans la editing_grace_period (5 minutes par défaut) et que la différence est inférieure à editing_grace_period_max_diff (100 caractères par défaut — une seule ligne Markdown d’image téléchargée fait environ 40 à 60 caractères), la modification ne crée aucune révision et aucune icône de crayon, rendant cette contournement complètement invisible dans l’interface.

Étapes pour reproduire

  1. Configurez skip_review_media_groups de sorte que les utilisateurs ordinaires (par exemple TL0/TL1) ne soient pas exemptés — les messages contenant des médias doivent nécessiter une approbation.
  2. En tant qu’utilisateur ordinaire, créez un message contenant uniquement du texte. Il est approuvé/publié normalement (pas de média → pas de modération).
  3. Dans la période de grâce, modifiez le message et insérez une image téléchargée.

Comportement attendu

Le message (contenant désormais des médias) devrait être envoyé à la file d’attente de modération, ou du moins la modification devrait être soumise à la même vérification des médias que lors de la création du message.

Comportement réel

  • Le message est publié avec l’image et n’entre jamais dans la file d’attente de modération.
  • Aucun enregistrement de révision n’est créé, aucun indicateur de modification n’est affiché.

Preuves (instance de production)

p.version                                   # => 1
PostRevision.where(post_id: p.id).count     # => 0
p.created_at                                # => 2026-07-30 07:33:28 UTC
p.updated_at                                # => 2026-07-30 07:34:00 UTC
UploadReference.where(target: p).pluck(:created_at)
                                            # => [2026-07-30 07:34:01 UTC]

Message texte seul créé à 07:33:28, image ajoutée par une modification environ 32 secondes plus tard — aucun historique de modification visible, aucune modération.

Code pertinent

  • lib/new_post_manager.rb — post_needs_approval? renvoie :contains_media via contains_embedded_media?, mais cela ne s’exécute que pour les nouveaux messages.
  • app/models/post_analyzer.rb#embedded_media_count — la logique de comptage des médias.
  • PostRevisor — aucune vérification des médias équivalente lors de la modification.

Correction suggérée

Exécuter la vérification contains_media dans PostRevisor également (lorsque la modification introduit des médias et que l’éditeur n’est pas dans skip_review_media_groups / n’est pas un membre du personnel), en mettant en file d’attente un ReviewablePost pour le message modifié.

2 « J'aime »

Merci pour le rapport @Editor0732 :+1: Sera corrigé par

J’ai essayé de déployer cette PR et j’ai remarqué une asymétrie dans les mécanismes de modération des médias entre les nouvelles publications et les éditions, et je voudrais soulever cette question :

Nouvelles publications avec médias — ReviewableQueuedPost (examen avant publication)

  • La publication n’est pas créée du tout ; le contenu reste dans la charge utile à examiner jusqu’à ce qu’il soit approuvé
  • L’auteur voit la section “en attente d’approbation” (pending_posts) sur la page du sujet
  • La publication ne devient visible pour tous que après approbation par un modérateur (perform_approve_postPostCreator)
  • En cas de rejet, le contenu est supprimé — il n’a jamais été public

Éditions qui ajoutent des médias — ReviewablePost (publication d’abord, examen après)

  • L’édition prend effet immédiatement ; la nouvelle version (y compris l’image) est instantanément visible pour tous
  • Il n’y a aucun avis “en cours d’examen” pour l’auteur — et pour les éditions pendant la période de grâce, il n’y a même pas de révision, donc le contenu original ne laisse aucune trace dans l’interface
  • En cas de rejet, la publication est supprimée (perform_reject_and_delete), récupérable via la révision précédente

La préoccupation

Avec l’approche actuelle, l’image problématique devient publiquement visible avant qu’aucun modérateur ne puisse agir, potentiellement pendant une longue période selon le délai d’examen. Cela semble affaiblir tout l’intérêt de skip_review_media_groups — la description du paramètre indique que les publications contenant des médias sont “envoyées au personnel pour examen”, ce qui laisse entendre qu’elles ne devraient pas être publiques en attendant.

Amélioration possible

  1. Mettre en file d’attente le contenu modifié au lieu de l’appliquer. (Je pense que c’est mieux) Lorsqu’une édition introduit de nouveaux médias, garder la publication inchangée, notifier l’auteur que la nouvelle édition est en attente d’examen, et n’appliquer le contenu modifié à la publication qu’une fois qu’un modérateur l’a approuvé — le supprimer en cas de rejet. Cela reproduit le comportement des nouvelles publications aussi étroitement que possible. (D’un point de vue implémentation, cela nécessiterait une variante examenable dont l’approbation effectuerait une révision sur la publication existante plutôt que d’en créer une nouvelle.)

  2. Masquer la publication lorsqu’une édition introduit de nouveaux médias, de sorte que seul l’auteur la voie avec un avis “en attente d’approbation”, et utiliser l’action existante perform_approve_and_unhide lors de l’approbation — les actions ReviewablePost prennent déjà en charge cela.

Merci d’avoir testé cela. Je suis d’accord, tout le système de révision n’est pas correctement conçu pour gérer les « révisions/modifications en attente » :thinking:

Je crains que ce soit une tâche beaucoup plus complexe qui nécessitera plus de temps pour être planifiée et mise en œuvre.