From 6f6291c2da6660aac0c31af0941a46d4e88c9a71 Mon Sep 17 00:00:00 2001 From: Ahmed Khalid Date: Wed, 1 Jul 2026 13:36:32 +0500 Subject: [PATCH] fix: seed users and refresh stats for all courses with threads The previous version returned early for courses whose topics were already correctly linked ("healthy"), so it never seeded ForumUser records or recomputed stats for them. Those courses were left with an empty Learners tab (and could still 404 on the stats endpoint if any stat-bearing user lacked a ForumUser). Only courses that happened to have orphaned topics got the user seeding and stats recompute. Drop the early return so that every course with threads seeds ForumUser records for its enrolled users and recomputes per-course stats, regardless of whether any topics needed reconnecting. Courses with no threads still return early. Report status as "stats-refreshed" (or "would-refresh-stats" in dry-run) when no topic changes were needed. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../reconnect_legacy_discussion_threads.py | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lms/djangoapps/discussion/management/commands/reconnect_legacy_discussion_threads.py b/lms/djangoapps/discussion/management/commands/reconnect_legacy_discussion_threads.py index 108bf77dece1..2fe32e11f30f 100644 --- a/lms/djangoapps/discussion/management/commands/reconnect_legacy_discussion_threads.py +++ b/lms/djangoapps/discussion/management/commands/reconnect_legacy_discussion_threads.py @@ -33,10 +33,14 @@ or a commentable whose XBlock no longer exists) is registered as a course-level topic so the threads remain reachable, and is reported rather than clobbered. -It then recomputes per-course user stats so the "Learners" tab populates. It performs -only Django-model writes (``DiscussionsConfiguration`` / ``DiscussionTopicLink``) plus -the stats recompute -- no modulestore/content writes and no forum-store writes -- so -it is reversible. +For **every** course that has threads -- whether or not any topics needed reconnecting +-- it also seeds ``ForumUser`` records for enrolled users and recomputes per-course user +stats, so the "Learners" tab populates. (The Mongo->MySQL migration brings threads but +not ``ForumUser`` records, and the stats read does ``ForumUser.objects.get()`` per +stat-bearing user, so a missing record otherwise makes the endpoint fail.) It performs +only Django-model writes (``DiscussionsConfiguration`` / ``DiscussionTopicLink`` / +``ForumUser``) plus the stats recompute -- no modulestore/content writes and no +forum thread/comment writes -- so it is reversible. Invoke with (dry-run by default):: @@ -172,8 +176,6 @@ def _process_course(self, course_key): links = list(DiscussionTopicLink.objects.filter(context_key=course_key, provider_id=PROVIDER)) linked_external_ids = {link.external_id for link in links} orphans = active - linked_external_ids - if not orphans: - return {"course": str(course_key), "status": "healthy", "threads": len(active)} xmap = self._build_xblock_map(course_key) links_by_unit = {link.usage_key: link for link in links if link.usage_key} @@ -217,7 +219,8 @@ def _process_course(self, course_key): if not self.apply: self.stdout.write(" (dry-run: no changes written)") - return {"course": str(course_key), "status": "would-fix", "actions": len(plan)} + status = "would-fix" if plan else "would-refresh-stats" + return {"course": str(course_key), "status": status, "actions": len(plan)} if need_graded and not config.enable_graded_units: config.enable_graded_units = True @@ -251,7 +254,8 @@ def _process_course(self, course_key): seeded = self._seed_forum_users(course_key) update_course_users_stats(course_key) self.stdout.write(f" -> applied; seeded {seeded} forum users; user stats recomputed") - return {"course": str(course_key), "status": "fixed", "actions": len(plan), "seeded_users": seeded} + status = "fixed" if plan else "stats-refreshed" + return {"course": str(course_key), "status": status, "actions": len(plan), "seeded_users": seeded} def _seed_forum_users(self, course_key): """