Пример #1
0
def add_cohort(course_key, name, assignment_type):
    """
    Add a cohort to a course.  Raises ValueError if a cohort of the same name already
    exists.
    """
    log.debug("Adding cohort %s to %s", name, course_key)
    if is_cohort_exists(course_key, name):
        raise ValueError(_("You cannot create two cohorts with the same name"))

    try:
        course = get_course_by_id(course_key)
    except Http404:
        raise ValueError("Invalid course_key")  # lint-amnesty, pylint: disable=raise-missing-from

    cohort = CourseCohort.create(
        cohort_name=name,
        course_id=course.id,
        assignment_type=assignment_type
    ).course_user_group

    tracker.emit(
        "edx.cohort.creation_requested",
        {"cohort_name": cohort.name, "cohort_id": cohort.id}
    )
    return cohort
Пример #2
0
 def _get_course(self):
     """
     Get course and save it in the context, so it doesn't need to be reloaded.
     """
     if self.context.get('course') is None:
         self.context['course'] = get_course_by_id(self.instance.context_key)
     return self.context['course']
Пример #3
0
def save_display_name(apps, schema_editor):
    '''
    Add override for `display_name` for CCX courses that don't have one yet.
    '''
    CcxFieldOverride = apps.get_model('ccx', 'CcxFieldOverride')
    CustomCourseForEdX = apps.get_model('ccx', 'CustomCourseForEdX')

    # Build list of CCX courses that don't have an override for `display_name` yet
    ccx_display_name_present_ids = list(
        CcxFieldOverride.objects.filter(field='display_name').values_list(
            'ccx__id', flat=True))
    ccx_list = CustomCourseForEdX.objects.exclude(
        id__in=ccx_display_name_present_ids)

    # Create `display_name` overrides for these CCX courses
    for ccx in ccx_list:
        try:
            course = get_course_by_id(ccx.course_id, depth=None)
        except Http404:
            log.error(
                "Root course %s not found. Can't create display_name override for %s.",
                ccx.course_id, ccx.display_name)
            continue
        display_name = course.fields['display_name']
        display_name_json = display_name.to_json(ccx.display_name)
        serialized_display_name = json.dumps(display_name_json)

        CcxFieldOverride.objects.get_or_create(
            ccx=ccx,
            location=course.location,
            field='display_name',
            defaults={'value': serialized_display_name},
        )
def remove_master_course_staff_from_ccx_for_existing_ccx(apps, schema_editor):
    """
    Remove all staff and instructors of master course from respective CCX(s).

    Arguments:
        apps (Applications): Apps in edX platform.
        schema_editor (SchemaEditor): For editing database schema i.e create, delete field (column)

    """
    CustomCourseForEdX = apps.get_model("ccx", "CustomCourseForEdX")
    list_ccx = CustomCourseForEdX.objects.all()
    for ccx in list_ccx:
        if not ccx.course_id or ccx.course_id.deprecated:
            # prevent migration for deprecated course ids or invalid ids.
            continue
        ccx_locator = CCXLocator.from_course_locator(ccx.course_id,
                                                     str(ccx.id))
        try:
            course = get_course_by_id(ccx.course_id)
            remove_master_course_staff_from_ccx(course,
                                                ccx_locator,
                                                ccx.display_name,
                                                send_email=False)
        except Http404:
            log.warning(
                "Unable to remove instructors and staff of master course %s from ccx %s.",
                ccx.course_id, ccx_locator)
