Esempio n. 1
0
    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)
Esempio n. 2
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"
Esempio n. 3
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),
        )
Esempio n. 4
0
    def test_get_user_roles(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
        """
        lti_consumer = LTIConsumerFactory()
        context = LTIContextFactory(lti_consumer=lti_consumer)

        # Create two users
        user = UserFactory(lti_consumer=lti_consumer)
        user2 = UserFactory(lti_consumer=lti_consumer)

        # Sync user groups in context with multiple roles
        context.sync_user_groups(user, ["role1", "role2"])
        # check that the list of roles is returned
        self.assertCountEqual(
            ["role1", "role2"],
            context.get_user_roles(user),
        )
        # add an extra group
        instructor_group = Group.objects.create(
            name=f"{context.base_group_name}:role:instructor")
        user.groups.add(instructor_group)
        # check that the list of roles is returned
        self.assertCountEqual(
            ["role1", "role2", "instructor"],
            context.get_user_roles(user),
        )
        # check that group that are not roles get ignored
        other_group = Group.objects.create(
            name=f"{context.base_group_name}:other)")
        user2.groups.add(other_group)
        self.assertCountEqual(
            [],
            context.get_user_roles(user2),
        )
Esempio n. 5
0
    def test_sync_user_groups(self):
        """Test group synchronization"""

        # Create a LTI Consumer
        lti_consumer = LTIConsumerFactory()

        # Create 2 LTI Contexts for lti_consumer
        context1 = LTIContextFactory(lti_consumer=lti_consumer)
        context2 = LTIContextFactory(lti_consumer=lti_consumer)

        # Create an unrelated django group
        unrelated_group = Group.objects.create(name="unrelated_django_group")

        # Initialize a user with no group
        user = UserFactory(lti_consumer=lti_consumer)
        self.assertEqual(0, user.groups.count())

        # Sync user groups in context1 with role "student"
        context1.sync_user_groups(user, ["student"])
        self.assertCountEqual(
            [
                context1.base_group_name,
                f"{context1.base_group_name}:role:student"
            ],
            list(user.groups.values_list("name", flat=True)),
        )

        # Add the user to an unrelated django group
        user.groups.add(unrelated_group)

        # Sync user groups in context2 with multiple roles
        context2.sync_user_groups(user, ["role1", "role2"])
        self.assertCountEqual(
            [
                unrelated_group.name,
                context1.base_group_name,
                f"{context1.base_group_name}:role:student",
                context2.base_group_name,
                f"{context2.base_group_name}:role:role1",
                f"{context2.base_group_name}:role:role2",
            ],
            list(user.groups.values_list("name", flat=True)),
        )

        # Sync user groups in context 2 with another role
        context2.sync_user_groups(user, ["instructor"])
        self.assertCountEqual(
            [
                unrelated_group.name,
                context1.base_group_name,
                f"{context1.base_group_name}:role:student",
                context2.base_group_name,
                f"{context2.base_group_name}:role:instructor",
            ],
            list(user.groups.values_list("name", flat=True)),
        )

        # Sync user groups in context 1 with no role
        context1.sync_user_groups(user, [])
        self.assertCountEqual(
            [
                unrelated_group.name,
                context1.base_group_name,
                context2.base_group_name,
                f"{context2.base_group_name}:role:instructor",
            ],
            list(user.groups.values_list("name", flat=True)),
        )

        # Create another LTIConsumer
        lti_consumer2 = LTIConsumerFactory()

        # Create a LTI Context for lti_consumer2
        context3 = LTIContextFactory(lti_consumer=lti_consumer2)

        # Create a user for this LTI Context
        user2 = UserFactory(lti_consumer=lti_consumer2)

        # Check the PermissionDenied gets called as the user in not part of this LTIContext
        with self.assertRaises(PermissionDenied):
            context3.sync_user_groups(user, ["instructor"])

        # Check the PermissionDenied gets called as the user in not part of this LTIContext
        with self.assertRaises(PermissionDenied):
            context2.sync_user_groups(user2, [])
Esempio n. 6
0
    def test_sync_user_with_internal_moderators_groups(self):
        """
        Test that internal group moderator doesn't get removed using sync_user_groups
        """
        lti_consumer = LTIConsumerFactory()
        context = LTIContextFactory(lti_consumer=lti_consumer)
        # Initialize a user with no group
        user = UserFactory(lti_consumer=lti_consumer)
        self.assertEqual(0, user.groups.count())

        # Sync user groups in context with role "student"
        context.sync_user_groups(user, ["student"])
        self.assertCountEqual(
            [
                context.base_group_name,
                f"{context.base_group_name}:role:student"
            ],
            list(user.groups.values_list("name", flat=True)),
        )
        # Add the user to moderator group
        group_moderator_name = context.get_group_role_name(
            _FORUM_ROLE_MODERATOR)
        group_moderator = Group.objects.create(name=group_moderator_name)
        user.groups.add(group_moderator)
        user.save()
        # confirm group has been added
        self.assertCountEqual(
            [
                context.base_group_name,
                f"{context.base_group_name}:role:student",
                f"{context.base_group_name}:role:moderator",
            ],
            list(user.groups.values_list("name", flat=True)),
        )

        # Sync user groups in context with funnyrole group
        context.sync_user_groups(user, ["funnyrole"])
        self.assertCountEqual(
            ["funnyrole", "moderator"],
            context.get_user_roles(user),
        )
        # User should still have the moderator group
        self.assertCountEqual(
            [
                context.base_group_name,
                f"{context.base_group_name}:role:funnyrole",
                f"{context.base_group_name}:role:moderator",
            ],
            list(user.groups.values_list("name", flat=True)),
        )

        # creates a new context
        context2 = LTIContextFactory(lti_consumer=lti_consumer)
        context2.sync_user_groups(user, ["instructor"])
        # moderator group should not exist in this context
        self.assertCountEqual(
            [
                context.base_group_name,
                f"{context.base_group_name}:role:funnyrole",
                f"{context.base_group_name}:role:moderator",
                context2.base_group_name,
                f"{context2.base_group_name}:role:instructor",
            ],
            list(user.groups.values_list("name", flat=True)),
        )
Esempio n. 7
0
    def test_render_block_is_admin_of_this_forum(self):
        """
        check that the admin icon is present on the different views
        as expected
        """
        lti_consumer = LTIConsumerFactory()
        # Create two users
        user1 = UserFactory(public_username="******",
                            lti_consumer=lti_consumer)
        user2 = UserFactory(public_username="******",
                            lti_consumer=lti_consumer)
        # Create an LTI Context
        context = LTIContextFactory(lti_consumer=lti_consumer)
        # Sync user1 groups in context with role "administrator"
        context.sync_user_groups(user1, ["administrator"])
        # Sync user1 groups in context with role "student"
        context.sync_user_groups(user2, ["student"])

        # Create forum and add context
        forum = ForumFactory(name="forum_test")
        forum.lti_contexts.add(context)

        # assign permission to the group for this forum
        self._init_forum(forum, context)

        # Set up topic
        topic1 = TopicFactory(forum=forum, poster=user1)

        # Set up post
        PostFactory.create(
            topic=topic1,
            poster=user1,
        )

        # log user1
        self.client.force_login(user1)

        # accessing forum view
        response = self.client.get(reverse("forum:index"))
        html = lxml.html.fromstring(response.content)
        forum_last_post = str(
            etree.tostring(html.cssselect(".forum-last-post")[0]))
        # control that the administrator's icon is present
        self.assertTrue((
            '<i class="icon_writer fas fa-award" aria-hidden="true" title="Administrator">'
            '<span class="sr-only">Administrator</span>'
            "</i>") in forum_last_post)
        # control that it's the right user's profile link
        self.assertTrue(
            (f'<a href="/forum/member/profile/{user1.id}/">Val&#233;ry</a>'
             ) in forum_last_post)

        # accessing forum topic listing view
        response = self.client.get(
            reverse("forum:forum", kwargs={
                "slug": forum.slug,
                "pk": forum.pk
            }))
        html = lxml.html.fromstring(response.content)
        # check that the topic creation writer contains the icon for administrator's role
        topic_created = str(etree.tostring(
            html.cssselect(".topic-created")[0]))
        # control that the administrator's icon is present
        self.assertTrue((
            '<i class="icon_writer fas fa-award" aria-hidden="true" title="Administrator">'
            '<span class="sr-only">Administrator</span>'
            "</i>") in topic_created)
        # control that it's the right user's profile link
        self.assertTrue(
            (f'<a href="/forum/member/profile/{user1.id}/">Val&#233;ry</a>'
             ) in topic_created)

        # check that the last post creation writer contains the icon for instructor's role
        html = lxml.html.fromstring(response.content)
        topic_last_post = str(
            etree.tostring(html.cssselect(".topic-last-post")[0]))
        # control that the administrator's icon is present
        self.assertTrue((
            '<i class="icon_writer fas fa-award" aria-hidden="true" title="Administrator">'
            '<span class="sr-only">Administrator</span>'
            "</i>") in topic_last_post)
        # control that it's the right user's profile link
        self.assertTrue(
            f'<a href="/forum/member/profile/{user1.id}/">Val&#233;ry</a>' in
            topic_last_post)

        # user2 add a post to the topic, last message is now from a student
        PostFactory.create(
            topic=topic1,
            poster=user2,
        )

        # reload the topic list view
        response = self.client.get(
            reverse("forum:forum", kwargs={
                "slug": forum.slug,
                "pk": forum.pk
            }))
        html = lxml.html.fromstring(response.content)
        topic_created = str(etree.tostring(
            html.cssselect(".topic-created")[0]))
        # control that the administrator's icon is present
        self.assertTrue((
            '<i class="icon_writer fas fa-award" aria-hidden="true" title="Administrator">'
            '<span class="sr-only">Administrator</span>'
            "</i>") in topic_created)
        # control that it's the right user's profile link
        self.assertTrue(
            (f'<a href="/forum/member/profile/{user1.id}/">Val&#233;ry</a>'
             ) in topic_created)

        topic_last_post = str(
            etree.tostring(html.cssselect(".topic-last-post")[0]))
        # check that there's no more icon as the post has been created by a student
        self.assertFalse("Administrator" in topic_last_post)
        # control that it's the right user's profile link
        self.assertTrue(
            (f'<a href="/forum/member/profile/{user2.id}/">Fran&#231;ois</a>'
             ) in topic_last_post)

        # accessing forum view
        response = self.client.get(reverse("forum:index"))
        # check that there's no more icon in this view as a new post has been created by a student
        self.assertNotContains(response, "icon_writer fas fa-award")

        # access list of posts from the topic
        response = self.client.get(
            reverse(
                "forum_conversation:topic",
                kwargs={
                    "forum_slug": forum.slug,
                    "forum_pk": forum.pk,
                    "slug": topic1.slug,
                    "pk": topic1.id,
                },
            ))
        # access 'post an answer' it should list the other posts of the topic
        response = self.client.get(
            f"/forum/forum/{forum.slug}-{forum.pk}/topic/{topic1.slug}-{topic1.pk}/post/create/"
        )
        html = lxml.html.fromstring(response.content)
        # check that for the posts in this topic we have the one from the instructor with the icon

        # check that for the message on first position there is no icon for the student
        html_first_post = str(etree.tostring(html.cssselect(".text-muted")[0]))
        self.assertFalse("Administrator" in html_first_post)
        self.assertTrue(
            (f'<a href="/forum/member/profile/{user2.id}/">Fran&#231;ois</a>'
             ) in html_first_post)
        # check that for the second message we have the instructor's icon
        html_second_post = str(etree.tostring(
            html.cssselect(".text-muted")[1]))
        self.assertTrue((
            '<i class="icon_writer fas fa-award" aria-hidden="true" title="Administrator">'
            '<span class="sr-only">Administrator</span>'
            "</i>") in html_second_post)
        self.assertTrue(
            (f'<a href="/forum/member/profile/{user1.id}/">Val&#233;ry</a>'
             ) in html_second_post)