Le bouton d'approbation sur le profil de l'utilisateur ne fonctionne pas

Suite à la discussion de Notification indique des utilisateurs X à approuver, mais aucun n’est trouvé :

J’ai récemment réactivé require_approval sur mon forum. Immédiatement après, j’ai reçu des notifications concernant un utilisateur en attente d’approbation, mais lorsque j’ai cliqué sur le lien du message, aucun utilisateur n’apparaissait dans la file d’examen. Depuis, je reçois cette notification tous les 7 jours. J’ai donc utilisé l’explorateur de données pour trouver l’utilisateur qui n’avait pas été approuvé mais qui n’apparaît pas dans la file d’examen.

étapes plus détaillées citées de l'autre sujet

Donc, lorsque je consulte la page d’administration des utilisateurs, le bouton d’approbation attendu est bien présent. Le problème est qu’il ne fonctionne pas. Il n’y a aucun retour visuel, comme une fenêtre modale affichant une erreur. Cependant, il y en a une dans la console de mon navigateur :

Erreur dans la console du navigateur
ajax.js:233  PUT https://my-forum.discourse.group/admin/users/123/approve 500 (Internal Server Error)
send @ jquery.js:9940
ajax @ jquery.js:9521
performAjax @ ajax.js:233
(anonymous) @ ajax.js:246
approve @ admin-user.js:220
approve @ index.js:224
(anonymous) @ d-button.gjs:206
invoke @ index.js:264
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
end @ index.js:565
_runExpiredTimers @ index.js:869
setTimeout
setTimeout @ index.js:39
_installTimerTimeout @ index.js:912
_reinstallTimerTimeout @ index.js:896
_later @ index.js:829
later @ index.js:652
next @ index.js:562
_triggerAction @ d-button.gjs:203
click @ d-button.gjs:161


/admin/users/123/anon84265489:1 Uncaught (in promise) {jqXHR: {…}, textStatus: 'error', errorThrown: ''}errorThrown: ""jqXHR: abort: ƒ (e)always: ƒ ()catch: ƒ (e)done: ƒ ()fail: ƒ ()getAllResponseHeaders: ƒ ()getResponseHeader: ƒ (e)jqTextStatus: "error"overrideMimeType: ƒ (e)pipe: ƒ ()progress: ƒ ()promise: ƒ (e)readyState: 4requestedUrl: "/admin/users/123/approve"responseText: "<!DOCTYPE html>\n<html>\n<head>\n  <title>Oups - Erreur 500</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n</head>\n<body>\n    <h1>Oups</h1>\n    <p>Le logiciel alimentant ce forum de discussion a rencontré un problème inattendu. Nous nous excusons pour la gêne occasionnée.</p>\n    <p>Des informations détaillées sur l'erreur ont été enregistrées et une notification automatique a été générée. Nous allons l'examiner.</p>\n    <p>Aucune action supplémentaire n'est nécessaire. Cependant, si le problème persiste, vous pouvez fournir des détails supplémentaires, y compris les étapes pour reproduire l'erreur, en publiant un sujet de discussion dans la catégorie de retour d'information du site.</p>\n</body>\n</html>\n"setRequestHeader: ƒ (e,t)state: ƒ ()status: 500statusCode: ƒ (e)statusText: "error"then: ƒ (e,i,n)[[Prototype]]: ObjecttextStatus: "error"[[Prototype]]: Object
Promise.then
approve @ admin-user.js:222
approve @ index.js:224
(anonymous) @ d-button.gjs:206
invoke @ index.js:264
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
end @ index.js:565
_runExpiredTimers @ index.js:869
setTimeout
setTimeout @ index.js:39
_installTimerTimeout @ index.js:912
_reinstallTimerTimeout @ index.js:896
_later @ index.js:829
later @ index.js:652
next @ index.js:562
_triggerAction @ d-button.gjs:203
click @ d-button.gjs:161

Ensuite, j’ai vérifié /logs :

Erreur dans /logs
Message (14 copies signalées)

