def test_access_api_can_manage_moderators_update_student_no_group_moderator(
            self):
        """If moderator group doesn't exist user can be updated and group created
        Case for forum created before this feature"""
        update_user = UserFactory()
        api_user = UserFactory(lti_consumer=update_user.lti_consumer)

        lti_context = LTIContextFactory(lti_consumer=update_user.lti_consumer)
        forum = ForumFactory()
        forum.lti_contexts.add(lti_context)
        # Add group student
        lti_context.sync_user_groups(update_user, ["student"])
        # Assign the permission
        assign_perm("can_manage_moderator", api_user, forum, True)
        # Creates the session
        self.client.force_login(api_user, "ashley.auth.backend.LTIBackend")
        session = self.client.session
        session[SESSION_LTI_CONTEXT_ID] = lti_context.id
        session.save()

        # Data to promote user to moderator
        response = self.client.patch(
            f"/api/v1.0/users/{update_user.id}/add_group_moderator/",
            content_type="application/json",
        )
        self.assertEqual(response.status_code, 200)
    def test_access_api_can_manage_moderators_update_student_no_session(self):
        """Users with no session can't update user"""
        update_user = UserFactory()
        api_user = UserFactory(lti_consumer=update_user.lti_consumer)

        lti_context = LTIContextFactory(lti_consumer=update_user.lti_consumer)
        forum = ForumFactory()
        forum.lti_contexts.add(lti_context)

        # Assign student group to user
        lti_context.sync_user_groups(update_user, ["student"])
        # Assign the permission
        assign_perm("can_manage_moderator", api_user, forum, True)
        #
        response = self.client.patch(
            f"/api/v1.0/users/{update_user.id}/add_group_moderator/",
            content_type="application/json",
        )
        self.assertEqual(response.status_code, 403)
        content = json.loads(response.content)
        self.assertEqual(
            content,
            {"detail": "Authentication credentials were not provided."})
        # Create the session and it should work
        self.client.force_login(api_user, "ashley.auth.backend.LTIBackend")
        session = self.client.session
        session[SESSION_LTI_CONTEXT_ID] = lti_context.id
        session.save()
        response = self.client.patch(
            f"/api/v1.0/users/{update_user.id}/add_group_moderator/",
            content_type="application/json",
        )
        self.assertEqual(response.status_code, 200)