Пример #5
0
 def __init__(self, course_key, request, username=''):
     self.request = request
     self.overview = course_detail(
         self.request,
         username or self.request.user.username,
         course_key,
     )
     # We must compute course load access *before* setting up masquerading,
     # else course staff (who are not enrolled) will not be able view
     # their course from the perspective of a learner.
     self.load_access = check_course_access(
         self.overview,
         self.request.user,
         'load',
         check_if_enrolled=True,
         check_if_authenticated=True,
     )
     self.original_user_is_staff = has_access(self.request.user, 'staff', self.overview).has_access
     self.original_user_is_global_staff = self.request.user.is_staff
     self.course_key = course_key
     self.course = get_course_by_id(self.course_key)
     self.course_masquerade, self.effective_user = setup_masquerade(
         self.request,
         course_key,
         staff_access=self.original_user_is_staff,
     )
     self.request.user = self.effective_user
     self.is_staff = has_access(self.effective_user, 'staff', self.overview).has_access
     self.enrollment_object = CourseEnrollment.get_enrollment(self.effective_user, self.course_key,
                                                              select_related=['celebration', 'user__celebration'])
     self.can_view_legacy_courseware = courseware_legacy_is_visible(
         course_key=course_key,
         is_global_staff=self.original_user_is_global_staff,
     )
Пример #6
0
 def test_post_list(self):
     """
     Test the creation of a CCX
     """
     outbox = self.get_outbox()
     data = {
         'master_course_id': self.master_course_key_str,
         'max_students_allowed': 111,
         'display_name': 'CCX Test Title',
         'coach_email': self.coach.email,
         'course_modules': self.master_course_chapters[0:1]
     }
     resp = self.client.post(self.list_url, data, format='json', HTTP_AUTHORIZATION=self.auth)
     assert resp.status_code == status.HTTP_201_CREATED
     # check if the response has at least the same data of the request
     for key, val in data.items():
         assert resp.data.get(key) == val
     assert 'ccx_course_id' in resp.data
     # check that the new CCX actually exists
     course_key = CourseKey.from_string(resp.data.get('ccx_course_id'))
     ccx_course = CustomCourseForEdX.objects.get(pk=course_key.ccx)
     assert str(CCXLocator.from_course_locator(ccx_course.course.id, ccx_course.id)) ==\
            resp.data.get('ccx_course_id')
     # check that the coach user has coach role on the master course
     coach_role_on_master_course = CourseCcxCoachRole(self.master_course_key)
     assert coach_role_on_master_course.has_user(self.coach)
     # check that the coach has been enrolled in the ccx
     ccx_course_object = get_course_by_id(course_key)
     assert CourseEnrollment.objects.filter(course_id=ccx_course_object.id, user=self.coach).exists()
     # check that an email has been sent to the coach
     assert len(outbox) == 1
     assert self.coach.email in outbox[0].recipients()
Пример #7
0
def get_group_names_by_id(
        course_discussion_settings: CourseDiscussionSettings
) -> Dict[str, str]:
    """
    Creates of a dict of group_id to learner-facing group names, for the division_scheme
    in use as specified by course_discussion_settings.
    Args:
        course_discussion_settings: CourseDiscussionSettings model instance

    Returns: dict of group_id to learner-facing group names. If no division_scheme
    is in use, returns an empty dict.
    """
    division_scheme = get_course_division_scheme(course_discussion_settings)
    course_key = course_discussion_settings.course_id
    if division_scheme == CourseDiscussionSettings.COHORT:
        return get_cohort_names(get_course_by_id(course_key))
    elif division_scheme == CourseDiscussionSettings.ENROLLMENT_TRACK:
        # We negate the group_ids from dynamic partitions so that they will not conflict
        # with cohort IDs (which are an auto-incrementing integer field, starting at 1).
        return {
            -1 * group.id: group.name
            for group in _get_enrollment_track_groups(course_key)
        }
    else:
        return {}
Пример #8
0
 def test_patch_detail(self):
     """
     Test for successful patch
     """
     outbox = self.get_outbox()
     # create a new coach
     new_coach = AdminFactory.create()
     data = {
         'max_students_allowed': 111,
         'display_name': 'CCX Title',
         'coach_email': new_coach.email
     }
     resp = self.client.patch(self.detail_url, data, format='json', HTTP_AUTHORIZATION=self.auth)
     assert resp.status_code == status.HTTP_204_NO_CONTENT
     ccx_from_db = CustomCourseForEdX.objects.get(id=self.ccx.id)
     assert ccx_from_db.max_student_enrollments_allowed == data['max_students_allowed']
     assert ccx_from_db.display_name == data['display_name']
     assert ccx_from_db.coach.email == data['coach_email']
     # check that the coach user has coach role on the master course
     coach_role_on_master_course = CourseCcxCoachRole(self.master_course_key)
     assert coach_role_on_master_course.has_user(new_coach)
     # check that the coach has been enrolled in the ccx
     ccx_course_object = get_course_by_id(self.ccx_key)
     assert CourseEnrollment.objects.filter(course_id=ccx_course_object.id, user=new_coach).exists()
     # check that an email has been sent to the coach
     assert len(outbox) == 1
     assert new_coach.email in outbox[0].recipients()
