def submit_bulk_course_email(request, course_key, email_id, schedule=None): """ Request to have bulk email sent as a background task. The specified CourseEmail object will be sent be updated for all students who have enrolled in a course. Parameters are the `course_key` and the `email_id`, the id of the CourseEmail object. AlreadyRunningError is raised if the same recipients are already being emailed with the same CourseEmail object. """ # Assume that the course is defined, and that the user has already been verified to have # appropriate access to the course. But make sure that the email exists. # We also pull out the targets argument here, so that is displayed in # the InstructorTask status. email_obj = CourseEmail.objects.get(id=email_id) # task_input has a limit to the size it can store, so any target_type with count > 1 is combined and counted targets = Counter([target.target_type for target in email_obj.targets.all()]) targets = [ target if count <= 1 else f"{count} {target}" for target, count in targets.items() ] task_type = 'bulk_course_email' task_class = send_bulk_course_email task_input = {'email_id': email_id, 'to_option': targets} task_key_stub = str(email_id) # create the key value by using MD5 hash: task_key = hashlib.md5(task_key_stub.encode('utf-8')).hexdigest() if schedule: return schedule_task(request, task_type, course_key, task_input, task_key, schedule) return submit_task(request, task_type, task_class, course_key, task_input, task_key)
def test_create_scheduled_instructor_task(self): """ Happy path test for the `schedule_task` function. Verifies that we create an InstructorTask instance and an associated InstructorTaskSchedule instance as expected. """ with LogCapture() as log: schedule_task(self.request, self.task_type, self.course.id, self.task_input, self.task_key, self.schedule) # get the task instance and its associated schedule for verifications task = InstructorTask.objects.get(course_id=self.course.id, task_key=self.task_key) task_schedule = InstructorTaskSchedule.objects.get(task=task) expected_task_args = { "request_info": { "username": self.instructor.username, "user_id": self.instructor.id, "ip": "127.0.0.1", "agent": "test_agent", "host": "test_server_name", }, "task_id": task.task_id } expected_messages = [ f"Creating a scheduled instructor task of type '{self.task_type}' for course '{self.course.id}' requested " f"by user with id '{self.request.user.id}'", f"Creating a task schedule associated with instructor task '{task.id}' and due after '{self.schedule}'", f"Updating task state of instructor task '{task.id}' to '{SCHEDULED}'" ] # convert from text back to JSON before comparison actual_task_args = json.loads(task_schedule.task_args) # verify the task has the correct state assert task.task_state == SCHEDULED # verify that the schedule is associated with the correct task_id (UUID) assert task_schedule.task_id == task.id # verify that the schedule is the expected date and time assert task_schedule.task_due == self.schedule # verify the task_arguments are as expected assert expected_task_args == actual_task_args self._verify_log_messages(expected_messages, log)
def test_create_scheduled_instructor_task_expect_failure( self, mock_get_xmodule_instance_args): """ A test to verify that we will mark a task as `FAILED` if a failure occurs during the creation of the task schedule. """ expected_messages = [ f"Creating a scheduled instructor task of type '{self.task_type}' for course '{self.course.id}' requested " f"by user with id '{self.request.user.id}'", "Error occurred during task or schedule creation: boom!", ] with self.assertRaises(QueueConnectionError): with LogCapture() as log: schedule_task(self.request, self.task_type, self.course.id, self.task_input, self.task_key, self.schedule) task = InstructorTask.objects.get(course_id=self.course.id, task_key=self.task_key) assert task.task_state == FAILURE self._verify_log_messages(expected_messages, log)