Exemple #1
0
    def test_course_create_multiple_forums_listing_on(self):
        """
        Instructor wants to lock the course that has multiple forums.
        The list of forums should be displayed before the confirmation's
        button.
        """
        forum1 = self._connects("instructor")
        forum2 = ForumFactory(name="Forum2")
        forum3 = ForumFactory(name="Forum3")
        # connects user and add forums to the lti_context
        forum2 = self._connects("instructor", forum_uuid=forum2.lti_id)
        forum3 = self._connects("instructor", forum_uuid=forum3.lti_id)

        # go on the page to lock the course from the forum1
        response = self.client.get(f"/forum/admin/lock-course/{forum1.id}/")
        self.assertEqual(200, response.status_code)
        # this listing is common for all the forums of the course
        forums_list = (
            f'<p class="ml-3 pb-3"><strong>{forum1.name}</strong><p>'
            '<p class="ml-3 pb-3"><strong>Forum2</strong><p>'
            '<p class="ml-3 pb-3"><strong>Forum3</strong><p>')
        self.assertContains(response, forums_list)

        # go on the page to lock the course from the forum2
        response = self.client.get(f"/forum/admin/lock-course/{forum2.id}/")
        self.assertEqual(200, response.status_code)
        self.assertContains(response, forums_list)

        # go on the page to lock the course from the forum3
        response = self.client.get(f"/forum/admin/lock-course/{forum3.id}/")
        self.assertEqual(200, response.status_code)
        self.assertContains(response, forums_list)
    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."},
        )
Exemple #3
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 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])
Exemple #6
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
Exemple #7
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)
Exemple #8
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_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)
    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_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": "******"})
Exemple #13
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)
Exemple #14
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)
Exemple #16
0
    def test_api_create_upload_image(self):
        """Verify that image gets created and uploaded"""
        user = UserFactory()
        forum = ForumFactory()
        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        filename = f"test-{datetime.datetime.now().strftime('%f')}.png"
        data = {
            "file": self._generate_image(filename),
            "forum": forum.id,
            "poster": user.id,
        }
        # At first, no image exists
        self.assertEqual(UploadImage.objects.count(), 0)
        # Upload image
        response = self.client.post("/api/v1.0/images/", data, format="multipart")
        self.assertEqual(response.status_code, 201)

        # Gets last id generated
        image_db = UploadImage.objects.last()

        # Image should have be added with right values
        self.assertEqual(UploadImage.objects.count(), 1)
        self.assertEqual(image_db.forum.id, forum.id)
        self.assertEqual(image_db.poster.id, user.id)

        # Controls image's path is respected on server
        self.assertIn(f"image_uploads/{forum.id}/{user.id}/", image_db.file.name)

        # Controls file has been uploaded
        uploaded_file = image_db.file.open()
        self.assertGreater(uploaded_file.size, 0)
        self.assertIsNotNone(uploaded_file.read())
Exemple #17
0
    def test_api_create_upload_bad_extension(self):
        """Make sure we can't upload a file with an unauthorized extension"""
        user = UserFactory()
        forum = ForumFactory()
        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        video = SimpleUploadedFile(
            "file.mp4", b"file_content", content_type="video/mp4"
        )

        data = {
            "file": video,
            "forum": forum.id,
            "poster": user.id,
        }
        # Upload image
        response = self.client.post("/api/v1.0/images/", data, format="multipart")
        self.assertEqual(response.status_code, 400)
        self.assertEqual(
            json.loads(response.content)["file"],
            [
                (
                    "Upload a valid image. The file you uploaded was either "
                    + "not an image or a corrupted image."
                )
            ],
        )
Exemple #18
0
    def test_testing_topic_announce(self):
        """Controls topics that are of type announcement don't have sorted options"""
        # Creates posts for announcement topics
        forum = ForumFactory()
        PostFactory(topic=TopicFactory(forum=forum, type=Topic.TOPIC_ANNOUNCE))
        PostFactory(topic=TopicFactory(forum=forum, type=Topic.TOPIC_ANNOUNCE))

        user = UserFactory()
        assign_perm("can_read_forum", user, forum)
        self.client.force_login(user)

        response = self.client.get(f"/forum/forum/{forum.slug}-{forum.pk}/")

        html = lxml.html.fromstring(response.content)
        # Select the header block of the announcement block, the first block
        announce_block = str(
            etree.tostring(html.cssselect(".topiclist .card-header")[0]))

        # Controls that announce_block is about announcements and not topics
        self.assertIn("Announcements", announce_block)
        self.assertNotIn("Topics", announce_block)
        self.assertIn("Replies", announce_block)
        self.assertIn("Views", announce_block)
        self.assertIn("Last post", announce_block)

        # There's no sortable informations
        self.assertNotIn("sortable sorted", announce_block)
        # There's no column that has a sorting link on
        self.assertNotIn("<a href=", announce_block)
        # There's no toggle sorting
        self.assertNotIn("Toggle sorting", announce_block)