def revert_ccx_staff_to_coaches(apps, schema_editor):
    """
    Modify all staff on CCX courses so that they no longer have the staff role
    on the course that they coach.

    Arguments:
        apps (Applications): Apps in edX platform.
        schema_editor (SchemaEditor): For editing database schema (unused)

    """
    CustomCourseForEdX = apps.get_model('ccx', 'CustomCourseForEdX')
    db_alias = schema_editor.connection.alias
    if not db_alias == 'default':
        return
    list_ccx = CustomCourseForEdX.objects.using(db_alias).all()
    for ccx in list_ccx:
        ccx_locator = CCXLocator.from_course_locator(ccx.course_id,
                                                     str(ccx.id))
        try:
            course = get_course_by_id(ccx_locator)
        except Http404:
            log.error('Could not migrate access for CCX course: %s',
                      str(ccx_locator))
        else:
            coach = User.objects.get(id=ccx.coach.id)
            allow_access(course, coach, 'ccx_coach', send_email=False)
            revoke_access(course, coach, 'staff', send_email=False)
            log.info(
                'The CCX coach of CCX %s has been switched from "Staff" to "CCX Coach".',
                str(ccx_locator))
def change_existing_ccx_coaches_to_staff(apps, schema_editor):
    """
    Modify all coaches of CCX courses so that they have the staff role on the
    CCX course they coach, but retain the CCX Coach role on the parent course.

    Arguments:
        apps (Applications): Apps in edX platform.
        schema_editor (SchemaEditor): For editing database schema (unused)

    """
    CustomCourseForEdX = apps.get_model('ccx', 'CustomCourseForEdX')
    db_alias = schema_editor.connection.alias
    if not db_alias == 'default':
        # This migration is not intended to run against the student_module_history database and
        # will fail if it does. Ensure that it'll only run against the default database.
        return
    list_ccx = CustomCourseForEdX.objects.using(db_alias).all()
    for ccx in list_ccx:
        ccx_locator = CCXLocator.from_course_locator(ccx.course_id,
                                                     str(ccx.id))
        try:
            course = get_course_by_id(ccx_locator)
        except Http404:
            log.error('Could not migrate access for CCX course: %s',
                      str(ccx_locator))
        else:
            coach = User.objects.get(id=ccx.coach.id)
            allow_access(course, coach, 'staff', send_email=False)
            revoke_access(course, coach, 'ccx_coach', send_email=False)
            log.info(
                'The CCX coach of CCX %s has been switched from "CCX Coach" to "Staff".',
                str(ccx_locator))
Пример #11
0
 def _update_plugin_configuration(
     self,
     instance: DiscussionsConfiguration,
     validated_data: dict,
 ) -> DiscussionsConfiguration:
     """
     Create/update legacy provider settings
     """
     updated_provider_type = validated_data.get(
         'provider_type') or instance.provider_type
     will_support_legacy = bool(updated_provider_type == 'legacy')
     if will_support_legacy:
         course_key = instance.context_key
         course = get_course_by_id(course_key)
         legacy_settings = LegacySettingsSerializer(
             course,
             context={
                 'user_id': self.context['user_id'],
             },
             data=validated_data.get('plugin_configuration', {}),
         )
         if legacy_settings.is_valid(raise_exception=True):
             legacy_settings.save()
         instance.plugin_configuration = {}
     else:
         instance.plugin_configuration = validated_data.get(
             'plugin_configuration') or {}
     return instance
