Beispiel #1
0
    def get(self, request, course_key_str, format=None):  # lint-amnesty, pylint: disable=redefined-builtin, unused-argument
        """
        The CourseOutline, customized for a given user.

        TODO: Swagger docs of API. For an exemplar to imitate, see:
        https://github.com/edx/edx-platform/blob/master/lms/djangoapps/program_enrollments/rest_api/v1/views.py#L792-L820
        """
        # Translate input params and do course key validation (will cause HTTP
        # 400 error if an invalid CourseKey was entered, instead of 404).
        course_key = validate_course_key(course_key_str)
        at_time = datetime.now(timezone.utc)

        if not can_call_public_api(request.user, course_key):
            raise PermissionDenied()

        try:
            # Grab the user's outline and send our response...
            outline_user = self._determine_user(request)
            user_course_outline_details = get_user_course_outline_details(
                course_key, outline_user, at_time)
        except CourseOutlineData.DoesNotExist as does_not_exist_err:
            raise NotFound() from does_not_exist_err

        serializer = self.UserCourseOutlineDataSerializer(
            user_course_outline_details)
        return Response(serializer.data)
Beispiel #2
0
    def update_configuration_data(request, course_key_string):
        """
        Update discussion configuration for the course based on data in the request.
        Args:
            request (Request): a DRF request
            course_key_string (str): a course key string

        Returns:
            Dict: modified course configuration data
        """
        course_key = validate_course_key(course_key_string)
        configuration = DiscussionsConfiguration.get(course_key)
        course = CourseOverview.get_from_id(course_key)
        serializer = DiscussionsConfigurationSerializer(
            configuration,
            context={
                'user_id': request.user.id,
            },
            data=request.data,
            partial=True,
        )
        if serializer.is_valid(raise_exception=True):
            new_provider_type = serializer.validated_data.get(
                'provider_type', None)
            if new_provider_type is not None and new_provider_type != configuration.provider_type:
                check_course_permissions(course, request.user,
                                         'change_provider')

            serializer.save()
        return serializer.data
Beispiel #3
0
    def get(self, request, course_key_str, format=None):  # lint-amnesty, pylint: disable=redefined-builtin, unused-argument
        """
        The CourseOutline, customized for a given user.

        TODO: Swagger docs of API. For an exemplar to imitate, see:
        https://github.com/edx/edx-platform/blob/master/lms/djangoapps/program_enrollments/rest_api/v1/views.py#L792-L820
        """
        # Translate input params and do course key validation (will cause HTTP
        # 400 error if an invalid CourseKey was entered, instead of 404).
        course_key = validate_course_key(course_key_str)
        at_time = datetime.now(timezone.utc)

        # Get target user (and override request user for the benefit of any waffle checks)
        request.user = self._determine_user(request, course_key)

        try:
            # Grab the user's outline and send our response...
            user_course_outline_details = get_user_course_outline_details(
                course_key, request.user, at_time)
        except CourseOutlineData.DoesNotExist as does_not_exist_err:
            if not request.user.id:
                # Outline is private or doesn't exist. But don't leak whether a course exists or not to anonymous
                # users with a 404 - give a 401 instead. This mostly prevents drive-by crawlers from creating a bunch
                # of 404 errors in your error report dashboard.
                raise NotAuthenticated() from does_not_exist_err
            raise NotFound() from does_not_exist_err

        serializer = self.UserCourseOutlineDataSerializer(
            user_course_outline_details)
        return Response(serializer.data)
Beispiel #4
0
 def has_permission(self, request, view):
     """
     Check if the user has write access to studio.
     """
     user = request.user
     course_key_string = view.kwargs.get("course_id")
     course_key = validate_course_key(course_key_string)
     return has_studio_write_access(user, course_key)
Beispiel #5
0
 def get(self, request, course_key_string: str, **_kwargs) -> Response:
     """
     Handle HTTP/GET requests
     """
     course_key = validate_course_key(course_key_string)
     configuration = DiscussionsConfiguration.get(course_key)
     serializer = DiscussionsConfigurationSerializer(configuration)
     return Response(serializer.data)
Beispiel #6
0
    def has_permission(self, request, view):
        course_key_string = view.kwargs.get('course_id')
        course_key = validate_course_key(course_key_string)

        if GlobalStaff().has_user(request.user):
            return True

        return (CourseInstructorRole(course_key).has_user(request.user)
                or CourseStaffRole(course_key).has_user(request.user))
Beispiel #7
0
 def has_permission(self, request, view):
     """
     Check if user has global or course staff permission
     """
     user = request.user
     if user.is_staff:
         return True
     course_key_string = view.kwargs.get('course_key_string')
     course_key = validate_course_key(course_key_string)
     return CourseStaffRole(course_key, ).has_user(request.user)
Beispiel #8
0
 def post(self, request, course_key_string: str, **_kwargs) -> Response:
     """
     Handle HTTP/POST requests
     """
     course_key = validate_course_key(course_key_string)
     configuration = DiscussionsConfiguration.get(course_key)
     serializer = DiscussionsConfigurationSerializer(
         configuration,
         context={
             'user_id': request.user.id,
         },
         data=request.data,
         partial=True,
     )
     if serializer.is_valid(raise_exception=True):
         serializer.save()
     return Response(serializer.data)