Exemple #19
0
    def test_api_cant_delete_image(self):
        """Controls user doesn't have the right to delete a record"""
        user = UserFactory()
        forum = ForumFactory()
        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        filename = "image.png"
        data = {
            "file": self._generate_image(filename),
            "forum": forum.id,
            "poster": user.id,
        }
        # At first, no image exists
        self.assertEqual(UploadImage.objects.count(), 0)
        # Upload image
        response = self.client.post("/api/v1.0/images/", data, format="multipart")
        self.assertEqual(response.status_code, 201)

        # Gets last id generated
        self.assertEqual(UploadImage.objects.count(), 1)
        image_db = UploadImage.objects.last()
        # Controls image's path is respected on server
        self.assertIn(f"image_uploads/{forum.id}/{user.id}/", image_db.file.name)

        # Specify the id of the image for the update
        data = {
            "id": image_db.id,
            "file": self._generate_image(filename),
            "forum": forum.id,
            "poster": user.id,
        }
        response = self.client.delete("/api/v1.0/images/", data, format="multipart")
        self.assertEqual(response.status_code, 405)
        content = json.loads(response.content)
        self.assertEqual(content, {"detail": 'Method "DELETE" not allowed.'})
Exemple #20
0
    def _get_url_list_topic_with_three_topics(self):
        """Creates a forum with three topics and a user to access the forum that has
        the permission to access it. It's a shortcut used in all the tests below."""
        forum = ForumFactory()
        # create 3 topics with distinct subject, views_count and date
        PostFactory(
            topic=TopicFactory(forum=forum, views_count=9),
            subject="TOPIC B the eldest with 9 views_count",
        )
        PostFactory(
            topic=TopicFactory(forum=forum, views_count=6),
            subject="TOPIC A created second with 6 views_count",
        )

        PostFactory(
            topic=TopicFactory(forum=forum, views_count=12),
            subject="TOPIC C the newest one with 12 views_count",
        )

        user = UserFactory()
        assign_perm("can_read_forum", user, forum)
        self.client.force_login(user)

        # Setup
        url_list_topic = f"/forum/forum/{forum.slug}-{forum.pk}/"

        return forum, url_list_topic
    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."},
        )
    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)
Exemple #23
0
    def test_testing_topic_announce_dont_get_ordered(self):
        """
        Controls topics that are of type announcement don't get ordered if sorting is
        submitted in url. Orders are only applied to Topic posts.
        """

        forum = ForumFactory()
        user = UserFactory()
        assign_perm("can_read_forum", user, forum)
        self.client.force_login(user)

        # Creates posts for announcement topics
        topicAnnounce1 = TopicFactory(forum=forum,
                                      type=Topic.TOPIC_ANNOUNCE,
                                      views_count=100)
        topicAnnounce2 = TopicFactory(forum=forum,
                                      type=Topic.TOPIC_ANNOUNCE,
                                      views_count=200)
        PostFactory(
            topic=topicAnnounce1,
            subject="TOPIC A TYPE ANNOUNCED",
        )
        PostFactory(
            topic=topicAnnounce2,
            subject="TOPIC B TYPE ANNOUNCED",
        )
        # Post of topicAnnounce2 has been created last, it should be the first one on the list
        self.assertLess(topicAnnounce1.last_post_on,
                        topicAnnounce2.last_post_on)
        # Orders on column view_post
        response = self.client.get(
            f"/forum/forum/{forum.slug}-{forum.pk}/?o=2")
        # Orders is respected on default creation order
        self.assertContentBefore(response, "TOPIC B TYPE ANNOUNCED",
                                 "TOPIC A TYPE ANNOUNCED")
        # Reverses order
        response = self.client.get(
            f"/forum/forum/{forum.slug}-{forum.pk}/?o=-2")
        # Orders of announcement topics stays the same
        self.assertContentBefore(response, "TOPIC B TYPE ANNOUNCED",
                                 "TOPIC A TYPE ANNOUNCED")

        # Orders on replies column
        response = self.client.get(
            f"/forum/forum/{forum.slug}-{forum.pk}/?o=-1")
        # Shows order is respected on default creation order
        self.assertContentBefore(response, "TOPIC B TYPE ANNOUNCED",
                                 "TOPIC A TYPE ANNOUNCED")

        # Reverses order
        response = self.client.get(
            f"/forum/forum/{forum.slug}-{forum.pk}/?o=1")
        # Orders of announcement topics stays the same
        self.assertContentBefore(response, "TOPIC B TYPE ANNOUNCED",
                                 "TOPIC A TYPE ANNOUNCED")
Exemple #24
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"
Exemple #25
0
 def test_api_create_upload_image_wrong_user_id(self):
     """Verify that if user id is wrong we get a 400 code"""
     user = UserFactory()
     forum = ForumFactory()
     self.client.force_login(user, "ashley.auth.backend.LTIBackend")
     data = {
         "file": self._generate_image("test.png"),
         "forum": forum.id,
         "poster": user.id + 10,
     }
     # Upload image
     response = self.client.post("/api/v1.0/images/", data, format="multipart")
     self.assertEqual(response.status_code, 400)