Example #3
0
    def test_group_generators(self):
        """Test utilities functions to generate django groups related to a LTIContext"""

        context = LTIContextFactory()
        # Create a django group (corresponding to the "student" role in the LTI context
        # we just created)
        initial_student_group = Group.objects.create(
            name=f"cg:{context.id}:role:student")

        initial_group_count = Group.objects.count()

        # Ensure that the base group name generator respect a specific name pattern
        base_group_name = f"cg:{context.id}"
        self.assertEqual(base_group_name, context.base_group_name)

        base_group = context.get_base_group()
        # Ensure that the base group is created if it does not exist
        self.assertEqual(initial_group_count + 1, Group.objects.count())
        self.assertEqual(base_group_name, base_group.name)

        # Get the django group corresponding to the "student" role.
        role_group_student = context.get_role_group("student")
        # Ensure that the previously created group is returned and no new group is created
        self.assertEqual(initial_student_group, role_group_student)
        self.assertEqual(initial_group_count + 1, Group.objects.count())

        # Get the django group corresponding to the "instructor role
        role_group_instructor = context.get_role_group("instructor")
        # Ensure that the django group is created since it does not exist
        self.assertEqual(initial_group_count + 2, Group.objects.count())
        self.assertEqual(f"{base_group_name}:role:instructor",
                         role_group_instructor.name)
    def test_access_api_update_instructor_patch(self):
        """
        Standard instructor call to patch user is allowed but doesn't change anything,
        as serializer's attributes are read-only.
        """
        # Creates a forum
        user = UserFactory(id=1, public_username="******")
        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
        forum = ForumFactory()
        forum.lti_contexts.add(lti_context)
        lti_context.sync_user_groups(user, ["instructor"])
        assign_perm("can_manage_moderator", user, forum, True)
        # Creates the session
        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        session = self.client.session
        session[SESSION_LTI_CONTEXT_ID] = lti_context.id
        session.save()
        data = {"id": 10, "public_username": "******"}
        response = self.client.patch(
            f"/api/v1.0/users/{user.id}/",
            json.dumps(data),
            content_type="application/json",
        )

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json(), {"id": 1, "public_username": "******"})
Example #5
0
    def test_forum_search_with_unautorized_forum_from_other_lti_context(self):
        """
        Try to search in a forum that is not part of our LTIContext by submitting
        in the search form a forum from another LTIContext.
        """
        user = UserFactory()

        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
        lti_context2 = LTIContextFactory(lti_consumer=user.lti_consumer)
        forum = ForumFactory()
        forum2 = ForumFactory()
        forum.lti_contexts.add(lti_context)
        forum2.lti_contexts.add(lti_context2)

        PostFactory(
            topic=TopicFactory(forum=forum),
            text="Good morning world",
        )

        PostFactory(
            topic=TopicFactory(forum=forum2),
            text="Hello world",
        )
        # Index posts in Elasticsearch
        call_command("rebuild_index", interactive=False)

        # Connects and gets acces to the forum
        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        assign_perm("can_read_forum", user, forum)
        assign_perm("can_read_forum", user, forum2)
        session = self.client.session
        session[SESSION_LTI_CONTEXT_ID] = lti_context.id
        session.save()

        form = SearchForm(user=user, lti_context=lti_context)

        # Checks that only the forum that is allowed is proposed as choice
        self.assertEqual(
            form.fields["search_forums"].choices,
            [(forum.id, "{} {}".format("-" * forum.margin_level, forum.name))],
        )
        # Despite that, we force the request on the forum that is not allowed
        response = self.client.get(
            f"/forum/search/?q=world&search_forums={forum2.id}")
        self.assertEqual(response.status_code, 200)
        # Controls that we get an error and the search is not executed
        self.assertContains(
            response,
            f"Select a valid choice. {forum2.id} is not one of the available choices.",
            html=True,
        )

        # Valid request, we search on the forum that is allowed, we get only one result
        # as forum2 is ignored
        response = self.client.get(
            f"/forum/search/?q=world&search_forums={forum.id}")
        self.assertEqual(response.status_code, 200)
        self.assertContains(response,
                            "Your search has returned <b>1</b> result",
                            html=True)
    def test_forum_list(self):
        user = UserFactory()
        lti_context_a = LTIContextFactory(lti_consumer=user.lti_consumer)
        lti_context_b = LTIContextFactory(lti_consumer=user.lti_consumer)

        # Create 2 forums for context A
        forum_a1 = ForumFactory(name="Forum A1")
        forum_a1.lti_contexts.add(lti_context_a)
        forum_a2 = ForumFactory(name="Forum A2")
        forum_a2.lti_contexts.add(lti_context_a)
        # Create 2 forums for context B
        forum_b1 = ForumFactory(name="Forum B1")
        forum_b1.lti_contexts.add(lti_context_b)
        forum_b2 = ForumFactory(name="Forum B2")
        forum_b2.lti_contexts.add(lti_context_b)

        # Grant read-only access for forums A1, A2 and B1 to our user
        assign_perm("can_see_forum", user, forum_a1, True)
        assign_perm("can_read_forum", user, forum_a1, True)
        assign_perm("can_see_forum", user, forum_a2, True)
        assign_perm("can_read_forum", user, forum_a2, True)
        assign_perm("can_see_forum", user, forum_b1, True)
        assign_perm("can_read_forum", user, forum_b1, True)

        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        session = self.client.session

        # Make a request to get the forum list, with an empty session
        response = self.client.get("/forum/")
        # We should see all forums we have access to
        self.assertContains(response, "Forum A1")
        self.assertContains(response, "Forum A2")
        self.assertContains(response, "Forum B1")
        self.assertNotContains(response, "Forum B2")

        # Update the client session to limit the user to the LTIContext A
        # Make a request to get he forum list again
        session[SESSION_LTI_CONTEXT_ID] = lti_context_a.id
        session.save()
        response = self.client.get("/forum/")

        # We should see only forums related to LTIContext A
        self.assertContains(response, "Forum A1")
        self.assertContains(response, "Forum A2")
        self.assertNotContains(response, "Forum B1")
        self.assertNotContains(response, "Forum B2")

        # Update the client session to limit the user to the LTIContext B
        # Make a request to get he forum list again
        session[SESSION_LTI_CONTEXT_ID] = lti_context_b.id
        session.save()
        response = self.client.get("/forum/")

        # We should see only forum B1
        self.assertNotContains(response, "Forum A1")
        self.assertNotContains(response, "Forum A2")
        self.assertContains(response, "Forum B1")
        self.assertNotContains(response, "Forum B2")
    def setUp(self):
        super().setUp()
        # Setup
        # Create consumer, context and user
        self.lti_consumer = LTIConsumerFactory()
        self.context = LTIContextFactory(lti_consumer=self.lti_consumer)

        # Create forum and add context
        self.forum = ForumFactory(name="Forum")
        self.forum.lti_contexts.add(self.context)
    def test_get_readable_forums(self):
        """
        The get_readable_forums() function should filter the results according
        to the LTIContext of the user, if available.
        """
        user = UserFactory()
        lti_context_a = LTIContextFactory(lti_consumer=user.lti_consumer)
        lti_context_b = LTIContextFactory(lti_consumer=user.lti_consumer)

        # Create 2 forums for context A
        forum_a1 = ForumFactory(name="Forum A1")
        forum_a1.lti_contexts.add(lti_context_a)
        forum_a2 = ForumFactory(name="Forum A2")
        forum_a2.lti_contexts.add(lti_context_a)
        # Create 2 forums for context B
        forum_b1 = ForumFactory(name="Forum B1")
        forum_b1.lti_contexts.add(lti_context_b)
        forum_b2 = ForumFactory(name="Forum B2")
        forum_b2.lti_contexts.add(lti_context_b)

        # Grant read-only access for forums A1, A2 and B1 to our user
        assign_perm("can_see_forum", user, forum_a1, True)
        assign_perm("can_read_forum", user, forum_a1, True)
        assign_perm("can_see_forum", user, forum_a2, True)
        assign_perm("can_read_forum", user, forum_a2, True)
        assign_perm("can_see_forum", user, forum_b1, True)
        assign_perm("can_read_forum", user, forum_b1, True)

        # Instantiate the permission Handler
        permission_handler = PermissionHandler()

        # When the permission handler has no lti context specified,
        # the get_readable_forums should return all forums the user
        # has access to
        forums_qs = Forum.objects.all()
        forums_list = list(Forum.objects.all())
        readable_forums = permission_handler.get_readable_forums(forums_qs, user)
        self.assertCountEqual(readable_forums, [forum_a1, forum_a2, forum_b1])

        # Inject a LTI context into the permission handler and ensure that
        # the results are filtered according to it
        permission_handler.current_lti_context_id = lti_context_a.id
        readable_forums = permission_handler.get_readable_forums(forums_qs, user)
        self.assertCountEqual(readable_forums, [forum_a1, forum_a2])

        # Check the same with a list of forums instead of a QuerySet
        readable_forums = permission_handler.get_readable_forums(forums_list, user)
        self.assertCountEqual(readable_forums, [forum_a1, forum_a2])

        # Inject another LTIContext into the permission handler
        permission_handler.current_lti_context_id = lti_context_b.id
        readable_forums = permission_handler.get_readable_forums(forums_qs, user)
        self.assertCountEqual(readable_forums, [forum_b1])
        readable_forums = permission_handler.get_readable_forums(forums_list, user)
        self.assertCountEqual(readable_forums, [forum_b1])
