def get_user_course_response_task(users, course_str, depth, callback_url): """ Get a list of users grades' for a course """ user_grades = {} grades_schema = {} course_key = CourseKey.from_string(str(course_str)) course = courses.get_course(course_key) for user in users: course_grade = CourseGradeFactory().update(user, course) if depth == "all": grades_schema = get_user_grades(user.id, course_str) else: grades_schema = "Showing course grade summary, specify depth=all in query params." user_grades[user.username] = { 'name': "{} {}".format(user.first_name, user.last_name), 'email': user.email, 'start_date': course.start, 'end_date': course.end if not None else "This course has no end date.", 'all_grades': grades_schema, "passed": course_grade.passed, "percent": course_grade.percent } #requests.post(str(callback_url), data=user_grades) return user_grades
def report(self): """ Generates a report for the Ed2go completion report endpoint. Returns: A dictionary containing the report values. """ course_grade = CourseGradeFactory().create(self.user, get_course(self.course_key)) persistent_grade = PersistentCourseGrade.objects.filter( user_id=self.user.id, course_id=self.course_key).first() return { c.REP_REGISTRATION_KEY: self.registration_key, c.REP_PERCENT_PROGRESS: round(self.progress * 100, 2), c.REP_LAST_ACCESS_DT: self.user.last_login.strftime('%Y-%m-%dT%H:%M:%SZ'), c.REP_COURSE_PASSED: str(course_grade.passed).lower(), c.REP_PERCENT_OVERALL_SCORE: course_grade.percent, c.REP_COMPLETION_DT: persistent_grade.passed_timestamp if persistent_grade else '', c.REP_TIME_SPENT: format_timedelta( CourseSession.total_time(user=self.user, course_key=self.course_key)), }
def get_course_descriptor(course_key, depth): """ Returns course descriptor """ try: course_descriptor = courses.get_course(course_key, depth) except ValueError: course_descriptor = None return course_descriptor
def is_course_public(course_key: CourseKey) -> AccessResponse: """ This checks if a course is publicly accessible or not. """ try: course = get_course(course_key, depth=0) except CourseRunNotFound: return ACCESS_DENIED return check_public_access(course, [COURSE_VISIBILITY_PUBLIC])
def handle(self, *args, **options): course_id = options['course_id'] course_key = CourseKey.from_string(course_id) course = get_course(course_key) if not course: raise CommandError(u'Invalid course id: {}'.format(course_id)) if course.discussion_link: self.stdout.write(course.discussion_link)
def _create_subsection_grade(self, user_id, course_key, usage_key): """ Given a user_id, course_key, and subsection usage_key, creates a new ``PersistentSubsectionGrade``. """ course = get_course(course_key, depth=None) subsection = course.get_child(usage_key) if not subsection: raise Exception('Subsection with given usage_key does not exist.') user = USER_MODEL.objects.get(id=user_id) course_data = CourseData(user, course=course) subsection_grade = CreateSubsectionGrade(subsection, course_data.structure, {}, {}) return subsection_grade.update_or_create_model(user, force_update_subsections=True)
def _is_data_valid(self, request): """ Validates the data posted to the view. Arguments request -- HTTP request Returns Tuple (data_is_valid, course_key, error_msg) """ course_id = request.data.get('course_id') if not course_id: return False, None, u'Field course_id is missing.' try: course_key = CourseKey.from_string(course_id) courses.get_course(course_key) except (InvalidKeyError, ValueError) as ex: log.exception(u'Unable to locate course matching %s.', course_id) return False, None, text_type(ex) return True, course_key, None
def _create_subsection_grade(user_id, course_key, usage_key): """ Given a user_id, course_key, and subsection usage_key, creates a new ``PersistentSubsectionGrade``. """ from lms.djangoapps.courseware.courses import get_course from django.contrib.auth import get_user_model course = get_course(course_key, depth=None) subsection = course.get_child(usage_key) if not subsection: raise Exception('Subsection with given usage_key does not exist.') user = get_user_model().objects.get(id=user_id) subsection_grade = CreateSubsectionGrade(subsection, course_data.CourseData(user, course=course).structure, {}, {}) return subsection_grade.update_or_create_model(user, force_update_subsections=True)
def dump_one(self, *args, **options): if not args: raise CommandError("Course id not specified") if len(args) > 2: raise CommandError("Only one course id may be specified") raw_course_key = args[0] if len(args) == 1: output_file_location = self.get_default_file_location( raw_course_key) else: output_file_location = args[1] try: course_key = CourseKey.from_string(raw_course_key) except InvalidKeyError: course_key = CourseLocator.from_string(raw_course_key) course = get_course(course_key) if not course: raise CommandError("Invalid course id: {}".format(course_key)) target_discussion_ids = None if options.get(self.COHORTED_ONLY_PARAMETER, False): cohorted_discussions = get_legacy_discussion_settings( course_key).cohorted_discussions if not cohorted_discussions: raise MissingCohortedConfigCommandError( "Only cohorted discussions are marked for export, " "but no cohorted discussions found for the course") else: target_discussion_ids = cohorted_discussions raw_end_date = options.get(self.END_DATE_PARAMETER, None) end_date = dateutil.parser.parse( raw_end_date) if raw_end_date else None data = Extractor().extract( course_key, end_date=end_date, thread_type=(options.get(self.THREAD_TYPE_PARAMETER, None)), thread_ids=target_discussion_ids, ) filter_str = self._get_filter_string_representation(options) self.stdout.write("Writing social stats ({}) to {}\n".format( filter_str, output_file_location)) with open(output_file_location, 'wb') as output_stream: Exporter(output_stream).export(data)
def _create_subsection_grade(self, user_id, course_key, usage_key): """ Given a user_id, course_key, and subsection usage_key, creates a new ``PersistentSubsectionGrade``. """ course = get_course(course_key, depth=None) subsection = course.get_child(usage_key) if not subsection: raise Exception('Subsection with given usage_key does not exist.') user = USER_MODEL.objects.get(id=user_id) course_data = CourseData(user, course=course) subsection_grade = CreateSubsectionGrade(subsection, course_data.structure, {}, {}) return subsection_grade.update_or_create_model( user, force_update_subsections=True)
def get_random_cohort(course_key): """ Helper method to get a cohort for random assignment. If there are multiple cohorts of type RANDOM in the course, one of them will be randomly selected. If there are no existing cohorts of type RANDOM in the course, one will be created. """ course = courses.get_course(course_key) cohorts = get_course_cohorts(course, assignment_type=CourseCohort.RANDOM) if cohorts: cohort = local_random().choice(cohorts) else: cohort = CourseCohort.create( cohort_name=DEFAULT_COHORT_NAME, course_id=course_key, assignment_type=CourseCohort.RANDOM).course_user_group return cohort
def post(self, request, *args, **kwargs): """ Attempt to enroll the user. """ user = request.user valid, course_key, error = self._is_data_valid(request) if not valid: return DetailResponse(error, status=HTTP_406_NOT_ACCEPTABLE) embargo_response = embargo_api.get_embargo_response( request, course_key, user) if embargo_response: return embargo_response # Don't do anything if an enrollment already exists course_id = six.text_type(course_key) enrollment = CourseEnrollment.get_enrollment(user, course_key) if enrollment and enrollment.is_active: msg = Messages.ENROLLMENT_EXISTS.format(course_id=course_id, username=user.username) return DetailResponse(msg, status=HTTP_409_CONFLICT) # Check to see if enrollment for this course is closed. course = courses.get_course(course_key) if CourseEnrollment.is_enrollment_closed(user, course): msg = Messages.ENROLLMENT_CLOSED.format(course_id=course_id) log.info(u'Unable to enroll user %s in closed course %s.', user.id, course_id) return DetailResponse(msg, status=HTTP_406_NOT_ACCEPTABLE) # If there is no audit or honor course mode, this most likely # a Prof-Ed course. Return an error so that the JS redirects # to track selection. honor_mode = CourseMode.mode_for_course(course_key, CourseMode.HONOR) audit_mode = CourseMode.mode_for_course(course_key, CourseMode.AUDIT) # Check to see if the User has an entitlement and enroll them if they have one for this course if CourseEntitlement.check_for_existing_entitlement_and_enroll( user=user, course_run_key=course_key): return JsonResponse( { 'redirect_destination': reverse('courseware', args=[six.text_type(course_id)]), }, ) # Accept either honor or audit as an enrollment mode to # maintain backwards compatibility with existing courses default_enrollment_mode = audit_mode or honor_mode course_name = None course_announcement = None if course is not None: course_name = course.display_name course_announcement = course.announcement if default_enrollment_mode: msg = Messages.ENROLL_DIRECTLY.format(username=user.username, course_id=course_id) if not default_enrollment_mode.sku: # If there are no course modes with SKUs, return a different message. msg = Messages.NO_SKU_ENROLLED.format( enrollment_mode=default_enrollment_mode.slug, course_id=course_id, course_name=course_name, username=user.username, announcement=course_announcement) log.info(msg) self._enroll(course_key, user, default_enrollment_mode.slug) mode = CourseMode.AUDIT if audit_mode else CourseMode.HONOR SAILTHRU_AUDIT_PURCHASE.send(sender=None, user=user, mode=mode, course_id=course_id) self._handle_marketing_opt_in(request, course_key, user) return DetailResponse(msg) else: msg = Messages.NO_DEFAULT_ENROLLMENT_MODE.format( course_id=course_id) return DetailResponse(msg, status=HTTP_406_NOT_ACCEPTABLE)
def handle(self, *args, **options): if len(args) < 1 or len(args) > 2: print(Command.help) return dry_run = True create_log = False msg_string = 'Script started on {}'.format( datetime.datetime.now().ctime()) if 'repair' in args: dry_run = False if 'dryrun' in args: dry_run = True if 'createlog' in args: create_log = True file_handler = logging.FileHandler( 'repair_internal_admin_instructor_role.log') file_handler.setLevel(logging.DEBUG) formatter = logging.Formatter( '%(asctime)s-%(name)s-%(levelname)s-%(message)s') file_handler.setFormatter(formatter) log.addHandler(file_handler) log.info(msg_string) if dry_run: msg_string = 'Script started in dry run mode, this will print for all internal admins courses for which ' \ 'we need to remove or add theirs instructor role' else: msg_string = 'Script started in repair mode, this will permanently remove or add instructor role of ' \ 'internal admins. THIS IS IRREVERSIBLE!' log.info(msg_string) internal_admin_group_name = 'mcka_role_internal_admin' internal_tag_group_type = 'tag:internal' instructor_role = 'instructor' staff_role = 'staff' number_of_removed_roles = 0 number_of_added_roles = 0 #get all internal admins try: internal_admin_group = Group.objects.get( name__icontains=internal_admin_group_name) except ObjectDoesNotExist: internal_admin_group = None if internal_admin_group: internal_admins = internal_admin_group.user_set.all() #get internal tagged courses try: internal_courses_group = Group.objects.get( groupprofile__group_type=internal_tag_group_type) except ObjectDoesNotExist: internal_courses_group = None if internal_courses_group: internal_courses = CourseGroupRelationship.objects.filter( group=internal_courses_group) internal_courses_ids = [] for internal_course in internal_courses: internal_courses_ids.append(internal_course.course_id) # for all internal admins check their roles and remove instructor role on course # if he doesn't have staff role on course and course isn't tagged internal for internal_admin in internal_admins: user_roles = CourseAccessRole.objects.filter(user=internal_admin) instructor_courses = [] staff_courses = [] for user_role in user_roles: if user_role.role == instructor_role: instructor_courses.append(user_role.course_id) if user_role.role == staff_role: staff_courses.append(user_role.course_id) for instructor_course in instructor_courses: if str( instructor_course ) not in internal_courses_ids and instructor_course not in staff_courses: number_of_removed_roles += 1 if dry_run: msg_string = 'Remove instructor role for internal admin ' + str(internal_admin.id) +\ ' on course ' + str(instructor_course) + '.' log.info(msg_string) else: role_to_delete = CourseAccessRole.objects.get( user=internal_admin, role=instructor_role, course_id=instructor_course) role_to_delete.delete() # for all internal tagged course check roles and if internal admins don't have instructor role on course add it for internal_course in internal_courses: course_id = get_course_key(internal_course.course_id) course_roles = CourseAccessRole.objects.filter(course_id=course_id) instructor_users = [] for course_role in course_roles: if course_role.role == instructor_role: instructor_users.append(course_role.user_id) for internal_admin in internal_admins: if internal_admin.id not in instructor_users: number_of_added_roles += 1 if dry_run: msg_string = 'Add instructor role for internal admin ' + str(internal_admin.id) + \ ' on course ' + str(course_id) + '.' log.info(msg_string) else: course = courses.get_course(course_id, 0) new_role = CourseAccessRole(user=internal_admin, role=instructor_role, course_id=course.id, org=course.org) new_role.save() msg_string = 'Number of removed roles: ' + str( number_of_removed_roles) + '.' log.info(msg_string) msg_string = 'Number of added roles: ' + str( number_of_added_roles) + '.' log.info(msg_string) log.info( '---------------------------------------------------------------------------------------------------' ) if create_log: print( 'Script started in create log mode, please open repair_internal_admin_instructor_role.log file.' )
def course(self): # TODO using 'modulestore().get_course(self._course_id)' doesn't work. return None from lms.djangoapps.courseware.courses import get_course return get_course(self.course_id)
def cohort_handler(request, course_key_string, cohort_id=None): """ The restful handler for cohort requests. Requires JSON. GET If a cohort ID is specified, returns a JSON representation of the cohort (name, id, user_count, assignment_type, user_partition_id, group_id). If no cohort ID is specified, returns the JSON representation of all cohorts. This is returned as a dict with the list of cohort information stored under the key `cohorts`. PUT or POST or PATCH If a cohort ID is specified, updates the cohort with the specified ID. Currently the only properties that can be updated are `name`, `user_partition_id` and `group_id`. Returns the JSON representation of the updated cohort. If no cohort ID is specified, creates a new cohort and returns the JSON representation of the updated cohort. """ course_key = CourseKey.from_string(course_key_string) if not has_course_author_access(request.user, course_key): raise Http404( 'The requesting user does not have course author permissions.') course = get_course(course_key) if request.method == 'GET': if not cohort_id: all_cohorts = [ _get_cohort_representation(c, course) for c in cohorts.get_course_cohorts(course) ] return JsonResponse({'cohorts': all_cohorts}) else: cohort = cohorts.get_cohort_by_id(course_key, cohort_id) return JsonResponse(_get_cohort_representation(cohort, course)) else: name = request.json.get('name') assignment_type = request.json.get('assignment_type') if not name: # Note: error message not translated because it is not exposed to the user (UI prevents this state). return JsonResponse({"error": "Cohort name must be specified."}, 400) if not assignment_type: # Note: error message not translated because it is not exposed to the user (UI prevents this state). return JsonResponse( {"error": "Assignment type must be specified."}, 400) # If cohort_id is specified, update the existing cohort. Otherwise, create a new cohort. if cohort_id: cohort = cohorts.get_cohort_by_id(course_key, cohort_id) if name != cohort.name: if cohorts.is_cohort_exists(course_key, name): err_msg = gettext( "A cohort with the same name already exists.") return JsonResponse({"error": str(err_msg)}, 400) cohort.name = name cohort.save() try: cohorts.set_assignment_type(cohort, assignment_type) except ValueError as err: return JsonResponse({"error": str(err)}, 400) else: try: cohort = cohorts.add_cohort(course_key, name, assignment_type) except ValueError as err: return JsonResponse({"error": str(err)}, 400) group_id = request.json.get('group_id') if group_id is not None: user_partition_id = request.json.get('user_partition_id') if user_partition_id is None: # Note: error message not translated because it is not exposed to the user (UI prevents this state). return JsonResponse( { "error": "If group_id is specified, user_partition_id must also be specified." }, 400) existing_group_id, existing_partition_id = cohorts.get_group_info_for_cohort( cohort) if group_id != existing_group_id or user_partition_id != existing_partition_id: unlink_cohort_partition_group(cohort) link_cohort_to_partition_group(cohort, user_partition_id, group_id) else: # If group_id was specified as None, unlink the cohort if it previously was associated with a group. existing_group_id, _ = cohorts.get_group_info_for_cohort(cohort) if existing_group_id is not None: unlink_cohort_partition_group(cohort) return JsonResponse(_get_cohort_representation(cohort, course))
def is_course_public(course_key: CourseKey) -> AccessResponse: """ This checks if a course is publicly accessible or not. """ course = get_course(course_key, depth=0) return check_public_access(course, [COURSE_VISIBILITY_PUBLIC])
def handle(self, *args, **options): # build a list of CourseKeys from any course IDs given course_key_list = [] for course_id in options["course_id"]: try: course_key_list.append(CourseKey.from_string(course_id)) except (InvalidKeyError, ValueError): log.error("Invalid course ID: %s", course_id) sys.exit(1) # get the Learndot:edX course mappings course_mappings = CourseMapping.objects.all() if course_key_list: course_mappings = course_mappings.filter( edx_course_key__in=course_key_list) if not course_mappings.exists(): if options["course_id"]: log.error( "No course mappings were found for your specified course IDs." ) else: log.error("No course mappings were found.") sys.exit(1) learndot_client = LearndotAPIClient() # for each mapped course, go through its enrollments, get the # course grade for each enrolled user, and if the user has passed, # update the Learndot enrolment date_settings = { 'TIMEZONE': settings.TIME_ZONE, 'RETURN_AS_TIMEZONE_AWARE': True } end_enrollments_date = dateparser.parse(options["end"], settings=date_settings) start_enrolments_date = dateparser.parse(options["start"], settings=date_settings) for cm in course_mappings: try: course = get_course(cm.edx_course_key) except (InvalidKeyError, ValueError): log.error("Invalid edX course found in map: %s", cm.edx_course_key) continue log.info("Processing enrollments in course %s", cm.edx_course_key) enrollments = CourseEnrollment.objects.filter( course_id=cm.edx_course_key, created__range=[start_enrolments_date, end_enrollments_date], ) if options["users"]: enrollments = enrollments.filter( user__username__in=options["users"]) for enrollment in enrollments: contact_id = learndot_client.get_contact_id(enrollment.user) if not contact_id: log.info( "Not setting enrolment status for user %s in course %s, because contact_id is None .", enrollment.user, cm.edx_course_key) continue # # Disturbingly enough, if persistent grades are not # enabled, it just takes looking up the grade to get # the Learndot enrolment updated, because when # CourseGradeFactory constructs the CourseGrade in its # read() method, it will actually call its _update() # method, which sends the COURSE_GRADE_NOW_PASSED # signal, which of course fires # edxlearndot.signals.listen_for_passing_grade. # # However, if the edX instance has persistent course # grades enabled, the CourseGrade doesn't have to be # constructed, so the signal isn't fired, and we have # to explicitly update Learndot. # course_grade = CourseGradeFactory().read( enrollment.user, course) if not course_grade: log.info( "Not setting enrolment status for user %s in course %s, because no grade is available.", enrollment.user, cm.edx_course_key) elif course_grade.passed and should_persist_grades( cm.edx_course_key): log.info( "Grades are persistent; explicitly updating Learndot enrolment." ) learndot_client.check_if_enrolment_and_set_status_to_passed( contact_id, cm.learndot_component_id, unconditional=options["unconditional"])
def get_user_grades(user_id, course_str): """ Get a single user's grades for course. """ user = USER_MODEL.objects.get(id=user_id) course_key = CourseKey.from_string(str(course_str)) course = courses.get_course(course_key) course_grade = CourseGradeFactory().update(user, course) course_structure = get_course_in_cache(course.id) courseware_summary = course_grade.chapter_grades.values() grade_summary = course_grade.summary grades_schema = {} courseware_summary = course_grade.chapter_grades.items() chapter_schema = {} for key, chapter in courseware_summary: subsection_schema = {} for section in chapter['sections']: section_children = course_structure.get_children(section.location) verticals = course_structure.get_children(section.location) vertical_schema = {} for vertical_key in verticals: sections_scores = {} problem_keys = course_structure.get_children(vertical_key) for problem_key in problem_keys: if problem_key in section.problem_scores: problem_score = section.problem_scores[problem_key] xblock_content_url = reverse( 'courseware.views.views.render_xblock', kwargs={'usage_key_string': unicode(problem_key)}, ) xblock_structure_url = generate_xblock_structure_url( course_str, problem_key, user) sections_scores[str(problem_key)] = { "date": problem_score.first_attempted if problem_score.first_attempted is not None else "Not attempted", "earned": problem_score.earned, "possible": problem_score.possible, "xblock_content_url": "{}{}".format(settings.LMS_ROOT_URL, xblock_content_url), "xblock_structure_url": "{}{}".format(settings.LMS_ROOT_URL, xblock_structure_url) } else: sections_scores[str( problem_key)] = "This block has no grades" vertical_structure_url = generate_xblock_structure_url( course_str, vertical_key, user) vertical_schema[str(vertical_key)] = { 'problem_blocks': sections_scores, "vertical_structure_url": vertical_structure_url } subsection_structure_url = generate_xblock_structure_url( course_str, section.location, user) subsection_schema[str(section.location)] = { "verticals": vertical_schema, "section_score": course_grade.score_for_module(section.location), "subsection_structure_url": subsection_structure_url } chapter_structure_url = generate_xblock_structure_url( course_str, key, user) chapter_schema[str(key)] = { "sections": subsection_schema, "chapter_structure_url": chapter_structure_url } return chapter_schema
def perform_delegate_email_batches(entry_id, course_id, task_input, action_name): """ Delegates emails by querying for the list of recipients who should get the mail, chopping up into batches of no more than settings.BULK_EMAIL_EMAILS_PER_TASK in size, and queueing up worker jobs. """ entry = InstructorTask.objects.get(pk=entry_id) # Get inputs to use in this task from the entry. user_id = entry.requester.id task_id = entry.task_id # Perfunctory check, since expansion is made for convenience of other task # code that doesn't need the entry_id. if course_id != entry.course_id: format_msg = "Course id conflict: explicit value %r does not match task value %r" log.warning("Task %s: " + format_msg, task_id, course_id, entry.course_id) # lint-amnesty, pylint: disable=logging-not-lazy raise ValueError(format_msg % (course_id, entry.course_id)) # Fetch the CourseEmail. email_id = task_input['email_id'] try: email_obj = CourseEmail.objects.get(id=email_id) except CourseEmail.DoesNotExist: # The CourseEmail object should be committed in the view function before the task # is submitted and reaches this point. log.warning("Task %s: Failed to get CourseEmail with id %s", task_id, email_id) raise # Check to see if email batches have already been defined. This seems to # happen sometimes when there is a loss of connection while a task is being # queued. When this happens, the same task gets called again, and a whole # new raft of subtasks gets queued up. We will assume that if subtasks # have already been defined, there is no need to redefine them below. # So we just return right away. We don't raise an exception, because we want # the current task to be marked with whatever it had been marked with before. if len(entry.subtasks) > 0 and len(entry.task_output) > 0: log.warning("Task %s has already been processed for email %s! InstructorTask = %s", task_id, email_id, entry) progress = json.loads(entry.task_output) return progress # Sanity check that course for email_obj matches that of the task referencing it. if course_id != email_obj.course_id: format_msg = "Course id conflict: explicit value %r does not match email value %r" log.warning("Task %s: " + format_msg, task_id, course_id, email_obj.course_id) # lint-amnesty, pylint: disable=logging-not-lazy raise ValueError(format_msg % (course_id, email_obj.course_id)) # Fetch the course object. course = get_course(course_id) # Get arguments that will be passed to every subtask. targets = email_obj.targets.all() global_email_context = _get_course_email_context(course) recipient_qsets = [ target.get_users(course_id, user_id) for target in targets ] # Use union here to combine the qsets instead of the | operator. This avoids generating an # inefficient OUTER JOIN query that would read the whole user table. combined_set = recipient_qsets[0].union(*recipient_qsets[1:]) if len(recipient_qsets) > 1 \ else recipient_qsets[0] recipient_fields = ['profile__name', 'email', 'username'] log.info("Task %s: Preparing to queue subtasks for sending emails for course %s, email %s", task_id, course_id, email_id) total_recipients = combined_set.count() # Weird things happen if we allow empty querysets as input to emailing subtasks # The task appears to hang at "0 out of 0 completed" and never finishes. if total_recipients == 0: msg = "Bulk Email Task: Empty recipient set" log.warning(msg) raise ValueError(msg) def _create_send_email_subtask(to_list, initial_subtask_status): """Creates a subtask to send email to a given recipient list.""" subtask_id = initial_subtask_status.task_id new_subtask = send_course_email.subtask( ( entry_id, email_id, to_list, global_email_context, initial_subtask_status.to_dict(), ), task_id=subtask_id, ) return new_subtask progress = queue_subtasks_for_query( entry, action_name, _create_send_email_subtask, [combined_set], recipient_fields, settings.BULK_EMAIL_EMAILS_PER_TASK, total_recipients, ) # We want to return progress here, as this is what will be stored in the # AsyncResult for the parent task as its return value. # The AsyncResult will then be marked as SUCCEEDED, and have this return value as its "result". # That's okay, for the InstructorTask will have the "real" status, and monitoring code # should be using that instead. return progress
def post(self, request): query_params = self.request.query_params depth = query_params.get('depth', None) # create the list based on the post parameters serializer = GradeBulkAPIViewSerializer(data=request.data) try: course_ids = request.data['course_ids'] except KeyError: course_ids = None try: usernames = request.data['usernames'] except KeyError: usernames = None try: email_extension = request.data['email_extension'] except KeyError: email_extension = None try: callback_url = request.data['callback_url'] except KeyError: callback_url = None # compile list of email adresses if email_extension is not None and usernames is not None: list_of_emails_or_usernames = _build_emails( usernames, email_extension) else: list_of_emails_or_usernames = usernames if course_ids is None and email_extension is None: return generate_error_response('email_extention') # Set up a dictionaries/list to contain the user grades and course grades # catching the incorrect courses in a "course_failure" list course_results = {} course_success = {} course_failure = [] user_grades = {} if course_ids is None: user_list = USER_MODEL.objects.filter( Q(username__in=usernames) | Q(email__in=list_of_emails_or_usernames), ) user_courses = CourseEnrollment.objects.filter(user__in=user_list) for course_enrollment in user_courses: course_str = str(course_enrollment.course_id) course = get_course(course_enrollment.course_id) course_key = CourseKey.from_string(str(course_str)) user_grades = get_user_course_response(course, user_list, course_str, depth) course_success[course_str] = user_grades if course_ids is not None: for course_str in course_ids: if usernames is not None: user_list = USER_MODEL.objects.filter( Q(username__in=usernames) | Q(email__in=list_of_emails_or_usernames), courseenrollment__course_id=CourseKey.from_string( course_str)).order_by('username').select_related( 'profile') else: # Get all users enrolled given a course key user_list = USER_MODEL.objects.filter( courseenrollment__course_id=CourseKey.from_string( course_str)).order_by('username').select_related( 'profile') try: course_key = CourseKey.from_string(str(course_str)) course = courses.get_course(course_key) user_grades = get_user_course_response( course, user_list, course_str, depth) course_success[course_str] = user_grades user_grades = {} except Exception as e: log.error(e) pass user_grades = {} except InvalidKeyError: log.error( 'Invalid key, {} does not exist'.format(course_str)) course_failure.append( "{} does not exist".format(course_str)) pass except ValueError: log.error('Value error, {} could not be found.'.format( course_str)) course_failure.append( "{} does not exist".format(course_str)) course_results["successes"] = course_success course_results["failures"] = course_failure return Response(course_results)