Exemple #26
0
    def test_api_create_upload_image_same_filename(self):
        """
        If a user try to upload an image with the same filename, we make sure that two images gets
        uploaded with a different filename
        """
        user = UserFactory()
        forum = ForumFactory()
        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        filename = "image.png"
        data = {
            "file": self._generate_image(filename),
            "forum": forum.id,
            "poster": user.id,
        }
        # At first, no image exists
        self.assertEqual(UploadImage.objects.count(), 0)
        # Upload image
        response = self.client.post("/api/v1.0/images/", data, format="multipart")
        self.assertEqual(response.status_code, 201)

        # Gets last id generated
        self.assertEqual(UploadImage.objects.count(), 1)
        image_db = UploadImage.objects.last()
        # Controls image's path is respected on server
        self.assertIn(f"image_uploads/{forum.id}/{user.id}/", image_db.file.name)
        # Controls file has been uploaded
        uploaded_file = image_db.file.open()
        self.assertGreater(uploaded_file.size, 0)
        self.assertIsNotNone(uploaded_file.read())

        # Upload an image with the same name
        data = {
            "file": self._generate_image(filename),
            "forum": forum.id,
            "poster": user.id,
        }
        response = self.client.post("/api/v1.0/images/", data, format="multipart")
        self.assertEqual(response.status_code, 201)

        # A new image has been uploaded
        self.assertEqual(UploadImage.objects.count(), 2)
        image_db2 = UploadImage.objects.last()

        # Name of the file is different for the two images
        self.assertNotEqual(image_db.file.name, image_db2.file.name)
        # Controls image's path is respected on server
        self.assertIn(f"image_uploads/{forum.id}/{user.id}/", image_db2.file.name)
        # Controls file has been uploaded
        uploaded_file = image_db2.file.open()
        self.assertGreater(uploaded_file.size, 0)
        self.assertIsNotNone(uploaded_file.read())
Exemple #27
0
    def test_course_admin_cant_lock_forum_in_other_context(self):
        """
        Instructors can't lock course from a forum that isn't
        in the same context.
        """
        forum = self._connects("instructor")
        forum_other_context = ForumFactory()

        # user can't access the view to lock a course
        response = self.client.get(
            f"/forum/admin/lock-course/{forum_other_context.id}/")
        self.assertEqual(403, response.status_code)

        # user can access the view to lock a course
        response = self.client.get(f"/forum/admin/lock-course/{forum.id}/")
        self.assertEqual(200, response.status_code)
Exemple #28
0
    def test_api_create_upload_max_size(self):
        """Make sure we can't upload file over limit size"""
        user = UserFactory()
        forum = ForumFactory()
        self.client.force_login(user, "ashley.auth.backend.LTIBackend")

        data = {
            "file": self._generate_image("test.png"),
            "forum": forum.id,
            "poster": user.id,
        }
        # Upload image
        response = self.client.post("/api/v1.0/images/", data, format="multipart")
        self.assertEqual(response.status_code, 400)
        self.assertEqual(
            json.loads(response.content)["file"],
            ["The maximum file size that can be uploaded is 0 MB"],
        )
Exemple #29
0
    def test_api_create_upload_image_no_user_id(self):
        """Verify that if user id is not send it's setup automatically to
        current user id"""
        user = UserFactory()
        forum = ForumFactory()
        self.client.force_login(user, "ashley.auth.backend.LTIBackend")
        data = {
            "file": self._generate_image("test.png"),
            "forum": forum.id,
        }
        # At first, no image exists
        self.assertEqual(UploadImage.objects.count(), 0)
        # Upload image
        response = self.client.post("/api/v1.0/images/", data, format="multipart")
        self.assertEqual(response.status_code, 201)

        # Poster id should be the current user id logged in
        self.assertEqual(UploadImage.objects.count(), 1)
Exemple #30
0
    def test_forum_search_empty_public_username(self):
        """
        A topic posted by a user that has not defined a public_username
        should be indexed with no error.
        """

        user = UserFactory(public_username="")
        forum = ForumFactory()

        # Create a topic and a post
        topic = TopicFactory(subject="yahl2vooPh", poster=user, forum=forum)
        post = PostFactory(subject="dooV7ei3ju", topic=topic, poster=user)

        # Index the post in Elasticsearch
        call_command("rebuild_index", interactive=False)

        user2 = UserFactory()
        assign_perm("can_read_forum", user2, post.topic.forum)
        self.client.force_login(user2)
        response = self.client.get(
            f"/forum/search/?q=dooV7ei3ju&search_poster_name={post.poster.get_public_username()}\
                    &search_forums={post.topic.forum.pk}")

        self.assertContains(response,
                            "Your search has returned <b>1</b> result",
                            html=True)

        # Ensure that the default display name is present
        user_profile_url = reverse("forum_member:profile",
                                   kwargs={"pk": user.id})
        self.assertContains(response,
                            f'<a href="{user_profile_url}">Anonymous</a>',
                            html=True)

        # Ensure that the default display name is not indexed
        response = self.client.get(
            f"/forum/search/?q=dooV7ei3ju&search_poster_name={post.poster.get_public_username()}\
                            &search_forums={post.topic.forum.pk}&search_poster_name=Anonymous"
        )
        self.assertContains(response,
                            "Your search has returned <b>0</b> results",
                            html=True)