tasks.py 7.6 KB
Newer Older
1
"""
2
This file contains tasks that are designed to perform background operations on the
3 4
running state of a course.

Brian Wilson committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
At present, these tasks all operate on StudentModule objects in one way or another,
so they share a visitor architecture.  Each task defines an "update function" that
takes a module_descriptor, a particular StudentModule object, and xmodule_instance_args.

A task may optionally specify a "filter function" that takes a query for StudentModule
objects, and adds additional filter clauses.

A task also passes through "xmodule_instance_args", that are used to provide
information to our code that instantiates xmodule instances.

The task definition then calls the traversal function, passing in the three arguments
above, along with the id value for an InstructorTask object.  The InstructorTask
object contains a 'task_input' row which is a JSON-encoded dict containing
a problem URL and optionally a student.  These are used to set up the initial value
of the query for traversing StudentModule objects.

21
"""
22
from django.conf import settings
23
from django.utils.translation import ugettext_noop
24
from celery import task
25
from functools import partial
26 27 28 29 30 31 32
from instructor_task.tasks_helper import (
    run_main_task,
    BaseInstructorTask,
    perform_module_state_update,
    rescore_problem_module_state,
    reset_attempts_module_state,
    delete_problem_module_state,
33
    upload_grades_csv,
34 35
    upload_students_csv,
    cohort_students_and_upload
36
)
37
from bulk_email.tasks import perform_delegate_email_batches
38 39


40
@task(base=BaseInstructorTask)  # pylint: disable=not-callable
41
def rescore_problem(entry_id, xmodule_instance_args):
42
    """Rescores a problem in a course, for all students or one specific student.
43 44

    `entry_id` is the id value of the InstructorTask entry that corresponds to this task.
45 46 47 48
    The entry contains the `course_id` that identifies the course, as well as the
    `task_input`, which contains task-specific input.

    The task_input should be a dict with the following entries:
49 50

      'problem_url': the full URL to the problem to be rescored.  (required)
51

52 53
      'student': the identifier (username or email) of a particular user whose
          problem submission should be rescored.  If not specified, all problem
54
          submissions for the problem will be rescored.
55 56 57 58

    `xmodule_instance_args` provides information needed by _get_module_instance_for_task()
    to instantiate an xmodule instance.
    """
59 60
    # Translators: This is a past-tense verb that is inserted into task progress messages as {action}.
    action_name = ugettext_noop('rescored')
61
    update_fcn = partial(rescore_problem_module_state, xmodule_instance_args)
62 63

    def filter_fcn(modules_to_update):
64
        """Filter that matches problems which are marked as being done"""
65 66
        return modules_to_update.filter(state__contains='"done": true')

67 68
    visit_fcn = partial(perform_module_state_update, update_fcn, filter_fcn)
    return run_main_task(entry_id, visit_fcn, action_name)
69 70


71
@task(base=BaseInstructorTask)  # pylint: disable=not-callable
72
def reset_problem_attempts(entry_id, xmodule_instance_args):
73
    """Resets problem attempts to zero for a particular problem for all students in a course.
74 75

    `entry_id` is the id value of the InstructorTask entry that corresponds to this task.
76 77 78 79
    The entry contains the `course_id` that identifies the course, as well as the
    `task_input`, which contains task-specific input.

    The task_input should be a dict with the following entries:
80 81 82 83 84 85

      'problem_url': the full URL to the problem to be rescored.  (required)

    `xmodule_instance_args` provides information needed by _get_module_instance_for_task()
    to instantiate an xmodule instance.
    """
86 87
    # Translators: This is a past-tense verb that is inserted into task progress messages as {action}.
    action_name = ugettext_noop('reset')
88 89 90
    update_fcn = partial(reset_attempts_module_state, xmodule_instance_args)
    visit_fcn = partial(perform_module_state_update, update_fcn, None)
    return run_main_task(entry_id, visit_fcn, action_name)
91 92


93
@task(base=BaseInstructorTask)  # pylint: disable=not-callable
94
def delete_problem_state(entry_id, xmodule_instance_args):
95
    """Deletes problem state entirely for all students on a particular problem in a course.
96 97

    `entry_id` is the id value of the InstructorTask entry that corresponds to this task.
98 99 100 101
    The entry contains the `course_id` that identifies the course, as well as the
    `task_input`, which contains task-specific input.

    The task_input should be a dict with the following entries:
102 103 104 105 106 107

      'problem_url': the full URL to the problem to be rescored.  (required)

    `xmodule_instance_args` provides information needed by _get_module_instance_for_task()
    to instantiate an xmodule instance.
    """
108 109
    # Translators: This is a past-tense verb that is inserted into task progress messages as {action}.
    action_name = ugettext_noop('deleted')
110 111 112 113 114
    update_fcn = partial(delete_problem_module_state, xmodule_instance_args)
    visit_fcn = partial(perform_module_state_update, update_fcn, None)
    return run_main_task(entry_id, visit_fcn, action_name)


115
@task(base=BaseInstructorTask)  # pylint: disable=not-callable
116 117
def send_bulk_course_email(entry_id, _xmodule_instance_args):
    """Sends emails to recipients enrolled in a course.
118 119 120 121 122

    `entry_id` is the id value of the InstructorTask entry that corresponds to this task.
    The entry contains the `course_id` that identifies the course, as well as the
    `task_input`, which contains task-specific input.

123
    The task_input should be a dict with the following entries:
124

125 126 127 128
      'email_id': the full URL to the problem to be rescored.  (required)

    `_xmodule_instance_args` provides information needed by _get_module_instance_for_task()
    to instantiate an xmodule instance.  This is unused here.
129
    """
130 131
    # Translators: This is a past-tense verb that is inserted into task progress messages as {action}.
    action_name = ugettext_noop('emailed')
132
    visit_fcn = perform_delegate_email_batches
133
    return run_main_task(entry_id, visit_fcn, action_name)
134 135


136
@task(base=BaseInstructorTask, routing_key=settings.GRADES_DOWNLOAD_ROUTING_KEY)  # pylint: disable=not-callable
137 138 139 140
def calculate_grades_csv(entry_id, xmodule_instance_args):
    """
    Grade a course and push the results to an S3 bucket for download.
    """
141
    # Translators: This is a past-tense verb that is inserted into task progress messages as {action}.
142
    action_name = ugettext_noop('graded')
143
    task_fn = partial(upload_grades_csv, xmodule_instance_args)
144
    return run_main_task(entry_id, task_fn, action_name)
145 146


147
@task(base=BaseInstructorTask, routing_key=settings.GRADES_DOWNLOAD_ROUTING_KEY)  # pylint: disable=not-callable
148 149 150 151 152 153 154
def calculate_students_features_csv(entry_id, xmodule_instance_args):
    """
    Compute student profile information for a course 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 = ugettext_noop('generated')
155
    task_fn = partial(upload_students_csv, xmodule_instance_args)
156
    return run_main_task(entry_id, task_fn, action_name)
157 158 159 160 161 162 163 164 165 166 167 168


@task(base=BaseInstructorTask)  # pylint: disable=E1102
def cohort_students(entry_id, xmodule_instance_args):
    """
    Cohort students in bulk, and upload the results.
    """
    # Translators: This is a past-tense verb that is inserted into task progress messages as {action}.
    # An example of such a message is: "Progress: {action} {succeeded} of {attempted} so far"
    action_name = ugettext_noop('cohorted')
    task_fn = partial(cohort_students_and_upload, xmodule_instance_args)
    return run_main_task(entry_id, task_fn, action_name)