Пример #12
0
    def to_representation(self, instance: DiscussionsConfiguration) -> dict:
        """
        Serialize data into a dictionary, to be used as a response
        """
        course_key = instance.context_key
        active_provider = instance.provider_type
        provider_type = self.context.get('provider_type') or active_provider
        payload = super().to_representation(instance)
        course_pii_sharing_allowed = get_lti_pii_sharing_state_for_course(course_key)

        # LTI configuration is only stored for the active provider.
        if provider_type == active_provider:
            lti_configuration = LtiSerializer(instance=instance.lti_configuration)
            lti_configuration_data = lti_configuration.data
            plugin_configuration = instance.plugin_configuration
        else:
            lti_configuration_data = {}
            plugin_configuration = {}

        course = get_course_by_id(course_key)
        if provider_type in [Provider.LEGACY, Provider.OPEN_EDX]:
            legacy_settings = LegacySettingsSerializer(course, data=plugin_configuration)
            if legacy_settings.is_valid(raise_exception=True):
                plugin_configuration = legacy_settings.data
            if provider_type == Provider.OPEN_EDX:
                plugin_configuration.update({
                    "group_at_subsection": instance.plugin_configuration.get("group_at_subsection", False)
                })
        lti_configuration_data.update({'pii_sharing_allowed': course_pii_sharing_allowed})
        payload.update({
            'provider_type': provider_type,
            'lti_configuration': lti_configuration_data,
            'plugin_configuration': plugin_configuration,
        })
        return payload
Пример #13
0
    def __init__(self, course_key, request, username=''):
        self.request = request
        self.overview = course_detail(
            self.request,
            username or self.request.user.username,
            course_key,
        )

        self.original_user_is_staff = has_access(self.request.user, 'staff',
                                                 self.overview).has_access
        self.original_user_is_global_staff = self.request.user.is_staff
        self.course_key = course_key
        self.course = get_course_by_id(self.course_key)
        self.course_masquerade, self.effective_user = setup_masquerade(
            self.request,
            course_key,
            staff_access=self.original_user_is_staff,
        )
        self.request.user = self.effective_user
        self.is_staff = has_access(self.effective_user, 'staff',
                                   self.overview).has_access
        self.enrollment_object = CourseEnrollment.get_enrollment(
            self.effective_user,
            self.course_key,
            select_related=['celebration', 'user__celebration'])
        self.can_view_legacy_courseware = courseware_legacy_is_visible(
            course_key=course_key,
            is_global_staff=self.original_user_is_global_staff,
        )
Пример #14
0
    def handle(self, *args, **options):
        course = get_course_by_id(CourseKey.from_string(options['course']))

        print(
            'Warning: this command directly edits the list of course tabs in mongo.'
        )
        print('Tabs before any changes:')
        print_course(course)

        try:
            if options['delete']:
                num = int(options['delete'][0])
                if num < 3:
                    raise CommandError("Tabs 1 and 2 cannot be changed.")

                if query_yes_no(f'Deleting tab {num} Confirm?', default='no'):
                    tabs.primitive_delete(course,
                                          num - 1)  # -1 for 0-based indexing
            elif options['insert']:
                num, tab_type, name = options['insert']
                num = int(num)
                if num < 3:
                    raise CommandError("Tabs 1 and 2 cannot be changed.")

                if query_yes_no(
                        f'Inserting tab {num} "{tab_type}" "{name}" Confirm?',
                        default='no'):
                    tabs.primitive_insert(course, num - 1, tab_type,
                                          name)  # -1 as above
        except ValueError as e:
            # Cute: translate to CommandError so the CLI error prints nicely.
            raise CommandError(e)  # lint-amnesty, pylint: disable=raise-missing-from
Пример #15
0
 def user_has_passing_grade(self):
     """ Returns a boolean on if the effective_user has a passing grade in the course """
     if not self.effective_user.is_anonymous:
         course = get_course_by_id(self.course_key)
         user_grade = CourseGradeFactory().read(self.effective_user, course).percent
         return user_grade >= course.lowest_passing_grade
     return False