Example #9
0
    def test_get_group_role_name(self):
        """get_group_role_name should return the name of the role with the specific pattern"""
        context = LTIContextFactory()

        # Ensure that the get_group_role_name generator respect a specific name pattern
        self.assertEqual(f"cg:{context.id}:role:",
                         context.get_group_role_name(""))
        # Test with a actual group name label
        name_instructor_group = f"cg:{context.id}:role:instructor"
        self.assertEqual(name_instructor_group,
                         context.get_group_role_name("instructor"))
Example #10
0
    def test_can_tell_if_the_user_is_instructor_of_this_forum():
        """
        Given two users. User1 is student of the forum, User2 is instructor.
        We control that is_user_instructor can detect if a user is an instructor.
        Then a forum can be part of multiple contexts. If a user is instructor in one context,
        he is considered intructor of this forum in all contexts. We add a new context to the forum
        where user is instructor and test that user is now considered as instructor
        """

        # load template
        def get_rendered(topic, user):
            template = Template(
                "{% load custom_tags %}" +
                "{% if topic|is_user_instructor:user %}YES{% else %}NO{% endif %}"
            )
            context = Context({"topic": topic, "user": user})
            rendered = template.render(context)

            return rendered

        lti_consumer = LTIConsumerFactory()
        # Create two LTI Context
        context1 = LTIContextFactory(lti_consumer=lti_consumer)
        context2 = LTIContextFactory(lti_consumer=lti_consumer)
        # Create two users
        user1 = UserFactory(lti_consumer=lti_consumer)
        user2 = UserFactory(lti_consumer=lti_consumer)

        # Sync user1 groups in context1 with role "student"
        context1.sync_user_groups(user1, ["student"])
        # Sync user1 groups in context2 with role "instructor"
        context2.sync_user_groups(user1, ["instructor"])
        # Sync user2 groups in context1 with role "instructor"
        context1.sync_user_groups(user2, ["instructor"])

        # Create forum and add context1
        forum = ForumFactory(name="Initial forum name")
        forum.lti_contexts.add(context1)

        # Set up topic
        topic = TopicFactory(forum=forum,
                             poster=user1,
                             subject="topic création")

        # Chek that user1 is not instructor
        assert get_rendered(topic, user1) == "NO"
        # Chek that user2 is instructor
        assert get_rendered(topic, user2) == "YES"

        # Add forum to context2 where user1 has role "instructor"
        forum.lti_contexts.add(context2)
        # Check that user1 is now instructor as well
        assert get_rendered(topic, user1) == "YES"