Reviewable::InvalidAction (Impossible d'effectuer `approve_user` sur ReviewableUser)
app/models/reviewable.rb:860:in 'Reviewable#validate_action!'
app/models/reviewable.rb:360:in 'Reviewable#perform'
app/controllers/admin/users_controller.rb:306:in 'Admin::UsersController#approve'
app/controllers/application_controller.rb:452:in 'block in ApplicationController#with_resolved_locale'
app/controllers/application_controller.rb:452:in 'ApplicationController#with_resolved_locale'
app/controllers/application_controller.rb:1101:in 'ApplicationController#ensure_dont_cache_page'
lib/middleware/omniauth_bypass_middleware.rb:35:in 'Middleware::OmniauthBypassMiddleware#call'
lib/middleware/crawler_hooks.rb:13:in 'Middleware::CrawlerHooks#call'
lib/content_security_policy/middleware.rb:12:in 'ContentSecurityPolicy::Middleware#call'
lib/middleware/anonymous_cache.rb:417:in 'Middleware::AnonymousCache#call'
lib/middleware/csp_script_nonce_injector.rb:12:in 'Middleware::CspScriptNonceInjector#call'
lib/middleware/track_view_session_id_injector.rb:12:in 'Middleware::TrackViewSessionIdInjector#call'
config/initializers/008-rack-cors.rb:26:in 'Discourse::Cors#call'
lib/middleware/default_headers.rb:13:in 'Middleware::DefaultHeaders#call'
config/initializers/100-quiet_logger.rb:20:in 'DiscourseRackQuietAssetsLogger#call'
config/initializers/100-silence_logger.rb:29:in 'SilenceLogger#call'
lib/middleware/enforce_hostname.rb:23:in 'Middleware::EnforceHostname#call'
lib/middleware/request_tracker.rb:372:in 'Middleware::RequestTracker#call'
lib/middleware/overload_protections.rb:18:in 'Middleware::OverloadProtections#call'
lib/middleware/processing_request.rb:14:in 'Middleware::ProcessingRequest#call'


Backtrace

app/models/reviewable.rb:860:in 'Reviewable#validate_action!'
app/models/reviewable.rb:360:in 'Reviewable#perform'
app/controllers/admin/users_controller.rb:306:in 'Admin::UsersController#approve'
actionpack (8.0.5) lib/action_controller/metal/basic_implicit_render.rb:8:in 'ActionController::BasicImplicitRender#send_action'
actionpack (8.0.5) lib/abstract_controller/base.rb:215:in 'AbstractController::Base#process_action'
actionpack (8.0.5) lib/action_controller/metal/rendering.rb:193:in 'ActionController::Rendering#process_action'
actionpack (8.0.5) lib/abstract_controller/callbacks.rb:261:in 'block in AbstractController::Callbacks#process_action'
activesupport (8.0.5) lib/active_support/callbacks.rb:120:in 'block in ActiveSupport::Callbacks#run_callbacks'
app/controllers/application_controller.rb:452:in 'block in ApplicationController#with_resolved_locale'
i18n (1.14.8) lib/i18n.rb:354:in 'I18n::Base#with_locale'
app/controllers/application_controller.rb:452:in 'ApplicationController#with_resolved_locale'
activesupport (8.0.5) lib/active_support/callbacks.rb:129:in 'block in ActiveSupport::Callbacks#run_callbacks'
app/controllers/application_controller.rb:1101:in 'ApplicationController#ensure_dont_cache_page'
activesupport (8.0.5) lib/active_support/callbacks.rb:129:in 'block in ActiveSupport::Callbacks#run_callbacks'
activesupport (8.0.5) lib/active_support/callbacks.rb:140:in 'ActiveSupport::Callbacks#run_callbacks'
actionpack (8.0.5) lib/abstract_controller/callbacks.rb:260:in 'AbstractController::Callbacks#process_action'
actionpack (8.0.5) lib/action_controller/metal/rescue.rb:27:in 'ActionController::Rescue#process_action'
actionpack (8.0.5) lib/action_controller/metal/instrumentation.rb:76:in 'block in ActionController::Instrumentation#process_action'
activesupport (8.0.5) lib/active_support/notifications.rb:210:in 'block in ActiveSupport::Notifications.instrument'
activesupport (8.0.5) lib/active_support/notifications/instrumenter.rb:58:in 'ActiveSupport::Notifications::Instrumenter#instrument'
activesupport (8.0.5) lib/active_support/notifications.rb:210:in 'ActiveSupport::Notifications.instrument'
actionpack (8.0.5) lib/action_controller/metal/instrumentation.rb:75:in 'ActionController::Instrumentation#process_action'
actionpack (8.0.5) lib/action_controller/metal/params_wrapper.rb:259:in 'ActionController::ParamsWrapper#process_action'
activerecord (8.0.5) lib/active_record/railties/controller_runtime.rb:39:in 'ActiveRecord::Railties::ControllerRuntime#process_action'
actionpack (8.0.5) lib/abstract_controller/base.rb:152:in 'AbstractController::Base#process'
actionview (8.0.5) lib/action_view/rendering.rb:40:in 'ActionView::Rendering#process'
rack-mini-profiler (4.0.1) lib/mini_profiler/profiling_methods.rb:90:in 'block in ActionController::Base#profile_method'
actionpack (8.0.5) lib/action_controller/metal.rb:252:in 'ActionController::Metal#dispatch'
actionpack (8.0.5) lib/action_controller/metal.rb:335:in 'ActionController::Metal.dispatch'
actionpack (8.0.5) lib/action_dispatch/routing/route_set.rb:67:in 'ActionDispatch::Routing::RouteSet::Dispatcher#dispatch'
actionpack (8.0.5) lib/action_dispatch/routing/route_set.rb:50:in 'ActionDispatch::Routing::RouteSet::Dispatcher#serve'
actionpack (8.0.5) lib/action_dispatch/routing/mapper.rb:32:in 'block in <class:Constraints>'
actionpack (8.0.5) lib/action_dispatch/routing/mapper.rb:62:in 'ActionDispatch::Routing::Mapper::Constraints#serve'
actionpack (8.0.5) lib/action_dispatch/journey/router.rb:53:in 'block in ActionDispatch::Journey::Router#serve'
actionpack (8.0.5) lib/action_dispatch/journey/router.rb:133:in 'block in ActionDispatch::Journey::Router#find_routes'
actionpack (8.0.5) lib/action_dispatch/journey/router.rb:126:in 'Array#each'
actionpack (8.0.5) lib/action_dispatch/journey/router.rb:126:in 'ActionDispatch::Journey::Router#find_routes'
actionpack (8.0.5) lib/action_dispatch/journey/router.rb:34:in 'ActionDispatch::Journey::Router#serve'
actionpack (8.0.5) lib/action_dispatch/routing/route_set.rb:908:in 'ActionDispatch::Routing::RouteSet#call'
lib/middleware/omniauth_bypass_middleware.rb:35:in 'Middleware::OmniauthBypassMiddleware#call'
lib/middleware/crawler_hooks.rb:13:in 'Middleware::CrawlerHooks#call'
rack (2.2.23) lib/rack/tempfile_reaper.rb:15:in 'Rack::TempfileReaper#call'
rack (2.2.23) lib/rack/conditional_get.rb:40:in 'Rack::ConditionalGet#call'
rack (2.2.23) lib/rack/head.rb:12:in 'Rack::Head#call'
actionpack (8.0.5) lib/action_dispatch/http/permissions_policy.rb:38:in 'ActionDispatch::PermissionsPolicy::Middleware#call'
lib/content_security_policy/middleware.rb:12:in 'ContentSecurityPolicy::Middleware#call'
lib/middleware/anonymous_cache.rb:417:in 'Middleware::AnonymousCache#call'
lib/middleware/csp_script_nonce_injector.rb:12:in 'Middleware::CspScriptNonceInjector#call'
lib/middleware/track_view_session_id_injector.rb:12:in 'Middleware::TrackViewSessionIdInjector#call'
config/initializers/008-rack-cors.rb:26:in 'Discourse::Cors#call'
rack (2.2.23) lib/rack/session/abstract/id.rb:266:in 'Rack::Session::Abstract::Persisted#context'
rack (2.2.23) lib/rack/session/abstract/id.rb:260:in 'Rack::Session::Abstract::Persisted#call'
actionpack (8.0.5) lib/action_dispatch/middleware/cookies.rb:706:in 'ActionDispatch::Cookies#call'
actionpack (8.0.5) lib/action_dispatch/middleware/callbacks.rb:31:in 'block in ActionDispatch::Callbacks#call'
activesupport (8.0.5) lib/active_support/callbacks.rb:100:in 'ActiveSupport::Callbacks#run_callbacks'
actionpack (8.0.5) lib/action_dispatch/middleware/callbacks.rb:30:in 'ActionDispatch::Callbacks#call'
actionpack (8.0.5) lib/action_dispatch/middleware/debug_exceptions.rb:31:in 'ActionDispatch::DebugExceptions#call'
actionpack (8.0.5) lib/action_dispatch/middleware/show_exceptions.rb:32:in 'ActionDispatch::ShowExceptions#call'
logster (2.21.0) lib/logster/middleware/reporter.rb:40:in 'Logster::Middleware::Reporter#call'
lib/middleware/default_headers.rb:13:in 'Middleware::DefaultHeaders#call'
lograge (0.14.0) lib/lograge/rails_ext/rack/logger.rb:18:in 'Rails::Rack::Logger#call_app'
railties (8.0.5) lib/rails/rack/logger.rb:29:in 'Rails::Rack::Logger#call'
config/initializers/100-quiet_logger.rb:20:in 'DiscourseRackQuietAssetsLogger#call'
config/initializers/100-silence_logger.rb:29:in 'SilenceLogger#call'
actionpack (8.0.5) lib/action_dispatch/middleware/request_id.rb:34:in 'ActionDispatch::RequestId#call'
lib/middleware/enforce_hostname.rb:23:in 'Middleware::EnforceHostname#call'
rack (2.2.23) lib/rack/method_override.rb:24:in 'Rack::MethodOverride#call'
rack (2.2.23) lib/rack/sendfile.rb:127:in 'Rack::Sendfile#call'
plugins/discourse-prometheus/lib/middleware/metrics.rb:14:in 'DiscoursePrometheus::Middleware::Metrics#call'
rack-mini-profiler (4.0.1) lib/mini_profiler.rb:191:in 'Rack::MiniProfiler#call'
message_bus (4.5.2) lib/message_bus/rack/middleware.rb:60:in 'MessageBus::Rack::Middleware#call'
lib/middleware/request_tracker.rb:372:in 'Middleware::RequestTracker#call'
actionpack (8.0.5) lib/action_dispatch/middleware/remote_ip.rb:96:in 'ActionDispatch::RemoteIp#call'
lib/middleware/overload_protections.rb:18:in 'Middleware::OverloadProtections#call'
lib/middleware/processing_request.rb:14:in 'Middleware::ProcessingRequest#call'
rails_failover (2.3.0) lib/rails_failover/active_record/middleware.rb:67:in 'block in RailsFailover::ActiveRecord::Middleware#call'
activerecord (8.0.5) lib/active_record/connection_handling.rb:401:in 'ActiveRecord::ConnectionHandling#with_role_and_shard'
activerecord (8.0.5) lib/active_record/connection_handling.rb:149:in 'ActiveRecord::ConnectionHandling#connected_to'
rails_failover (2.3.0) lib/rails_failover/active_record/middleware.rb:64:in 'RailsFailover::ActiveRecord::Middleware#call'
rails_multisite (7.0.0) lib/rails_multisite/middleware.rb:26:in 'RailsMultisite::Middleware#call'
railties (8.0.5) lib/rails/engine.rb:535:in 'Rails::Engine#call'
railties (8.0.5) lib/rails/railtie.rb:226:in 'Kernel#public_send'
railties (8.0

Env

HTTP HOSTS: my-forum.discourse.group

Je ne suis pas sûr de ce qui cause cela. Il existe d’autres utilisateurs anonymisés qui ont été approuvés sans problème lorsque j’ai activé le paramètre.

2 « J'aime »

C’est un « moi aussi » de ma part, aussi.

(Édition : J’ai découvert exactement un utilisateur dans cet état, actif il y a quelques semaines, non anonymisé)

2 « J'aime »

Votre « moi aussi » est très utile pour confirmer que le fait que mon utilisateur ait été anonymisé n’est pas la cause de ce bogue.

L’explorateur de données indique que l’utilisateur est révisable par un modérateur

user_id id type target_id target_type reviewable_by_moderator
anon84265489 264 ReviewableUser 123 User true
requête
SELECT 
    u.id AS user_id,
    r.id,
    r.type,
    r.target_id,
    r.target_type,
    r.reviewable_by_moderator
FROM reviewables r
JOIN users u
    ON r.target_id = u.id
WHERE u.approved = false
  AND u.active = true
1 « J'aime »

Je ne comprends pas pourquoi cela dysfonctionne, mais je peux au moins identifier certains extraits de code qui concluent que cette action ne peut pas être effectuée. Cependant, je ne vois pas pourquoi ils en arrivent à cette conclusion. Je suppose que la logique se trouve à la ligne 859 dans reviewable.rb (discourse/app/models/reviewable.rb at main · discourse/discourse · GitHub).

approve() se trouve à la ligne 306 dans users_controller.rb

perform() se trouve à la ligne 360 dans reviewable.rb

validate_action!() se trouve à la ligne 860 dans reviewable.rb et lève l’exception

Je pense que le problème vient du fait que l’utilisateur a déjà été examiné. Je ne suis pas sûr qu’il soit possible de réexaminer le même utilisateur. Jusqu’à présent, je n’ai pas réussi à reproduire ce problème.

Je n’ai toujours pas réussi à reproduire ce problème. Cependant, j’ai découvert que l’utilisateur qui n’apparaît pas dans la file d’attente des examens avait été signalé comme suspect_user après son inscription en décembre. À cette époque, must_approve_users était désactivé sur mon forum. J’ai donc agi à son sujet à ce moment-là. Je ne suis pas sûr que disagreed signifie que j’ai choisi de conserver l’utilisateur. Mais lorsque j’ai tenté de reproduire la situation maintenant, la seule autre option était de supprimer l’utilisateur. Je ne sais pas comment status = 2 s’est produit.
Lorsque j’ai activé must_approve_users il y a quelques semaines, l’utilisateur n’a pas été automatiquement approuvé car il existait un élément examenable avec l’user_id comme target_id. Cela a du sens.

Mais je n’ai toujours aucune idée de comment j’ai fini avec un utilisateur que je n’ai ni approuvé, ni supprimé alors qu’il avait été signalé.

reviewable status status reason context created_at
264 disagreed 2 suspect_user NULL 2025-12-18T14:16:28.322Z
requête
SELECT
    rs.reviewable_id,
    CASE
      WHEN rs.status = 0 THEN 'en attente'
      WHEN rs.status = 1 THEN 'accordé'
      WHEN rs.status = 2 THEN 'en désaccord'
      WHEN rs.status = 3 THEN 'ignoré'
    END as status,
    rs.status as status_id,
    rs.reason,
    rs.context,
    rs.created_at
FROM reviewable_scores rs
JOIN reviewables r
ON rs.reviewable_id = r.id
JOIN users u
ON r.target_id = u.id
WHERE u.approved = false
AND u.active = true
1 « J'aime »

Super — il semble que ce soit aussi mon cas : un utilisateur (dans mon cas, un utilisateur actif et en ligne jusqu’à il y a quelques semaines) qui, dans un passé lointain, avait acquis le statut « suspect_user ».

Je pense que cet utilisateur a probablement découvert qu’il ne pouvait plus utiliser le forum depuis que j’ai activé l’approbation des nouveaux utilisateurs.
Inscrit le 9 avril 2021, dernier message le 16 avril, dernière activité le 16 avril, 1311 vues. Niveau de confiance : membre.
Statistiques : 78 jours visités, 4 heures de temps de lecture, 3 minutes de temps de lecture récent, 83 sujets consultés, 491 messages lus, 6 donnés, 31 reçus, 4 sujets créés, 25 messages créés.

En remontant dans ma file d’examen, je ne vois aucun élément à cette date, ni aucun élément avec ce nom d’utilisateur.

Je vois maintenant que, dans mon cas, nous avons eu un utilisateur spammeur, qui a récupéré l’ID 332, a été signalé et supprimé. Quelques jours plus tard, un nouvel utilisateur est arrivé et a de nouveau récupéré l’ID 332.

Connaissant l’ID de l’utilisateur valide concerné, j’ai exécuté cette requête Data Explorer :

SELECT *
FROM reviewables
WHERE target_id = 332
ORDER BY created_at DESC