Пример #16
0
    def setUp(self):
        """
        Set up tests
        """
        super().setUp()

        self.ccx = ccx = CustomCourseForEdX(course_id=self.course.id,
                                            display_name='Test CCX',
                                            coach=AdminFactory.create())
        ccx.save()

        patch = mock.patch('lms.djangoapps.ccx.overrides.get_current_ccx')
        self.get_ccx = get_ccx = patch.start()
        get_ccx.return_value = ccx
        self.addCleanup(patch.stop)

        self.addCleanup(RequestCache.clear_all_namespaces)

        inject_field_overrides(iter_blocks(ccx.course), self.course,
                               AdminFactory.create())

        self.ccx_key = CCXLocator.from_course_locator(self.course.id, ccx.id)
        self.ccx_course = get_course_by_id(self.ccx_key, depth=None)

        def cleanup_provider_classes():
            """
            After everything is done, clean up by un-doing the change to the
            OverrideFieldData object that is done during the wrap method.
            """
            OverrideFieldData.provider_classes = None

        self.addCleanup(cleanup_provider_classes)
Пример #17
0
 def to_representation(self, instance: DiscussionsConfiguration) -> dict:
     """
     Serialize data into a dictionary, to be used as a response
     """
     payload = super().to_representation(instance)
     lti_configuration_data = {}
     supports_lti = instance.supports('lti')
     if supports_lti:
         lti_configuration = LtiSerializer(instance.lti_configuration)
         lti_configuration_data = lti_configuration.data
     provider_type = instance.provider_type or DEFAULT_PROVIDER_TYPE
     plugin_configuration = instance.plugin_configuration
     if provider_type == 'legacy':
         course_key = instance.context_key
         course = get_course_by_id(course_key)
         legacy_settings = LegacySettingsSerializer(
             course,
             data=plugin_configuration,
         )
         if legacy_settings.is_valid(raise_exception=True):
             plugin_configuration = legacy_settings.data
     features_list = [feature.value for feature in Features]
     payload.update({
         'features': features_list,
         'lti_configuration': lti_configuration_data,
         'plugin_configuration': plugin_configuration,
         'providers': {
             'active': provider_type or DEFAULT_PROVIDER_TYPE,
             'available': PROVIDER_FEATURE_MAP,
         },
     })
     return payload
Пример #18
0
 def set_enabled(cls, course_key: CourseKey, enabled: bool, user: '******') -> bool:
     """
     Enable/disable edxnotes in the modulestore.
     """
     course = get_course_by_id(course_key)
     course.edxnotes = enabled
     modulestore().update_item(course, user.id)
     return enabled
Пример #19
0
 def certificate_data(self):
     """
     Returns certificate data if the effective_user is enrolled.
     Note: certificate data can be None depending on learner and/or course state.
     """
     course = get_course_by_id(self.course_key)
     if self.enrollment_object:
         return get_cert_data(self.effective_user, course, self.enrollment_object.mode)
Пример #20
0
 def set_enabled(cls, course_key: CourseKey, enabled: bool, user: '******') -> bool:
     """
     The progress course enabled/disabled status is stored in the course module.
     """
     course = get_course_by_id(course_key)
     course.hide_progress_tab = not enabled
     modulestore().update_item(course, user.id)
     return enabled
Пример #21
0
 def set_enabled(cls, course_key: CourseKey, enabled: bool, user: '******') -> bool:
     """
     Update calculator enabled status in modulestore.
     """
     course = get_course_by_id(course_key)
     course.show_calculator = enabled
     modulestore().update_item(course, user.id)
     return enabled