Example #11
0
    def test_browsing_with_can_manage_moderator_forum_permission(self):
        """
        A user with the `can_manage_moderator_forum` permission and
        `SESSION_LTI_CONTEXT_ID` should be able to access it.
        """
        user = UserFactory()
        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
        forum = ForumFactory()
        forum.lti_contexts.add(lti_context)

        assign_perm("can_manage_moderator", user, forum, True)

        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        response = self.client.get("/moderators/")
        # Controls the page is forbidden as session is not set
        self.assertEqual(403, response.status_code)

        session = self.client.session
        session[SESSION_LTI_CONTEXT_ID] = lti_context.id
        session.save()
        self.assertEqual(
            self.client.session.get(SESSION_LTI_CONTEXT_ID), lti_context.id
        )

        # Now session and permission are set, we should be able to access it
        response = self.client.get("/moderators/")
        self.assertEqual(200, response.status_code)
        self.assertContains(response, "Manage forum's moderators")
    def test_access_can_manage_moderators_moderator_list_students(self):
        """Users that can manage moderators should be able to use the API to request
        list of students"""
        user = UserFactory()
        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
        forum = ForumFactory()
        forum.lti_contexts.add(lti_context)

        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        response = self.client.get("/api/v1.0/users/?role=student")
        # First it's forbidden
        self.assertEqual(403, response.status_code)
        # Add session
        session = self.client.session
        session[SESSION_LTI_CONTEXT_ID] = lti_context.id
        session.save()
        self.assertEqual(self.client.session.get(SESSION_LTI_CONTEXT_ID),
                         lti_context.id)

        response = self.client.get("/api/v1.0/users/?role=student")
        # Still forbidden session ok but missing permission
        self.assertEqual(response.status_code, 403)

        assign_perm("can_manage_moderator", user, forum, True)
        # Should now be authorized
        response = self.client.get("/api/v1.0/users/?role=student")
        self.assertEqual(response.status_code, 200)
    def test_access_api_can_manage_moderators_instructor_other_forum(self):
        """
        If a user can manage another forum, he can't update moderators from a forum
        where is doesn't have this permission.
        """
        update_user = UserFactory()
        api_user = UserFactory(lti_consumer=update_user.lti_consumer)

        lti_context = LTIContextFactory(lti_consumer=update_user.lti_consumer)
        forum = ForumFactory()
        forum.lti_contexts.add(lti_context)
        update_user.refresh_from_db()
        # Assign the permission
        assign_perm("can_manage_moderator", api_user, ForumFactory(), True)
        # Creates the session
        self.client.force_login(api_user, "ashley.auth.backend.LTIBackend")
        session = self.client.session
        session[SESSION_LTI_CONTEXT_ID] = lti_context.id
        session.save()

        action = random.choice(
            ["add_group_moderator", "remove_group_moderator"])
        # Revoke user to moderator
        response = self.client.patch(
            f"/api/v1.0/users/{update_user.id}/{action}/",
            content_type="application/json",
        )
        self.assertEqual(response.status_code, 403)
        self.assertEqual(
            response.json(),
            {"detail": "You do not have permission to perform this action."},
        )
    def test_access_api_update_student_patch(self):
        """Standard call should not be allowed to update a student."""
        # Creates a forum
        user = UserFactory()
        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
        forum = ForumFactory()
        forum.lti_contexts.add(lti_context)
        assign_perm("can_read_forum", user, forum, True)

        # Creates the session
        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        session = self.client.session
        session[SESSION_LTI_CONTEXT_ID] = lti_context.id
        session.save()
        data = {
            "public_username": "******",
        }
        response = self.client.patch(
            f"/api/v1.0/users/{user.id}/",
            json.dumps(data),
            content_type="application/json",
        )
        self.assertEqual(response.status_code, 403)
        self.assertEqual(
            response.json(),
            {"detail": "You do not have permission to perform this action."},
        )
