Пример #1
0
def is_mode_upsellable(user, enrollment, course=None):
    """
    Return whether the user is enrolled in a mode that can be upselled to another mode,
    usually audit upselled to verified.
    The partition code allows this function to more accurately return results for masquerading users.

    Arguments:
        user (:class:`.AuthUser`): The user from the request.user property
        enrollment (:class:`.CourseEnrollment`): The enrollment under consideration.
        course (:class:`.ModulestoreCourse`): Optional passed in modulestore course.
            If provided, it is expected to correspond to `enrollment.course.id`.
            If not provided, the course will be loaded from the modulestore.
            We use the course to retrieve user partitions when calculating whether
            the upgrade link will be shown.
    """
    partition_service = PartitionService(enrollment.course.id, course=course)
    enrollment_track_partition = partition_service.get_user_partition(
        ENROLLMENT_TRACK_PARTITION_ID)
    group = partition_service.get_group(user, enrollment_track_partition)
    current_mode = None
    if group:
        try:
            current_mode = [
                mode.get('slug')
                for mode in settings.COURSE_ENROLLMENT_MODES.values()
                if mode['id'] == group.id
            ].pop()
        except IndexError:
            pass
    upsellable_mode = not current_mode or current_mode in CourseMode.UPSELL_TO_VERIFIED_MODES
    return upsellable_mode
Пример #2
0
def _get_enrollment_track_groups(course_key):
    """
    Helper method that returns an array of the Groups in the EnrollmentTrackUserPartition for the given course.
    If no such partition exists on the course, an empty array is returned.
    """
    partition_service = PartitionService(course_key)
    partition = partition_service.get_user_partition(ENROLLMENT_TRACK_PARTITION_ID)
    return partition.groups if partition else []
Пример #3
0
def _get_enrollment_track_groups(course_key):
    """
    Helper method that returns an array of the Groups in the EnrollmentTrackUserPartition for the given course.
    If no such partition exists on the course, an empty array is returned.
    """
    partition_service = PartitionService(course_key)
    partition = partition_service.get_user_partition(ENROLLMENT_TRACK_PARTITION_ID)
    return partition.groups if partition else []
Пример #4
0
 def get_group_id_by_course_mode_name(self, course_id, mode_name):
     """
     Get the needed group_id from the Enrollment_Track partition for the specific masquerading track.
     """
     partition_service = PartitionService(course_id)
     enrollment_track_user_partition = partition_service.get_user_partition(ENROLLMENT_TRACK_PARTITION_ID)
     for group in enrollment_track_user_partition.groups:
         if group.name == mode_name:
             return group.id
     return None
Пример #5
0
def can_show_verified_upgrade(user, enrollment, course=None):
    """
    Return whether this user can be shown upgrade message.

    Arguments:
        user (:class:`.AuthUser`): The user from the request.user property
        enrollment (:class:`.CourseEnrollment`): The enrollment under consideration.
            If None, then the enrollment is considered to be upgradeable.
        course (:class:`.ModulestoreCourse`): Optional passed in modulestore course.
            If provided, it is expected to correspond to `enrollment.course.id`.
            If not provided, the course will be loaded from the modulestore.
            We use the course to retrieve user partitions when calculating whether
            the upgrade link will be shown.
    """
    # Return `true` if user is not enrolled in course
    if enrollment is None:
        return False
    partition_service = PartitionService(enrollment.course.id, course=course)
    enrollment_track_partition = partition_service.get_user_partition(
        ENROLLMENT_TRACK_PARTITION_ID)
    group = partition_service.get_group(user, enrollment_track_partition)
    current_mode = None
    if group:
        try:
            current_mode = [
                mode.get('slug')
                for mode in settings.COURSE_ENROLLMENT_MODES.values()
                if mode['id'] == group.id
            ].pop()
        except IndexError:
            pass
    upgradable_mode = not current_mode or current_mode in CourseMode.UPSELL_TO_VERIFIED_MODES

    if not upgradable_mode:
        return False

    upgrade_deadline = enrollment.upgrade_deadline

    if upgrade_deadline is None:
        return False

    if datetime.datetime.now(utc).date() > upgrade_deadline.date():
        return False

    # Show the summary if user enrollment is in which allow user to upsell
    return enrollment.is_active and enrollment.mode in CourseMode.UPSELL_TO_VERIFIED_MODES