Beispiel #9
0
    def get(self, request, course_key_str, format=None):  # lint-amnesty, pylint: disable=redefined-builtin, unused-argument
        """
        The CourseOutline, customized for a given user.

        TODO: Swagger docs of API. For an exemplar to imitate, see:
        https://github.com/edx/edx-platform/blob/master/lms/djangoapps/program_enrollments/rest_api/v1/views.py#L792-L820
        """
        # Translate input params and do course key validation (will cause HTTP
        # 400 error if an invalid CourseKey was entered, instead of 404).
        course_key = validate_course_key(course_key_str)
        at_time = datetime.now(timezone.utc)

        # Get target user (and override request user for the benefit of any waffle checks)
        request.user = self._determine_user(request, course_key)

        # We use can_call_public_api to slowly roll this feature out, and be
        # able to turn it off for a course. But it's not really a permissions
        # thing in that it doesn't give them elevated access. If I had it to do
        # over again, I'd call it something else, but all this code is supposed
        # to go away when rollout is completed anyway.
        #
        # The force_on param just means, "Yeah, never mind whether you're turned
        # on by default for the purposes of the MFE. I want to see production
        # data using this API." The MFE should _never_ pass this parameter. It's
        # just a way to peek at the API while it's techincally dark for rollout
        # purposes. TODO: REMOVE THIS PARAM AFTER FULL ROLLOUT OF THIS FEATURE.
        force_on = request.GET.get("force_on")
        if (not force_on) and (not can_call_public_api(course_key)):
            raise PermissionDenied()

        try:
            # Grab the user's outline and send our response...
            user_course_outline_details = get_user_course_outline_details(
                course_key, request.user, at_time)
        except CourseOutlineData.DoesNotExist as does_not_exist_err:
            if not request.user.id:
                # Outline is private or doesn't exist. But don't leak whether a course exists or not to anonymous
                # users with a 404 - give a 401 instead. This mostly prevents drive-by crawlers from creating a bunch
                # of 404 errors in your error report dashboard.
                raise NotAuthenticated() from does_not_exist_err
            raise NotFound() from does_not_exist_err

        serializer = self.UserCourseOutlineDataSerializer(
            user_course_outline_details)
        return Response(serializer.data)
Beispiel #10
0
    def post(self, request, course_key_string: str, **_kwargs) -> Response:
        """
        Handle HTTP/POST requests
        """
        course_key = validate_course_key(course_key_string)
        configuration = DiscussionsConfiguration.get(course_key)
        course = CourseOverview.get_from_id(course_key)
        serializer = DiscussionsConfigurationSerializer(
            configuration,
            context={
                'user_id': request.user.id,
            },
            data=request.data,
            partial=True,
        )
        if serializer.is_valid(raise_exception=True):
            new_provider_type = serializer.validated_data.get('provider_type', None)
            if new_provider_type is not None and new_provider_type != configuration.provider_type:
                check_course_permissions(course, request.user, 'change_provider')

            serializer.save()
        return Response(serializer.data)
Beispiel #11
0
    def get_provider_data(course_key_string: str) -> Dict:
        """
        Get provider data for specified course
        Args:
            course_key_string (str): course key string

        Returns:
            Dict: course discussion providers
        """
        course_key = validate_course_key(course_key_string)
        configuration = DiscussionsConfiguration.get(course_key)
        hidden_providers = []
        # If the user is currently using the legacy provider, don't show the new provider
        # TODO: Allow switching between legacy and new providers
        if configuration.provider_type == Provider.LEGACY:
            hidden_providers.append(Provider.OPEN_EDX)
        # If the user is currently using the new provider, don't show the legacy provider
        elif configuration.provider_type == Provider.OPEN_EDX:
            hidden_providers.append(Provider.LEGACY)
        else:
            # If this is a new course, or some other provider is selected, the new provider
            # should only show up if the new structure for in context discussions flag is enabled
            if not ENABLE_NEW_STRUCTURE_DISCUSSIONS.is_enabled(course_key):
                hidden_providers.append(Provider.OPEN_EDX)
        serializer = DiscussionsProvidersSerializer({
            'features': [{
                'id': feature.value,
                'feature_support_type': feature.feature_support_type
            } for feature in Features],
            'active':
            configuration.provider_type,
            'available': {
                key: value
                for key, value in AVAILABLE_PROVIDER_MAP.items()
                if key not in hidden_providers
            },
        })
        return serializer.data
Beispiel #12
0
    def get_configuration_data(request: Request,
                               course_key_string: str) -> Dict:
        """
        Get discussions configuration data for the course
        Args:
            request (Request): a DRF request
            course_key_string (str): a course key string

        Returns:
            Dict: Discussion configuration data for the course
        """
        course_key = validate_course_key(course_key_string)
        configuration = DiscussionsConfiguration.get(course_key)
        provider_type = request.query_params.get('provider_id', None)
        if provider_type and provider_type not in AVAILABLE_PROVIDER_MAP:
            raise ValidationError("Unsupported provider type")
        serializer = DiscussionsConfigurationSerializer(configuration,
                                                        context={
                                                            'user_id':
                                                            request.user.id,
                                                            'provider_type':
                                                            provider_type,
                                                        })
        return serializer.data