Example #15
0
    def test_forum_display_button_manage_moderator(self):
        """
        Connects a user with standard forum permission and controls that CTA to manage
        moderator is not present, then add the permission can_manage_moderator and
        control that we now see the CTA as expected
        """
        user = UserFactory()
        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
        forum = ForumFactory(name="Initial forum name")
        forum.lti_contexts.add(lti_context)
        assign_perm("can_read_forum", user, forum)

        # Connects user and go on the forum page
        self.client.force_login(user)
        response = self.client.get(f"/forum/forum/{forum.name}-{forum.id}/")

        # Check the CTA to manage moderators is not present
        self.assertNotContains(
            response,
            ('<a href="/moderators/" title="Manage moderators" class="dropdown-item">'
             "Manage moderators</a>"),
            html=True,
        )
        # Assign permission can_manage_moderator
        assign_perm("can_manage_moderator", user, forum)
        response = self.client.get(f"/forum/forum/{forum.name}-{forum.id}/")

        # Check the CTA to manage moderators is now present
        self.assertContains(
            response,
            ('<a href="/moderators/" title="Manage moderators" class="dropdown-item">'
             "Manage moderators</a>"),
            html=True,
        )
    def test_access_can_manage_moderators_list_non_moderators(self):
        """Users that can manage moderators should be able to use the API to request
        list of users that are not moderators"""
        user = UserFactory()
        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
        forum = ForumFactory()
        forum.lti_contexts.add(lti_context)
        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        response = self.client.get("/api/v1.0/users/?role=!moderator")

        # First it's forbidden
        self.assertEqual(403, response.status_code)

        # Add permission
        assign_perm("can_manage_moderator", user, forum, True)

        # Still forbidden, missing the session
        response = self.client.get("/api/v1.0/users/?!role=moderator")
        self.assertEqual(403, response.status_code)

        # Add session
        session = self.client.session
        session[SESSION_LTI_CONTEXT_ID] = lti_context.id
        session.save()
        self.assertEqual(self.client.session.get(SESSION_LTI_CONTEXT_ID),
                         lti_context.id)

        response = self.client.get("/api/v1.0/users/?role=!moderator")
        # Permission + session added, it should be allowed
        self.assertEqual(response.status_code, 200)
Example #17
0
    def test_with_can_rename_forum_permission(self):
        """
        A user with the `can_rename_forum` permission should be able
        to rename it.
        """

        user = UserFactory()
        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
        forum = ForumFactory(name="Initial forum name")
        forum.lti_contexts.add(lti_context)

        assign_perm("can_rename_forum", user, forum, True)

        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        response = self.client.get(f"/forum/admin/rename/{forum.pk}/")
        self.assertEqual(200, response.status_code)
        self.assertContains(response, "Rename the forum")

        update_response = self.client.post(
            f"/forum/admin/rename/{forum.pk}/",
            data={"name": "Modified forum name"})
        self.assertEqual(302, update_response.status_code)

        self.assertEqual("Modified forum name",
                         Forum.objects.get(pk=forum.pk).name)
Example #18
0
    def test_basic_user(self):
        """
        A user without the `can_archive_forum` permission
        should not be able to archive it.
        """
        user = UserFactory()
        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
        forum = ForumFactory()
        forum.lti_contexts.add(lti_context)
        assign_perm("can_read_forum", user, forum)

        self.assertFalse(forum.archived)

        self.client.force_login(user, "ashley.auth.backend.LTIBackend")

        # The user can read the forum
        response = self.client.get(f"/forum/forum/{forum.slug}-{forum.pk}/")
        self.assertEqual(200, response.status_code)
        self.assertContains(response, forum.name)

        # but he's not allowed to archive it
        response = self.client.get(f"/forum/admin/archive/{forum.pk}/")
        self.assertEqual(403, response.status_code)

        update_response = self.client.post(f"/forum/admin/archive/{forum.pk}/")
        self.assertEqual(403, update_response.status_code)

        self.assertFalse(Forum.objects.get(pk=forum.pk).archived)