Пример #6
0
def can_show_verified_upgrade(user, course_id, enrollment):
    """
    Check if we are able to show verified upgrade message based
    on the enrollment and current user partition
    """
    if not enrollment:
        return False
    partition_service = PartitionService(course_id)
    enrollment_track_partition = partition_service.get_user_partition(
        ENROLLMENT_TRACK_PARTITION_ID)
    group = partition_service.get_group(user, enrollment_track_partition)
    current_mode = None
    if group:
        try:
            current_mode = [
                mode.get('slug')
                for mode in settings.COURSE_ENROLLMENT_MODES.values()
                if mode['id'] == group.id
            ].pop()
        except IndexError:
            pass
    upgradable_mode = not current_mode or current_mode in CourseMode.UPSELL_TO_VERIFIED_MODES
    return upgradable_mode and verified_upgrade_link_is_valid(enrollment)
    def handle(self, *args, **options):

        errors = []

        module_store = modulestore()

        print "Starting Swap from Auto Track Cohort Pilot command"

        verified_track_cohorts_setting = self._latest_settings()

        if not verified_track_cohorts_setting:
            raise CommandError("No MigrateVerifiedTrackCohortsSetting found")

        if not verified_track_cohorts_setting.enabled:
            raise CommandError("No enabled MigrateVerifiedTrackCohortsSetting found")

        old_course_key = verified_track_cohorts_setting.old_course_key
        rerun_course_key = verified_track_cohorts_setting.rerun_course_key
        audit_cohort_names = verified_track_cohorts_setting.get_audit_cohort_names()

        # Verify that the MigrateVerifiedTrackCohortsSetting has all required fields
        if not old_course_key:
            raise CommandError("No old_course_key set for MigrateVerifiedTrackCohortsSetting with ID: '%s'"
                               % verified_track_cohorts_setting.id)

        if not rerun_course_key:
            raise CommandError("No rerun_course_key set for MigrateVerifiedTrackCohortsSetting with ID: '%s'"
                               % verified_track_cohorts_setting.id)

        if not audit_cohort_names:
            raise CommandError("No audit_cohort_names set for MigrateVerifiedTrackCohortsSetting with ID: '%s'"
                               % verified_track_cohorts_setting.id)

        print "Running for MigrateVerifiedTrackCohortsSetting with old_course_key='%s' and rerun_course_key='%s'" % \
              (verified_track_cohorts_setting.old_course_key, verified_track_cohorts_setting.rerun_course_key)

        # Get the CourseUserGroup IDs for the audit course names from the old course
        audit_course_user_group_ids = CourseUserGroup.objects.filter(
            name__in=audit_cohort_names,
            course_id=old_course_key,
            group_type=CourseUserGroup.COHORT,
        ).values_list('id', flat=True)

        if not audit_course_user_group_ids:
            raise CommandError(
                "No Audit CourseUserGroup found for course_id='%s' with group_type='%s' for names='%s'"
                % (old_course_key, CourseUserGroup.COHORT, audit_cohort_names)
            )

        # Get all of the audit CourseCohorts from the above IDs that are RANDOM
        random_audit_course_user_group_ids = CourseCohort.objects.filter(
            course_user_group_id__in=audit_course_user_group_ids,
            assignment_type=CourseCohort.RANDOM
        ).values_list('course_user_group_id', flat=True)

        if not random_audit_course_user_group_ids:
            raise CommandError(
                "No Audit CourseCohorts found for course_user_group_ids='%s' with assignment_type='%s"
                % (audit_course_user_group_ids, CourseCohort.RANDOM)
            )

        # Get the CourseUserGroupPartitionGroup for the above IDs, these contain the partition IDs and group IDs
        # that are set for group_access inside of modulestore
        random_audit_course_user_group_partition_groups = list(CourseUserGroupPartitionGroup.objects.filter(
            course_user_group_id__in=random_audit_course_user_group_ids
        ))

        if not random_audit_course_user_group_partition_groups:
            raise CommandError(
                "No Audit CourseUserGroupPartitionGroup found for course_user_group_ids='%s'"
                % random_audit_course_user_group_ids
            )

        # Get the single VerifiedTrackCohortedCourse for the old course
        try:
            verified_track_cohorted_course = VerifiedTrackCohortedCourse.objects.get(course_key=old_course_key)
        except VerifiedTrackCohortedCourse.DoesNotExist:
            raise CommandError("No VerifiedTrackCohortedCourse found for course: '%s'" % old_course_key)

        if not verified_track_cohorted_course.enabled:
            raise CommandError("VerifiedTrackCohortedCourse not enabled for course: '%s'" % old_course_key)

        # Get the single CourseUserGroupPartitionGroup for the verified_track
        # based on the verified_track name for the old course
        try:
            verified_course_user_group = CourseUserGroup.objects.get(
                course_id=old_course_key,
                group_type=CourseUserGroup.COHORT,
                name=verified_track_cohorted_course.verified_cohort_name
            )
        except CourseUserGroup.DoesNotExist:
            raise CommandError(
                "No Verified CourseUserGroup found for course_id='%s' with group_type='%s' for names='%s'"
                % (old_course_key, CourseUserGroup.COHORT, verified_track_cohorted_course.verified_cohort_name)
            )

        try:
            verified_course_user_group_partition_group = CourseUserGroupPartitionGroup.objects.get(
                course_user_group_id=verified_course_user_group.id
            )
        except CourseUserGroupPartitionGroup.DoesNotExist:
            raise CommandError(
                "No Verified CourseUserGroupPartitionGroup found for course_user_group_ids='%s'"
                % random_audit_course_user_group_ids
            )

        # Verify the enrollment track CourseModes exist for the new course
        try:
            CourseMode.objects.get(
                course_id=rerun_course_key,
                mode_slug=CourseMode.AUDIT
            )
        except CourseMode.DoesNotExist:
            raise CommandError("Audit CourseMode is not defined for course: '%s'" % rerun_course_key)

        try:
            CourseMode.objects.get(
                course_id=rerun_course_key,
                mode_slug=CourseMode.VERIFIED
            )
        except CourseMode.DoesNotExist:
            raise CommandError("Verified CourseMode is not defined for course: '%s'" % rerun_course_key)

        items = module_store.get_items(rerun_course_key)
        if not items:
            raise CommandError("Items for Course with key '%s' not found." % rerun_course_key)

        items_to_update = []

        all_cohorted_track_group_ids = set()
        for audit_course_user_group_partition_group in random_audit_course_user_group_partition_groups:
            all_cohorted_track_group_ids.add(audit_course_user_group_partition_group.group_id)
            all_cohorted_track_group_ids.add(verified_course_user_group_partition_group.group_id)

        for item in items:
            # Verify that there exists group access for this xblock, otherwise skip these checks
            if item.group_access:
                set_audit_enrollment_track = False
                set_verified_enrollment_track = False

                # Check the partition and group IDs for the audit course groups, if they exist in
                # the xblock's access settings then set the audit track flag to true
                for audit_course_user_group_partition_group in random_audit_course_user_group_partition_groups:
                    audit_partition_group_access = item.group_access.get(
                        audit_course_user_group_partition_group.partition_id,
                        None
                    )
                    if (audit_partition_group_access
                            and audit_course_user_group_partition_group.group_id in audit_partition_group_access):
                        print "Queueing XBlock at location: '%s' for Audit Content Group update " % item.location
                        set_audit_enrollment_track = True

                # Check the partition and group IDs for the verified course group, if it exists in
                # the xblock's access settings then set the verified track flag to true
                verified_partition_group_access = item.group_access.get(
                    verified_course_user_group_partition_group.partition_id,
                    None
                )
                if verified_partition_group_access:
                    non_verified_track_access_groups = (set(verified_partition_group_access) -
                                                        all_cohorted_track_group_ids)
                    # If the item has group_access that is not the
                    # verified or audit group IDs then raise an error
                    # This only needs to be checked for this partition_group once
                    if non_verified_track_access_groups:
                        errors.append(
                            "Non audit/verified cohorted content group set for xblock, location '%s' with IDs '%s'"
                            % (item.location, non_verified_track_access_groups)
                        )
                    if verified_course_user_group_partition_group.group_id in verified_partition_group_access:
                        print "Queueing XBlock at location: '%s' for Verified Content Group update " % item.location
                        set_verified_enrollment_track = True

                # Add the enrollment track ids to a group access array
                enrollment_track_group_access = []
                if set_audit_enrollment_track:
                    enrollment_track_group_access.append(settings.COURSE_ENROLLMENT_MODES['audit'])
                if set_verified_enrollment_track:
                    enrollment_track_group_access.append(settings.COURSE_ENROLLMENT_MODES['verified'])

                # If there are no errors, and either the audit track, or verified
                #  track needed an update, set the access, update and publish
                if set_verified_enrollment_track or set_audit_enrollment_track:
                    # Sets whether or not an xblock has changes
                    has_changes = module_store.has_changes(item)

                    # Check that the xblock does not have changes and add it to be updated, otherwise add an error
                    if not has_changes:
                        item.group_access = {ENROLLMENT_TRACK_PARTITION_ID: enrollment_track_group_access}
                        items_to_update.append(item)
                    else:
                        errors.append("XBlock '%s' with location '%s' needs access changes, but is a draft"
                                      % (item.display_name, item.location))

        partitions_to_delete = random_audit_course_user_group_partition_groups
        partitions_to_delete.append(verified_course_user_group_partition_group)

        # If there are no errors iterate over and update all of the items that had the access changed
        if not errors:
            for item in items_to_update:
                module_store.update_item(item, ModuleStoreEnum.UserID.mgmt_command)
                module_store.publish(item.location, ModuleStoreEnum.UserID.mgmt_command)
                print "Updated and published XBlock at location: '%s'" % item.location

        # Check if we should delete any partition groups if there are no errors.
        # If there are errors, none of the xblock items will have been updated,
        # so this section will throw errors for each partition in use
        if partitions_to_delete and not errors:
            partition_service = PartitionService(rerun_course_key)
            course = partition_service.get_course()
            for partition_to_delete in partitions_to_delete:
                # Get the user partition, and the index of that partition in the course
                partition = partition_service.get_user_partition(partition_to_delete.partition_id)
                if partition:
                    partition_index = course.user_partitions.index(partition)
                    group_id = int(partition_to_delete.group_id)

                    # Sanity check to verify that all of the groups being deleted are empty,
                    # since they should have been converted to use enrollment tracks instead.
                    # Taken from contentstore/views/course.py.remove_content_or_experiment_group
                    usages = GroupConfiguration.get_partitions_usage_info(module_store, course)
                    used = group_id in usages
                    if used:
                        errors.append("Content group '%s' is in use and cannot be deleted."
                                      % partition_to_delete.group_id)

                    # If there are not errors, proceed to update the course and user_partitions
                    if not errors:
                        # Remove the groups that match the group ID of the partition to be deleted
                        # Else if there are no match groups left, remove the user partition
                        matching_groups = [group for group in partition.groups if group.id == group_id]
                        if matching_groups:
                            group_index = partition.groups.index(matching_groups[0])
                            partition.groups.pop(group_index)
                            # Update the course user partition with the updated groups
                            if partition.groups:
                                course.user_partitions[partition_index] = partition
                            else:
                                course.user_partitions.pop(partition_index)
                        module_store.update_item(course, ModuleStoreEnum.UserID.mgmt_command)

        # If there are any errors, join them together and raise the CommandError
        if errors:
            raise CommandError(
                ("Error for MigrateVerifiedTrackCohortsSetting with ID='%s'\n" % verified_track_cohorts_setting.id) +
                "\t\n".join(errors)
            )

        print "Finished for MigrateVerifiedTrackCohortsSetting with ID='%s" % verified_track_cohorts_setting.id