from unittest.mock import patch from django.forms.models import model_to_dict from cms.api import add_plugin from cms.models import CMSPlugin, Placeholder, UserSettings from cms.test_utils.project.placeholderapp.models import Example1 from cms.test_utils.testcases import CMSTestCase from cms.test_utils.util.context_managers import override_placeholder_conf from cms.utils.urlutils import admin_reverse class AppAdminTestCase(CMSTestCase): def setUp(self): self._obj = self._get_example_obj() def _add_plugin_to_placeholder(self, placeholder, plugin_type='LinkPlugin', language='en'): plugin_data = { 'StylePlugin': {'tag_type': 'div'}, 'LinkPlugin': {'name': 'A Link', 'external_link': 'https://www.django-cms.org'}, 'PlaceholderPlugin': {'name': 'Content'}, } plugin = add_plugin( placeholder, plugin_type, language, **plugin_data[plugin_type] ) return plugin def _get_move_data(self, plugin, position, placeholder=None, parent=None): try: placeholder_id = placeholder.pk except AttributeError: placeholder_id = '' try: parent_id = parent.pk except AttributeError: parent_id = '' data = { 'placeholder_id': placeholder_id, 'target_language': 'en', 'target_position': position, 'plugin_id': plugin.pk, 'plugin_parent': parent_id, } return data def _get_add_plugin_uri(self, plugin_type='LinkPlugin', language='en'): uri = self.get_add_plugin_uri( placeholder=self._obj.placeholder, plugin_type=plugin_type, language=language, ) return uri def _get_example_obj(self): obj = Example1.objects.create( char_1='one', char_2='two', char_3='tree', char_4='four' ) return obj class AppAdminTest(AppAdminTestCase): placeholderconf = {'placeholder': { 'limits': { 'global': 2, 'StylePlugin': 1, } } } def test_global_limit_on_plugin_add(self): """ Ensures placeholder global plugin limit is respected when adding plugins to the placeholder. """ superuser = self.get_superuser() endpoint = self._get_add_plugin_uri() with self.login_user_context(superuser): with override_placeholder_conf(CMS_PLACEHOLDER_CONF=self.placeholderconf): data = {'name': 'A Link', 'external_link': 'https://www.django-cms.org'} response = self.client.post(endpoint, data) # first self.assertEqual(response.status_code, 200) response = self.client.post(endpoint, data) # second self.assertEqual(response.status_code, 200) response = self.client.post(endpoint, data) # third self.assertEqual(response.status_code, 400) self.assertEqual( response.content, b"This placeholder already has the maximum number of plugins (2).", ) def test_global_limit_on_plugin_move(self): """ Ensures placeholder global plugin limit is respected when moving plugins to the placeholder. """ superuser = self.get_superuser() source_placeholder = self._obj.placeholder target_placeholder = self._get_example_obj().placeholder plugin_1 = self._add_plugin_to_placeholder(source_placeholder) plugin_2 = self._add_plugin_to_placeholder(source_placeholder) plugin_3 = self._add_plugin_to_placeholder(source_placeholder) with self.login_user_context(superuser): with override_placeholder_conf(self.placeholderconf): data = self._get_move_data(plugin_1, position=1, placeholder=target_placeholder) endpoint = self.get_move_plugin_uri(plugin_1) response = self.client.post(endpoint, data) # first self.assertEqual(response.status_code, 200) data = self._get_move_data(plugin_2, position=2, placeholder=target_placeholder) endpoint = self.get_move_plugin_uri(plugin_2) response = self.client.post(endpoint, data) # second self.assertEqual(response.status_code, 200) data = self._get_move_data(plugin_3, position=3, placeholder=target_placeholder) endpoint = self.get_move_plugin_uri(plugin_3) response = self.client.post(endpoint, data) # third self.assertEqual(response.status_code, 400) self.assertEqual( response.content, b"This placeholder already has the maximum number of plugins (2)." ) def test_no_global_limit_check_same_placeholder_move(self): """ Ensures no global limit exception is raised when moving plugins inside a placeholder. """ superuser = self.get_superuser() source_placeholder = self._obj.placeholder plugin_1 = self._add_plugin_to_placeholder(source_placeholder) plugin_2 = self._add_plugin_to_placeholder(source_placeholder) with self.login_user_context(superuser): with override_placeholder_conf(self.placeholderconf): data = self._get_move_data(plugin_1, position=1) endpoint = self.get_move_plugin_uri(plugin_1) response = self.client.post(endpoint, data) # first self.assertEqual(response.status_code, 200) data = self._get_move_data(plugin_2, position=2) endpoint = self.get_move_plugin_uri(plugin_2) response = self.client.post(endpoint, data) # second self.assertEqual(response.status_code, 200) def test_type_limit_on_plugin_add(self): """ Ensures placeholder plugin type limit is respected when adding plugins to the placeholder. """ superuser = self.get_superuser() endpoint = self._get_add_plugin_uri('StylePlugin') with self.login_user_context(superuser): with override_placeholder_conf(CMS_PLACEHOLDER_CONF=self.placeholderconf): data = {'tag_type': 'div'} response = self.client.post(endpoint, data) # first self.assertEqual(response.status_code, 200) response = self.client.post(endpoint, data) # second self.assertEqual(response.status_code, 400) self.assertEqual( response.content, b"This placeholder already has the " b"maximum number (1) of allowed Style plugins." ) def test_type_limit_on_plugin_move(self): """ Ensures placeholder plugin type limit is respected when moving plugins to the placeholder. """ superuser = self.get_superuser() source_placeholder = self._obj.placeholder target_placeholder = self._get_example_obj().placeholder plugin_1 = self._add_plugin_to_placeholder(source_placeholder, 'StylePlugin') plugin_2 = self._add_plugin_to_placeholder(source_placeholder, 'StylePlugin') with self.login_user_context(superuser): with override_placeholder_conf(CMS_PLACEHOLDER_CONF=self.placeholderconf): data = self._get_move_data(plugin_1, position=1, placeholder=target_placeholder) endpoint = self.get_move_plugin_uri(plugin_1) response = self.client.post(endpoint, data) # first self.assertEqual(response.status_code, 200) data = self._get_move_data(plugin_2, position=1, placeholder=target_placeholder) endpoint = self.get_move_plugin_uri(plugin_2) response = self.client.post(endpoint, data) # second self.assertEqual(response.status_code, 400) self.assertEqual(response.content, b"This placeholder already has the maximum number (1) of allowed Style plugins.") def test_no_type_limit_check_same_placeholder_move(self): """ Ensures no plugin type limit exception is raised when moving plugins inside of a placeholder. """ superuser = self.get_superuser() source_placeholder = self._obj.placeholder plugin_1 = self._add_plugin_to_placeholder(source_placeholder, 'StylePlugin') with self.login_user_context(superuser): with override_placeholder_conf(CMS_PLACEHOLDER_CONF=self.placeholderconf): data = self._get_move_data(plugin_1, position=1) endpoint = self.get_move_plugin_uri(plugin_1) response = self.client.post(endpoint, data) # first self.assertEqual(response.status_code, 200) class AppAdminPermissionsTest(AppAdminTestCase): def setUp(self): self._obj = self._get_example_obj() self._staff_user = self.get_staff_user_with_no_permissions() def test_user_can_add_plugin(self): """ User can add a new plugin if he has change permissions on the model attached to the placeholder and he has add permissions on the plugin model. """ staff_user = self._staff_user placeholder = self._obj.placeholder plugins = placeholder.get_plugins('en').filter(plugin_type='LinkPlugin') endpoint = self._get_add_plugin_uri() self.add_permission(staff_user, 'change_example1') self.add_permission(staff_user, 'add_link') with self.login_user_context(staff_user): data = {'name': 'A Link', 'external_link': 'https://www.django-cms.org'} response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 200) self.assertEqual(plugins.count(), 1) def test_user_cant_add_plugin(self): """ User can't add a new plugin if he does not have change permissions on the model attached to the placeholder and/or does not have add permissions on the plugin model. """ staff_user = self._staff_user placeholder = self._obj.placeholder plugins = placeholder.get_plugins('en').filter(plugin_type='LinkPlugin') endpoint = self._get_add_plugin_uri() self.add_permission(staff_user, 'add_example1') self.add_permission(staff_user, 'delete_example1') self.add_permission(staff_user, 'add_link') with self.login_user_context(staff_user): data = {'name': 'A Link', 'external_link': 'https://www.django-cms.org'} response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 403) self.assertEqual(plugins.count(), 0) self.add_permission(staff_user, 'change_example1') self.remove_permission(staff_user, 'add_link') with self.login_user_context(staff_user): data = {'name': 'A Link', 'external_link': 'https://www.django-cms.org'} response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 403) self.assertEqual(plugins.count(), 0) def test_user_can_edit_plugin(self): """ User can edit a plugin if he has change permissions on the model attached to the placeholder and he has change permissions on the plugin model. """ staff_user = self._staff_user placeholder = self._obj.placeholder plugin = self._add_plugin_to_placeholder(placeholder) endpoint = self.get_change_plugin_uri(plugin) self.add_permission(staff_user, 'change_example1') self.add_permission(staff_user, 'change_link') with self.login_user_context(staff_user): data = model_to_dict(plugin, fields=['name', 'external_link']) data['name'] = 'A link 2' response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 200) plugin.refresh_from_db() self.assertEqual(plugin.name, data['name']) def test_user_cant_edit_plugin(self): """ User can't edit a plugin if he does not have change permissions on the model attached to the placeholder and/or does not have change permissions on the plugin model. """ staff_user = self._staff_user placeholder = self._obj.placeholder plugin = self._add_plugin_to_placeholder(placeholder) endpoint = self.get_change_plugin_uri(plugin) self.add_permission(staff_user, 'add_example1') self.add_permission(staff_user, 'delete_example1') self.add_permission(staff_user, 'change_link') with self.login_user_context(staff_user): data = model_to_dict(plugin, fields=['name', 'external_link']) data['name'] = 'A link 2' response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 403) plugin.refresh_from_db() self.assertNotEqual(plugin.name, data['name']) self.add_permission(staff_user, 'change_example1') self.remove_permission(staff_user, 'change_link') with self.login_user_context(staff_user): data = model_to_dict(plugin, fields=['name', 'external_link']) data['name'] = 'A link 2' response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 403) plugin.refresh_from_db() self.assertNotEqual(plugin.name, data['name']) def test_user_can_delete_plugin(self): """ User can delete a plugin if he has change permissions on the model attached to the placeholder and he has delete permissions on the plugin model. """ staff_user = self._staff_user placeholder = self._obj.placeholder plugin = self._add_plugin_to_placeholder(placeholder) endpoint = self.get_delete_plugin_uri(plugin) self.add_permission(staff_user, 'change_example1') self.add_permission(staff_user, 'delete_link') with self.login_user_context(staff_user): data = {'post': True} response = self.client.post(endpoint, data) self.assertContains(response, '
') self.assertFalse(CMSPlugin.objects.filter(pk=plugin.pk).exists()) def test_user_cant_delete_plugin(self): """ User can't delete a plugin if he does not have change permissions on the model attached to the placeholder and/or does not have delete permissions on the plugin model. """ staff_user = self._staff_user placeholder = self._obj.placeholder plugin = self._add_plugin_to_placeholder(placeholder) endpoint = self.get_delete_plugin_uri(plugin) self.add_permission(staff_user, 'add_example1') self.add_permission(staff_user, 'delete_example1') self.add_permission(staff_user, 'delete_link') with self.login_user_context(staff_user): data = {'post': True} response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 403) self.assertTrue(CMSPlugin.objects.filter(pk=plugin.pk).exists()) self.add_permission(staff_user, 'change_example1') self.remove_permission(staff_user, 'delete_link') with self.login_user_context(staff_user): data = {'post': True} response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 403) self.assertTrue(CMSPlugin.objects.filter(pk=plugin.pk).exists()) def test_user_can_move_plugin(self): """ User can move a plugin if he has change permissions on the model attached to the placeholder and he has change permissions on the plugin model. """ staff_user = self._staff_user source_placeholder = self._obj.placeholder target_placeholder = self._get_example_obj().placeholder plugin = self._add_plugin_to_placeholder(source_placeholder) data = self._get_move_data(plugin, position=1, placeholder=target_placeholder) self.add_permission(staff_user, 'change_example1') self.add_permission(staff_user, 'change_link') with self.login_user_context(staff_user): endpoint = self.get_move_plugin_uri(plugin) response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 200) self.assertTrue(target_placeholder.get_plugins('en').filter(pk=plugin.pk)) self.assertFalse(source_placeholder.get_plugins('en').filter(pk=plugin.pk)) def test_user_cant_move_plugin(self): """ User can't move a plugin if he does not have change permissions on the model attached to the placeholder and/or does not have change permissions on the plugin model. """ staff_user = self._staff_user source_placeholder = self._obj.placeholder target_placeholder = self._get_example_obj().placeholder plugin = self._add_plugin_to_placeholder(source_placeholder) data = self._get_move_data(plugin, position=1, placeholder=target_placeholder) self.add_permission(staff_user, 'add_example1') self.add_permission(staff_user, 'delete_example1') self.add_permission(staff_user, 'change_link') with self.login_user_context(staff_user): endpoint = self.get_move_plugin_uri(plugin) response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 403) self.assertFalse(target_placeholder.get_plugins('en').filter(pk=plugin.pk)) self.assertTrue(source_placeholder.get_plugins('en').filter(pk=plugin.pk)) self.add_permission(staff_user, 'change_example1') self.remove_permission(staff_user, 'change_link') with self.login_user_context(staff_user): response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 403) self.assertFalse(target_placeholder.get_plugins('en').filter(pk=plugin.pk)) self.assertTrue(source_placeholder.get_plugins('en').filter(pk=plugin.pk)) def test_user_can_copy_plugin(self): """ User can copy a plugin if he has change permissions on the model attached to the placeholder and he has add permissions on the plugin model. """ staff_user = self._staff_user placeholder = self._obj.placeholder plugin = self._add_plugin_to_placeholder(placeholder) endpoint = self.get_copy_plugin_uri(plugin) source_placeholder = plugin.placeholder target_placeholder = self._get_example_obj().placeholder data = { 'source_plugin_id': plugin.pk, 'source_placeholder_id': source_placeholder.pk, 'source_language': plugin.language, 'target_language': 'en', 'target_placeholder_id': target_placeholder.pk, } self.add_permission(staff_user, 'change_example1') self.add_permission(staff_user, 'add_link') with self.login_user_context(staff_user): response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 200) self.assertTrue(source_placeholder.get_plugins('en').filter(pk=plugin.pk).exists()) self.assertTrue( target_placeholder .get_plugins('en') .filter(plugin_type=plugin.plugin_type) .exists() ) def test_user_cant_copy_plugin(self): """ User can't copy a plugin if he does not have change permissions on the model attached to the placeholder and/or does not have add permissions on the plugin model. """ staff_user = self._staff_user placeholder = self._obj.placeholder plugin = self._add_plugin_to_placeholder(placeholder) endpoint = self.get_copy_plugin_uri(plugin) source_placeholder = plugin.placeholder target_placeholder = self._get_example_obj().placeholder data = { 'source_plugin_id': plugin.pk, 'source_placeholder_id': source_placeholder.pk, 'source_language': plugin.language, 'target_language': 'en', 'target_placeholder_id': target_placeholder.pk, } self.add_permission(staff_user, 'add_example1') self.add_permission(staff_user, 'delete_example1') self.add_permission(staff_user, 'add_link') with self.login_user_context(staff_user): response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 403) self.assertTrue(source_placeholder.get_plugins('en').filter(pk=plugin.pk).exists()) self.assertFalse( target_placeholder .get_plugins('en') .filter(plugin_type=plugin.plugin_type) .exists() ) self.add_permission(staff_user, 'change_example1') self.remove_permission(staff_user, 'add_link') with self.login_user_context(staff_user): response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 403) self.assertTrue(source_placeholder.get_plugins('en').filter(pk=plugin.pk).exists()) self.assertFalse( target_placeholder .get_plugins('en') .filter(plugin_type=plugin.plugin_type) .exists() ) def test_user_can_clear_empty_placeholder(self): """ User can clear a placeholder if he has change permissions on the model attached to the placeholder. """ staff_user = self._staff_user placeholder = self._obj.placeholder endpoint = self.get_clear_placeholder_url(placeholder) self.add_permission(staff_user, 'change_example1') with self.login_user_context(staff_user): response = self.client.post(endpoint, {'test': 0}) self.assertEqual(response.status_code, 200) def test_user_cant_clear_empty_placeholder(self): """ User can't clear a placeholder if he does not have change permissions on the model attached to the placeholder. """ staff_user = self._staff_user placeholder = self._obj.placeholder endpoint = self.get_clear_placeholder_url(placeholder) with self.login_user_context(staff_user): response = self.client.post(endpoint, {'test': 0}) self.assertEqual(response.status_code, 403) def test_user_can_clear_non_empty_placeholder(self): """ User can clear a placeholder with plugins if he has change permissions on the model attached to the placeholder and delete permissions on the plugin model. """ staff_user = self._staff_user placeholder = self._obj.placeholder plugins = [ self._add_plugin_to_placeholder(placeholder, 'StylePlugin'), self._add_plugin_to_placeholder(placeholder, 'LinkPlugin'), ] placeholder = plugins[0].placeholder endpoint = self.get_clear_placeholder_url(placeholder) self.add_permission(staff_user, 'delete_style') self.add_permission(staff_user, 'delete_link') self.add_permission(staff_user, 'change_example1') with self.login_user_context(staff_user): response = self.client.post(endpoint, {'test': 0}) self.assertEqual(response.status_code, 200) self.assertEqual(placeholder.get_plugins('en').count(), 0) def test_user_cant_clear_non_empty_placeholder(self): """ User can't clear a placeholder with plugins if he does not have change permissions on the model attached to the placeholder and/or does not have delete permissions on the plugin model. """ staff_user = self._staff_user placeholder = self._obj.placeholder plugins = [ self._add_plugin_to_placeholder(placeholder, 'StylePlugin'), self._add_plugin_to_placeholder(placeholder, 'LinkPlugin'), ] placeholder = plugins[0].placeholder endpoint = self.get_clear_placeholder_url(placeholder) self.add_permission(staff_user, 'delete_text') self.add_permission(staff_user, 'delete_link') with self.login_user_context(staff_user): response = self.client.post(endpoint, {'test': 0}) self.assertEqual(response.status_code, 403) self.assertEqual(placeholder.get_plugins('en').count(), 2) def test_user_can_copy_placeholder_to_clipboard(self): """ User can copy a placeholder to the clipboard if he has add permissions on the plugin models being copied. """ staff_user = self._staff_user source_placeholder = self._obj.placeholder endpoint = self.get_copy_placeholder_uri(source_placeholder) self._add_plugin_to_placeholder(source_placeholder, 'StylePlugin') self._add_plugin_to_placeholder(source_placeholder, 'LinkPlugin') user_settings = UserSettings.objects.create( language="en", user=staff_user, clipboard=Placeholder.objects.create(), ) self.add_permission(staff_user, 'change_example1') self.add_permission(staff_user, 'add_link') self.add_permission(staff_user, 'add_style') data = { 'source_plugin_id': '', 'source_placeholder_id': source_placeholder.pk, 'source_language': 'en', 'target_language': 'en', 'target_placeholder_id': user_settings.clipboard.pk, } with self.login_user_context(staff_user): # Copy plugins into the clipboard response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 200) clipboard_plugins = user_settings.clipboard.get_plugins() # assert the clipboard has a PlaceholderPlugin self.assertTrue(clipboard_plugins.filter(plugin_type='PlaceholderPlugin').exists()) self.assertEqual(len(clipboard_plugins), 1) placeholder_plugin = clipboard_plugins[0].get_plugin_instance()[0] ref_placeholder = placeholder_plugin.placeholder_ref # assert there's only two plugins in the clipboard self.assertEqual(ref_placeholder.get_plugins().count(), 2) def test_user_cant_copy_placeholder_to_clipboard(self): """ User cant copy a placeholder to the clipboard if he does not have add permissions on the plugin models being copied. """ staff_user = self._staff_user source_placeholder = self._obj.placeholder endpoint = self.get_copy_placeholder_uri(source_placeholder) self._add_plugin_to_placeholder(source_placeholder, 'StylePlugin') self._add_plugin_to_placeholder(source_placeholder, 'LinkPlugin') user_settings = UserSettings.objects.create( language="en", user=staff_user, clipboard=Placeholder.objects.create(), ) self.add_permission(staff_user, 'change_link') self.add_permission(staff_user, 'delete_link') self.add_permission(staff_user, 'change_style') self.add_permission(staff_user, 'delete_style') data = { 'source_plugin_id': '', 'source_placeholder_id': source_placeholder.pk, 'source_language': 'en', 'target_language': 'en', 'target_placeholder_id': user_settings.clipboard.pk, } with self.login_user_context(staff_user): # Copy plugins into the clipboard response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 403) clipboard_plugins = user_settings.clipboard.get_plugins() self.assertEqual(len(clipboard_plugins), 0) def test_user_can_paste_from_clipboard(self): """ User can paste plugins from the clipboard if he has change permissions on the model attached to the target placeholder and he has add permissions on the plugin models being copied. """ staff_user = self._staff_user target_placeholder = self._obj.placeholder self.add_permission(staff_user, 'change_example1') self.add_permission(staff_user, 'add_link') user_settings = UserSettings.objects.create( language="en", user=staff_user, clipboard=Placeholder.objects.create(), ) placeholder_plugin = self._add_plugin_to_placeholder( user_settings.clipboard, 'PlaceholderPlugin', ) ref_placeholder = placeholder_plugin.placeholder_ref self._add_plugin_to_placeholder(ref_placeholder) self._add_plugin_to_placeholder(ref_placeholder) with self.login_user_context(staff_user): # Paste plugins from clipboard into placeholder # under the french language. data = { 'placeholder_id': target_placeholder.pk, 'plugin_id': placeholder_plugin.pk, 'plugin_parent': '', 'target_language': 'fr', 'move_a_copy': True, 'target_position': target_placeholder.get_next_plugin_position('fr', insert_order='last'), } endpoint = self.get_move_plugin_uri(placeholder_plugin) response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 200) self.assertEqual(target_placeholder.get_plugins('fr').count(), 2) def test_user_cant_paste_from_clipboard(self): """ User cant paste plugins from the clipboard if he does not have change permissions on the model attached to the target placeholder and/or does not have add permissions on the plugin models being copied. """ staff_user = self._staff_user target_placeholder = self._obj.placeholder self.add_permission(staff_user, 'add_example1') self.add_permission(staff_user, 'delete_example1') self.add_permission(staff_user, 'add_link') user_settings = UserSettings.objects.create( language="en", user=staff_user, clipboard=Placeholder.objects.create(), ) placeholder_plugin = self._add_plugin_to_placeholder( user_settings.clipboard, 'PlaceholderPlugin', ) ref_placeholder = placeholder_plugin.placeholder_ref self._add_plugin_to_placeholder(ref_placeholder) self._add_plugin_to_placeholder(ref_placeholder) with self.login_user_context(staff_user): # Paste plugins from clipboard into placeholder # under the french language. data = { 'placeholder_id': target_placeholder.pk, 'plugin_id': placeholder_plugin.pk, 'plugin_parent': '', 'target_language': 'fr', 'move_a_copy': True, 'target_position': target_placeholder.get_next_plugin_position('fr', insert_order='last'), } endpoint = self.get_move_plugin_uri(placeholder_plugin) response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 403) self.assertEqual(target_placeholder.get_plugins('fr').count(), 0) self.add_permission(staff_user, 'change_example1') self.remove_permission(staff_user, 'add_link') with self.login_user_context(staff_user): # Paste plugins from clipboard into placeholder # under the french language. data = { 'placeholder_id': target_placeholder.pk, 'plugin_id': placeholder_plugin.pk, 'plugin_parent': '', 'target_language': 'fr', 'move_a_copy': True, 'target_position': target_placeholder.get_next_plugin_position('fr', insert_order='last'), } response = self.client.post(endpoint, data) self.assertEqual(response.status_code, 403) self.assertEqual(target_placeholder.get_plugins('fr').count(), 0) class AppAdminInlineEditPermissionsTest(AppAdminTestCase): """Tests that the PlaceholderAdmin's edit_field endpoint (inline editing) checks plugin change permissions and runs the placeholder's check_source method.""" def setUp(self): from cms.test_utils.project.pluginapp.plugins.link.cms_plugins import LinkPlugin self._obj = self._get_example_obj() self._staff_user = self.get_staff_user_with_no_permissions() # LinkPlugin does not define frontend_editable_fields by default, # so we patch it for these tests to enable inline editing of the "name" field. self._fe_patcher = patch.object(LinkPlugin, "frontend_editable_fields", ("name",), create=True) self._fe_patcher.start() def tearDown(self): self._fe_patcher.stop() def _get_edit_field_endpoint(self, plugin): return ( admin_reverse("cms_placeholder_edit_field", args=(plugin.pk, "en")) + "?edit_fields=name" ) def test_inline_edit_checks_change_plugin_permission(self): """ Inline editing a plugin via PlaceholderAdmin's edit_field endpoint requires change permission on the model attached to the placeholder and change permission on the plugin model. """ staff_user = self._staff_user placeholder = self._obj.placeholder plugin = self._add_plugin_to_placeholder(placeholder) endpoint = self._get_edit_field_endpoint(plugin) # Give change permission on the plugin model but NOT on the source model self.add_permission(staff_user, 'change_link') with self.login_user_context(staff_user): response = self.client.get(endpoint) # Should be denied because user lacks change_example1 permission self.assertContains(response, "You do not have permission to edit this item") def test_inline_edit_allowed_with_correct_permissions(self): """ Inline editing a plugin via PlaceholderAdmin's edit_field endpoint succeeds when user has both change permission on the source model and change permission on the plugin model. """ staff_user = self._staff_user placeholder = self._obj.placeholder plugin = self._add_plugin_to_placeholder(placeholder) endpoint = self._get_edit_field_endpoint(plugin) # Give all required permissions self.add_permission(staff_user, 'change_example1') self.add_permission(staff_user, 'change_link') with self.login_user_context(staff_user): response = self.client.get(endpoint) # Should show the edit form self.assertEqual(response.status_code, 200) self.assertNotContains(response, "You do not have permission to edit this item") def test_inline_edit_calls_check_source(self): """ Inline editing a plugin via PlaceholderAdmin's edit_field endpoint runs the placeholder's check_source method to verify source-level permissions. """ staff_user = self._staff_user placeholder = self._obj.placeholder plugin = self._add_plugin_to_placeholder(placeholder) endpoint = self._get_edit_field_endpoint(plugin) self.add_permission(staff_user, 'change_example1') self.add_permission(staff_user, 'change_link') with self.login_user_context(staff_user): with patch.object( Placeholder, "check_source", return_value=False ) as mock_check_source: response = self.client.get(endpoint) # check_source should have been called mock_check_source.assert_called_once_with(staff_user) # Should be denied because check_source returned False self.assertContains(response, "You do not have permission to edit this item")