Example #19
0
    def test_lti_context_id(self):
        """
        When the `SESSION_LTI_CONTEXT_ID` is set in the user session, it should
        be injected into the PermissionHandler instance that is stored in the
        request object.
        """

        user = UserFactory()
        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)

        # Generate a request
        request = RequestFactory().get("/")

        # Attach a user to the request
        request.user = user

        # Attach a session to the request
        session_middleware = SessionMiddleware(lambda r: None)
        session_middleware.process_request(request)

        # Store the LTIContext id in the session
        request.session[SESSION_LTI_CONTEXT_ID] = lti_context.id
        self.assertEqual(request.session.get(SESSION_LTI_CONTEXT_ID),
                         lti_context.id)

        # Execute the ForumPermissionMiddleware on the request
        permission_middleware = ForumPermissionMiddleware(lambda r: None)
        permission_middleware.process_request(request)

        # The permission handler instance should have been injected, with the
        # right current_lti_context_id
        self.assertEqual(
            request.forum_permission_handler.current_lti_context_id,
            lti_context.id)
Example #20
0
    def test_get_readable_forums_super_user(self):
        """
        Super user has access to all the forum filtered on LTIContext and
        archived ones but don't need to have access in reading.
        """
        super_user = UserFactory(is_superuser=True)
        basic_user = UserFactory()
        lti_context_a = LTIContextFactory(lti_consumer=super_user.lti_consumer)
        lti_context_b = LTIContextFactory(lti_consumer=super_user.lti_consumer)

        # Create 2 forums for context A
        forum_a1 = ForumFactory(name="Forum A1")
        forum_a1.lti_contexts.add(lti_context_a)
        forum_a2_archived = ForumFactory(name="Forum A2")
        forum_a2_archived.lti_contexts.add(lti_context_a)
        forum_a2_archived.archived = True
        forum_a2_archived.save()
        # Create 1 forum for context B
        forum_b1 = ForumFactory(name="Forum B1")
        forum_b1.lti_contexts.add(lti_context_b)

        # Instantiate the permission Handler
        permission_handler = PermissionHandler()

        forums_qs = Forum.objects.all()
        # With no lti_context super_user can see all forums
        readable_forums = permission_handler.get_readable_forums(forums_qs, super_user)
        self.assertCountEqual(readable_forums, [forum_a1, forum_b1])
        # standard user can't see any
        readable_forums = permission_handler.get_readable_forums(forums_qs, basic_user)
        self.assertCountEqual(readable_forums, [])

        # Inject a LTI context into the permission handler and ensure that
        # the results are filtered according to it
        permission_handler.current_lti_context_id = lti_context_a.id
        readable_forums = permission_handler.get_readable_forums(forums_qs, super_user)
        # even if super user has no can_read_forum permission is still can see all
        # unarchived forums of his lti_context
        self.assertCountEqual(readable_forums, [forum_a1])

        # standard user can't see any
        readable_forums = permission_handler.get_readable_forums(forums_qs, basic_user)
        self.assertCountEqual(readable_forums, [])
 def test_access_api_update_instructor_post(self):
     """Post to update user is not allowed even for an instructor."""
     # Creates a forum
     user = UserFactory()
     lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
     forum = ForumFactory()
     forum.lti_contexts.add(lti_context)
     lti_context.sync_user_groups(user, ["instructor"])
     assign_perm("can_manage_moderator", user, forum, True)
     # Creates the session
     self.client.force_login(user, "ashley.auth.backend.LTIBackend")
     session = self.client.session
     session[SESSION_LTI_CONTEXT_ID] = lti_context.id
     session.save()
     response = self.client.post(
         f"/api/v1.0/users/{user.id}/",
         content_type="application/json",
     )
     self.assertEqual(response.status_code, 405)
     self.assertEqual(response.json(),
                      {"detail": 'Method "POST" not allowed.'})
Example #22
0
    def _get_url_list_forum_with_forums(self):
        """Creates four forums and a user to access the forum that has
        the permission to access it. It's a shortcut used in all the tests below.
        """
        user = UserFactory()
        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
        forum = ForumFactory(name="Z Letter")
        forum.lti_contexts.add(lti_context)
        # create 3 topics, and one topic with 10 posts
        topic = TopicFactory(forum=forum)
        for i in range(10):
            PostFactory(topic=topic)
        PostFactory(topic=TopicFactory(forum=forum))
        PostFactory(topic=TopicFactory(forum=forum))

        # create a forum with 2 topics
        forum2 = ForumFactory(name="A Letter")
        forum2.lti_contexts.add(lti_context)
        PostFactory(topic=TopicFactory(forum=forum2))
        PostFactory(topic=TopicFactory(forum=forum2))

        # create a forum with 1 topic and 5 messages
        forum3 = ForumFactory(name="Q Letter")
        forum3.lti_contexts.add(lti_context)
        topic3 = TopicFactory(forum=forum3)
        PostFactory(topic=topic3)
        PostFactory(topic=topic3)
        PostFactory(topic=topic3)
        PostFactory(topic=topic3)
        PostFactory(topic=topic3)
        PostFactory(topic=TopicFactory(forum=forum3))
        PostFactory(topic=TopicFactory(forum=forum3))
        PostFactory(topic=TopicFactory(forum=forum3))

        # create a forum with no topic
        forum4 = ForumFactory(name="M Letter")
        forum4.lti_contexts.add(lti_context)

        # Grant access
        assign_perm("can_see_forum", user, forum, True)
        assign_perm("can_read_forum", user, forum, True)
        assign_perm("can_see_forum", user, forum2, True)
        assign_perm("can_read_forum", user, forum2, True)
        assign_perm("can_see_forum", user, forum3, True)
        assign_perm("can_read_forum", user, forum3, True)
        assign_perm("can_see_forum", user, forum4, True)
        assign_perm("can_read_forum", user, forum4, True)

        self.client.force_login(user, "ashley.auth.backend.LTIBackend")

        return forum, forum2, forum3, forum4