Пример #22
0
def get_valid_course(course_id, is_ccx=False, advanced_course_check=False):
    """
    Helper function used to validate and get a course from a course_id string.
    It works with both master and ccx course id.

    Args:
        course_id (str): A string representation of a Master or CCX Course ID.
        is_ccx (bool): Flag to perform the right validation
        advanced_course_check (bool): Flag to perform extra validations for the master course

    Returns:
        tuple: a tuple of course_object, course_key, error_code, http_status_code
    """
    if course_id is None:
        # the ccx detail view cannot call this function with a "None" value
        # so the following `error_code` should be never used, but putting it
        # to avoid a `NameError` exception in case this function will be used
        # elsewhere in the future
        error_code = 'course_id_not_provided'
        if not is_ccx:
            log.info('Master course ID not provided')
            error_code = 'master_course_id_not_provided'

        return None, None, error_code, status.HTTP_400_BAD_REQUEST

    try:
        course_key = CourseKey.from_string(course_id)
    except InvalidKeyError:
        log.info('Course ID string "%s" is not valid', course_id)
        return None, None, 'course_id_not_valid', status.HTTP_400_BAD_REQUEST

    if not is_ccx:
        try:
            course_object = get_course_by_id(course_key)
        except Http404:
            log.info('Master Course with ID "%s" not found', course_id)
            return None, None, 'course_id_does_not_exist', status.HTTP_404_NOT_FOUND
        if advanced_course_check:
            if course_object.id.deprecated:
                return None, None, 'deprecated_master_course_id', status.HTTP_400_BAD_REQUEST
            if not course_object.enable_ccx:
                return None, None, 'ccx_not_enabled_for_master_course', status.HTTP_403_FORBIDDEN
        return course_object, course_key, None, None
    else:
        try:
            ccx_id = course_key.ccx
        except AttributeError:
            log.info('Course ID string "%s" is not a valid CCX ID', course_id)
            return None, None, 'course_id_not_valid_ccx_id', status.HTTP_400_BAD_REQUEST
        # get the master_course key
        master_course_key = course_key.to_course_locator()
        try:
            ccx_course = CustomCourseForEdX.objects.get(
                id=ccx_id, course_id=master_course_key)
            return ccx_course, course_key, None, None
        except CustomCourseForEdX.DoesNotExist:
            log.info('CCX Course with ID "%s" not found', course_id)
            return None, None, 'ccx_course_id_does_not_exist', status.HTTP_404_NOT_FOUND
Пример #23
0
def move_to_verified_cohort(sender, instance, **kwargs):  # pylint: disable=unused-argument
    """
    If the learner has changed modes, update assigned cohort iff the course is using
    the Automatic Verified Track Cohorting MVP feature.
    """
    course_key = instance.course_id
    verified_cohort_enabled = VerifiedTrackCohortedCourse.is_verified_track_cohort_enabled(
        course_key)
    verified_cohort_name = VerifiedTrackCohortedCourse.verified_cohort_name_for_course(
        course_key)

    if verified_cohort_enabled and (instance.mode != instance._old_mode):  # pylint: disable=protected-access
        if not is_course_cohorted(course_key):
            log.error(
                "Automatic verified cohorting enabled for course '%s', but course is not cohorted.",
                course_key)
        else:
            course = get_course_by_id(course_key)
            existing_manual_cohorts = get_course_cohorts(
                course, assignment_type=CourseCohort.MANUAL)
            if any(cohort.name == verified_cohort_name
                   for cohort in existing_manual_cohorts):
                # Get a random cohort to use as the default cohort (for audit learners).
                # Note that calling this method will create a "Default Group" random cohort if no random
                # cohort yet exist.
                random_cohort = get_random_cohort(course_key)
                args = {
                    'course_id': str(course_key),
                    'user_id': instance.user.id,
                    'verified_cohort_name': verified_cohort_name,
                    'default_cohort_name': random_cohort.name
                }
                log.info(
                    "Queuing automatic cohorting for user '%s' in course '%s' "
                    "due to change in enrollment mode from '%s' to '%s'.",
                    instance.user.id,
                    course_key,
                    instance._old_mode,
                    instance.mode  # pylint: disable=protected-access
                )

                # Do the update with a 3-second delay in hopes that the CourseEnrollment transaction has been
                # completed before the celery task runs. We want a reasonably short delay in case the learner
                # immediately goes to the courseware.
                sync_cohort_with_mode.apply_async(kwargs=args, countdown=3)

                # In case the transaction actually was not committed before the celery task runs,
                # run it again after 5 minutes. If the first completed successfully, this task will be a no-op.
                sync_cohort_with_mode.apply_async(kwargs=args, countdown=300)
            else:
                log.error(
                    "Automatic verified cohorting enabled for course '%s', "
                    "but verified cohort named '%s' does not exist.",
                    course_key,
                    verified_cohort_name,
                )
