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)
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": "******"})
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])
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"))
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"
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."}, )
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)
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)
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)
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)
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.'})
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
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.'})
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)
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."}, )
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)
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)