Example #23
0
    def test_get_user_roles_other_context(self):
        """get_user_roles should return the list of the roles names without the specific
        patterns cg:{context.id}:role: only the label of the roles and only for the
        current context"""
        lti_consumer = LTIConsumerFactory()
        context = LTIContextFactory(lti_consumer=lti_consumer)
        context2 = LTIContextFactory(lti_consumer=lti_consumer)
        # Create user
        user = UserFactory(lti_consumer=lti_consumer)

        # Sync user groups in context with multiple roles
        context.sync_user_groups(user, ["role1", "role2"])
        # Sync user groups in context2 with other roles)
        context2.sync_user_groups(user, ["newgroup"])

        # check that the list of roles is returned
        self.assertCountEqual(
            ["role1", "role2"],
            context.get_user_roles(user),
        )
        self.assertCountEqual(
            ["newgroup"],
            context2.get_user_roles(user),
        )
    def _login_authorized_user_to_manage_moderators(self):
        """
        Access to API has been tested in previous tests. This method is a shortcut for tests
        below to retrieve a granted user for the API and the current lti_context.
        """
        api_user = UserFactory()

        lti_context = LTIContextFactory(lti_consumer=api_user.lti_consumer)
        forum = ForumFactory()
        forum.lti_contexts.add(lti_context)
        # Assign the permission for API user
        assign_perm("can_manage_moderator", api_user, forum, True)

        # Create the session and it should work
        self.client.force_login(api_user, "ashley.auth.backend.LTIBackend")
        session = self.client.session
        session[SESSION_LTI_CONTEXT_ID] = lti_context.id
        session.save()

        return api_user, lti_context
    def test_access_api_moderator_group_instructor_put(self):
        """Instructor can't update user with a put to add or remove the group moderator."""
        user = UserFactory(public_username="******")
        # Creates a forum
        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
        forum = ForumFactory()
        forum.lti_contexts.add(lti_context)
        assign_perm("can_manage_moderator", user, forum, True)

        # Creates the session
        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        session = self.client.session
        session[SESSION_LTI_CONTEXT_ID] = lti_context.id
        session.save()

        action = random.choice(
            ["add_group_moderator", "remove_group_moderator"])
        response = self.client.put(f"/api/v1.0/users/{user.id}/{action}/")
        self.assertEqual(response.status_code, 405)
        self.assertEqual(response.json(),
                         {"detail": 'Method "PUT" not allowed.'})
Example #26
0
    def test_basic_user(self):
        """
        A user without the `can_rename_forum` permission
        should not be able to rename it.
        """
        user = UserFactory()
        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
        forum = ForumFactory(name="Initial forum name")
        forum.lti_contexts.add(lti_context)

        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        response = self.client.get(f"/forum/admin/rename/{forum.pk}/")
        self.assertEqual(403, response.status_code)

        update_response = self.client.post(
            f"/forum/admin/rename/{forum.pk}/",
            data={"name": "Modified forum name"})
        self.assertEqual(403, update_response.status_code)

        self.assertEqual("Initial forum name",
                         Forum.objects.get(pk=forum.pk).name)