Пример #24
0
 def is_enabled(cls, request, course_key):
     """
     Returns True if the user should be shown course updates for this course.
     """
     if DISABLE_UNIFIED_COURSE_TAB_FLAG.is_enabled(course_key):
         return False
     if not CourseEnrollment.is_enrolled(request.user, course_key):
         return False
     course = get_course_by_id(course_key)
     return CourseUpdatesFragmentView.has_updates(request, course)
Пример #25
0
def get_legacy_discussion_settings(course_key):  # lint-amnesty, pylint: disable=missing-function-docstring

    try:
        course_cohort_settings = CourseCohortsSettings.objects.get(course_id=course_key)
        return {
            'is_cohorted': course_cohort_settings.is_cohorted,
            'cohorted_discussions': course_cohort_settings.cohorted_discussions,
            'always_cohort_inline_discussions': course_cohort_settings.always_cohort_inline_discussions
        }
    except CourseCohortsSettings.DoesNotExist:
        course = get_course_by_id(course_key)
        return _get_cohort_settings_from_modulestore(course)
Пример #26
0
    def setUp(self):
        """
        Set up the course and user context
        """
        super().setUp()

        store = modulestore()
        course_items = import_course_from_xml(store, self.user.id, TEST_DATA_DIR, ['toy'])
        course_key = course_items[0].id
        self.course = get_course_by_id(course_key)
        self.addCleanup(set_current_request, None)
        self.request = get_mock_request(UserFactory.create())
Пример #27
0
def un_flag_abuse_for_comment(request, course_id, comment_id):
    """
    given a course_id and comment id, unflag comment for abuse
    ajax only
    """
    user = cc.User.from_django_user(request.user)
    course_key = CourseKey.from_string(course_id)
    course = get_course_by_id(course_key)
    remove_all = bool(
        has_permission(request.user, 'openclose_thread', course_key)
        or has_access(request.user, 'staff', course))
    comment = cc.Comment.find(comment_id)
    comment.unFlagAbuse(user, comment, remove_all)
    return JsonResponse(prepare_content(comment.to_dict(), course_key))
Пример #28
0
 def set_enabled(cls, course_key: CourseKey, enabled: bool, user: '******') -> bool:
     """
     Enable/disable edxnotes in the modulestore.
     """
     course = get_course_by_id(course_key)
     course.edxnotes = enabled
     if enabled:
         notes_tab = CourseTabList.get_tab_by_id(course.tabs, 'edxnotes')
         if notes_tab is None:
             # If the course doesn't already have the notes tab, add it.
             notes_tab = CourseTab.load("edxnotes")
             course.tabs.append(notes_tab)
     modulestore().update_item(course, user.id)
     return enabled
Пример #29
0
def un_flag_abuse_for_thread(request, course_id, thread_id):
    """
    given a course id and thread id, remove abuse flag for this thread
    ajax only
    """
    user = cc.User.from_django_user(request.user)
    course_key = CourseKey.from_string(course_id)
    course = get_course_by_id(course_key)
    thread = cc.Thread.find(thread_id)
    remove_all = bool(
        has_permission(request.user, 'openclose_thread', course_key)
        or has_access(request.user, 'staff', course))
    thread.unFlagAbuse(user, thread, remove_all)

    return JsonResponse(prepare_content(thread.to_dict(), course_key))
Пример #30
0
    def set_enabled(cls, course_key: CourseKey, enabled: bool,
                    user: User) -> bool:
        """
        Returns the enabled status of teams.
        Args:
            course_key (CourseKey): The course for which to set the status of teams
            enabled (bool): The new satus for the app.
            user (User): The user performing the operation

        Returns:
            (bool): the new status of the app
        """
        course = get_course_by_id(course_key)
        course.teams_configuration.is_enabled = enabled
        modulestore().update_item(course, user.id)
        return enabled