feat: add data report for enrolled & inactive user

Add new data report for learners who are enrolled in a course and have not activated their account
This commit is contained in:
Muhammad Faraz Maqsood
2025-07-16 14:09:38 +05:00
committed by Muhammad Faraz Maqsood
parent 25f9397683
commit 5879a52b72
12 changed files with 185 additions and 4 deletions

View File

@@ -32,6 +32,7 @@ from lms.djangoapps.instructor_task.data import InstructorTaskTypes
from lms.djangoapps.instructor_task.models import InstructorTask, InstructorTaskSchedule, SCHEDULED
from lms.djangoapps.instructor_task.tasks import (
calculate_grades_csv,
calculate_inactive_enrolled_students_info_csv,
calculate_may_enroll_csv,
calculate_problem_grade_report,
calculate_problem_responses_csv,
@@ -409,6 +410,21 @@ def submit_calculate_may_enroll_csv(request, course_key, features):
return submit_task(request, task_type, task_class, course_key, task_input, task_key)
def submit_calculate_inactive_enrolled_students_csv(request, course_key, features):
"""
Submits a task to generate a CSV file containing information about
enrolled students in a course who have not activated their account yet.
Raises AlreadyRunningError if said file is already being updated.
"""
task_type = InstructorTaskTypes.INACTIVE_ENROLLED_STUDENTS_INFO_CSV
task_class = calculate_inactive_enrolled_students_info_csv
task_input = {'features': features}
task_key = ""
return submit_task(request, task_type, task_class, course_key, task_input, task_key)
def submit_course_survey_report(request, course_key):
"""
Submits a task to generate a HTML File containing the executive summary report.

View File

@@ -114,7 +114,7 @@ def generate_already_running_error_message(task_type):
'proctored_exam_results_report': _('proctored exam results'),
'export_ora2_data': _('ORA data'),
'grade_course': _('grade'),
'inactive_enrolled_students_info_csv': _('inactive enrollment')
}
if report_types.get(task_type):

View File

@@ -24,6 +24,7 @@ class InstructorTaskTypes(str, Enum):
GRADE_COURSE = "grade_course"
GRADE_PROBLEMS = "grade_problems"
MAY_ENROLL_INFO_CSV = "may_enroll_info_csv"
INACTIVE_ENROLLED_STUDENTS_INFO_CSV = "inactive_enrolled_students_info_csv"
OVERRIDE_PROBLEM_SCORE = "override_problem_score"
PROBLEM_RESPONSES_CSV = "problem_responses_csv"
PROCTORED_EXAM_RESULTS_REPORT = "proctored_exam_results_report"

View File

@@ -30,7 +30,11 @@ from edx_django_utils.monitoring import set_code_owner_attribute
from lms.djangoapps.bulk_email.tasks import perform_delegate_email_batches
from lms.djangoapps.instructor_task.tasks_base import BaseInstructorTask
from lms.djangoapps.instructor_task.tasks_helper.certs import generate_students_certificates
from lms.djangoapps.instructor_task.tasks_helper.enrollments import upload_may_enroll_csv, upload_students_csv
from lms.djangoapps.instructor_task.tasks_helper.enrollments import (
upload_inactive_enrolled_students_info_csv,
upload_may_enroll_csv,
upload_students_csv
)
from lms.djangoapps.instructor_task.tasks_helper.grades import CourseGradeReport, ProblemGradeReport, ProblemResponses
from lms.djangoapps.instructor_task.tasks_helper.misc import (
cohort_students_and_upload,
@@ -267,6 +271,20 @@ def calculate_may_enroll_csv(entry_id, xblock_instance_args):
return run_main_task(entry_id, task_fn, action_name)
@shared_task(base=BaseInstructorTask)
@set_code_owner_attribute
def calculate_inactive_enrolled_students_info_csv(entry_id, xblock_instance_args):
"""
Compute information about invited students who have not enrolled
in a given course yet and upload the CSV to an S3 bucket for
download.
"""
# Translators: This is a past-tense verb that is inserted into task progress messages as {action}.
action_name = gettext_noop('generated')
task_fn = partial(upload_inactive_enrolled_students_info_csv, xblock_instance_args)
return run_main_task(entry_id, task_fn, action_name)
@shared_task(base=BaseInstructorTask)
@set_code_owner_attribute
def generate_certificates(entry_id, xblock_instance_args):

View File

@@ -7,7 +7,11 @@ import logging
from datetime import datetime
from time import time
from pytz import UTC
from lms.djangoapps.instructor_analytics.basic import enrolled_students_features, list_may_enroll
from lms.djangoapps.instructor_analytics.basic import (
enrolled_students_features,
list_inactive_enrolled_students,
list_may_enroll,
)
from lms.djangoapps.instructor_analytics.csvs import format_dictlist
from common.djangoapps.student.models import CourseEnrollment # lint-amnesty, pylint: disable=unused-import
@@ -50,6 +54,38 @@ def upload_may_enroll_csv(_xblock_instance_args, _entry_id, course_id, task_inpu
return task_progress.update_task_state(extra_meta=current_step)
def upload_inactive_enrolled_students_info_csv(_xblock_instance_args, _entry_id, course_id, task_input, action_name):
"""
For a given `course_id`, generate a CSV file containing
information about students who are enrolled in a course but have not
activated their account yet, and store using a `ReportStore`.
"""
start_time = time()
start_date = datetime.now(UTC)
num_reports = 1
task_progress = TaskProgress(action_name, num_reports, start_time)
current_step = {'step': 'Calculating info about students who are enrolled and their account is inactive'}
task_progress.update_task_state(extra_meta=current_step)
# Compute result table and format it
query_features = task_input.get('features')
student_data = list_inactive_enrolled_students(course_id, query_features)
header, rows = format_dictlist(student_data, query_features)
task_progress.attempted = task_progress.succeeded = len(rows)
task_progress.skipped = task_progress.total - task_progress.attempted
rows.insert(0, header)
current_step = {'step': 'Uploading CSV'}
task_progress.update_task_state(extra_meta=current_step)
# Perform the upload
upload_csv_to_report_store(rows, 'inactive_enrolled_students_info', course_id, start_date)
return task_progress.update_task_state(extra_meta=current_step)
def upload_students_csv(_xblock_instance_args, _entry_id, course_id, task_input, action_name):
"""
For a given `course_id`, generate a CSV file containing profile