Example #27
0
    def test_lti_context_id_anonymous(self):
        """
        The ForumPermissionMiddleware should not inject any LTIContext id in
        the permission handler for request made by anonymous users.
        """
        lti_context = LTIContextFactory()

        # Generate an anonymous request (with no LTIContext ID in session)
        request_without_lti_context = RequestFactory().get("/")
        request_without_lti_context.user = AnonymousUser()
        session_middleware = SessionMiddleware(lambda r: None)
        session_middleware.process_request(request_without_lti_context)
        permission_middleware = ForumPermissionMiddleware(lambda r: None)
        permission_middleware.process_request(request_without_lti_context)

        # The permission handler should have been injected, without the current_lti_context_id
        self.assertIsNotNone(
            request_without_lti_context.forum_permission_handler)
        self.assertIsNone(request_without_lti_context.forum_permission_handler.
                          current_lti_context_id)

        # Generate an anonymous request (with a LTIContext ID in session)
        request_with_lti_context = RequestFactory().get("/")
        request_with_lti_context.user = AnonymousUser()
        session_middleware = SessionMiddleware(lambda r: None)
        session_middleware.process_request(request_with_lti_context)
        request_with_lti_context.session[
            SESSION_LTI_CONTEXT_ID] = lti_context.id
        self.assertEqual(
            request_with_lti_context.session.get(SESSION_LTI_CONTEXT_ID),
            lti_context.id)
        permission_middleware = ForumPermissionMiddleware(lambda r: None)
        permission_middleware.process_request(request_with_lti_context)

        # The permission handler should have been injected, without the current_lti_context_id
        self.assertIsNotNone(request_with_lti_context.forum_permission_handler)
        self.assertIsNone(request_with_lti_context.forum_permission_handler.
                          current_lti_context_id)
    def test_access_api_moderator_group_student_patch(self):
        """Student can't patch user to add or remove the group moderator."""
        user = UserFactory(public_username="******")
        # Creates a forum
        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
        forum = ForumFactory()
        forum.lti_contexts.add(lti_context)
        assign_perm("can_read_forum", user, forum, True)

        # Creates the session
        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        session = self.client.session
        session[SESSION_LTI_CONTEXT_ID] = lti_context.id
        session.save()

        action = random.choice(
            ["add_group_moderator", "remove_group_moderator"])
        response = self.client.patch(f"/api/v1.0/users/{user.id}/{action}/")
        self.assertEqual(response.status_code, 403)
        self.assertEqual(
            response.json(),
            {"detail": "You do not have permission to perform this action."},
        )
Example #29
0
    def test_with_can_archive_forum_permission(self):
        """
        A user with the `can_archive_forum` permission should be able
        to archive it.
        """

        user = UserFactory()
        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
        forum = ForumFactory()
        forum.lti_contexts.add(lti_context)

        assign_perm("can_read_forum", user, forum, True)
        assign_perm("can_archive_forum", user, forum, True)

        self.assertFalse(forum.archived)

        self.client.force_login(user, "ashley.auth.backend.LTIBackend")

        # The user can access the forum
        response = self.client.get(f"/forum/forum/{forum.slug}-{forum.pk}/")
        self.assertEqual(200, response.status_code)
        self.assertContains(response, forum.name)

        # He can access the form that allows to archive it
        response = self.client.get(f"/forum/admin/archive/{forum.pk}/")
        self.assertEqual(200, response.status_code)
        self.assertContains(response, "Delete the forum")

        # He can archive it
        update_response = self.client.post(f"/forum/admin/archive/{forum.pk}/")
        self.assertEqual(302, update_response.status_code)
        self.assertTrue(Forum.objects.get(pk=forum.pk).archived)

        # And once it's done, he can no longer access it
        response = self.client.get(f"/forum/forum/{forum.slug}-{forum.pk}/")
        self.assertEqual(404, response.status_code)
Example #30
0
    def test_browsing_basic_user(self):
        """
        A user without the `can_manage_moderator` permission should not be able
        to access the page .
        """
        user = UserFactory()
        lti_context = LTIContextFactory(lti_consumer=user.lti_consumer)
        forum = ForumFactory()
        forum.lti_contexts.add(lti_context)

        # Check user can access forum view
        response = self.client.get("/forum/")
        self.assertEqual(200, response.status_code)
        # Check user can't access moderators view
        response = self.client.get("/moderators/")
        self.assertEqual(302, response.status_code)
        # Check user gets redirected to login page
        self.assertIn(settings.LOGIN_URL, response.url)

        # Authenticate user
        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        response = self.client.get("/moderators/")
        # Controls the page is forbidden
        self.assertEqual(403, response.status_code)

        # Add session manually
        session = self.client.session
        session[SESSION_LTI_CONTEXT_ID] = lti_context.id
        session.save()
        self.assertEqual(
            self.client.session.get(SESSION_LTI_CONTEXT_ID), lti_context.id
        )

        response = self.client.get("/moderators/")
        # Controls the page is still forbidden
        self.assertEqual(403, response.status_code)