def test_inherit_plugin_with_empty_plugin(self): inheritfrompage = create_page('page to inherit from', 'nav_playground.html', 'en', published=True) body = inheritfrompage.placeholders.get(slot="body") empty_plugin = CMSPlugin( plugin_type='TextPlugin', # create an empty plugin placeholder=body, position=1, language='en', ) empty_plugin.insert_at(None, position='last-child', save=True) other_page = create_page('other page', 'nav_playground.html', 'en', published=True) inherited_body = other_page.placeholders.get(slot="body") inherit_plugin = InheritPagePlaceholder( plugin_type='InheritPagePlaceholderPlugin', placeholder=inherited_body, position=1, language='en', from_page=inheritfrompage, from_language='en' ) inherit_plugin.insert_at(None, position='last-child', save=True) add_plugin(inherited_body, "TextPlugin", "en", body="foobar") # this should not fail, even if there in an empty plugin rendered = inherited_body.render(context=self.get_context(other_page.get_absolute_url()), width=200) self.assertIn("foobar", rendered)
def add_plugin(self, request): # only allow POST if request.method != "POST": raise Http404 plugin_type = request.POST['plugin_type'] if not has_plugin_permission(request.user, plugin_type, "add"): return HttpResponseForbidden( "You don't have permission to add plugins") placeholder_id = request.POST.get('placeholder', None) position = None language = get_language_from_request(request) parent = None # check if we got a placeholder (id) if placeholder_id: placeholder = get_object_or_404(Placeholder, pk=placeholder_id) else: # else get the parent_id parent_id = request.POST.get('parent_id', None) if not parent_id: # if we get neither a placeholder nor a parent, bail out raise Http404 parent = get_object_or_404(CMSPlugin, pk=parent_id) placeholder = parent.placeholder # check add permissions on placeholder if not placeholder.has_add_permission(request): return HttpResponseForbidden( _("You don't have permission to add content here.")) # check the limits defined in CMS_PLACEHOLDER_CONF for this placeholder limits = settings.CMS_PLACEHOLDER_CONF.get(placeholder.slot, {}).get('limits', None) if limits: count = placeholder.cmsplugin_set.count() global_limit = limits.get("global", None) type_limit = limits.get(plugin_type, None) # check the global limit first if global_limit and count >= global_limit: return HttpResponseBadRequest( "This placeholder already has the maximum number of plugins." ) elif type_limit: # then check the type specific limit type_count = CMSPlugin.objects.filter( language=language, placeholder=placeholder, plugin_type=plugin_type).count() if type_count >= type_limit: return HttpResponseBadRequest( "This placeholder already has the maximum number (%s) " "of %s plugins." % (type_limit, plugin_type)) # actually add the plugin plugin = CMSPlugin(language=language, plugin_type=plugin_type, position=position, placeholder=placeholder, parent=parent) plugin.save() # returns it's ID as response return HttpResponse(str(plugin.pk))
def save_body(self, placeholder, desc): language = settings.LANGUAGE_CODE try: plugin = CMSPlugin.objects.get(placeholder=placeholder, position=0, language=language) plugin.body = desc except CMSPlugin.DoesNotExist: plugin = CMSPlugin(language=language, plugin_type="TextPlugin", position=0, placeholder=placeholder) plugin.save() if plugin: text = Text() # text.set_base_attr(plugin) text.pk = plugin.pk text.id = plugin.pk text.placeholder = placeholder text.position = plugin.position text.plugin_type = plugin.plugin_type text.tree_id = plugin.tree_id text.lft = plugin.lft text.rght = plugin.rght text.level = plugin.level text.cmsplugin_ptr = plugin text.publisher_public_id = None text.public_id = None text.published = False text.language = language text.body = desc text.save()
def add_plugin(self, user=None, page=None, placeholder=None, language='en', body=''): if not placeholder: if page: placeholder = page.placeholders.get( slot__iexact='Right-Column') else: placeholder = page.placeholders.get( slot__iexact='Right-Column') plugin_base = CMSPlugin( plugin_type='TextPlugin', placeholder=placeholder, position=1, language=language) plugin_base.insert_at(None, position='last-child', commit=False) plugin = Text(body=body) plugin_base.set_base_attr(plugin) plugin.save() return plugin.pk
def add_plugin(placeholder, plugin_type, language, position='last-child', **data): """ Add a plugin to a placeholder See docs/extending_cms/api_reference.rst for more info """ # validate placeholder assert isinstance(placeholder, Placeholder) # validate and normalize plugin type plugin_model, plugin_type = _verify_plugin_type(plugin_type) plugin_base = CMSPlugin( plugin_type=plugin_type, placeholder=placeholder, position=1, language=language ) plugin_base.insert_at(None, position=position, save=False) plugin = plugin_model(**data) plugin_base.set_base_attr(plugin) plugin.save() return plugin
def add_plugin(placeholder, plugin_type, language, position='last-child', target=None, **data): """ Add a plugin to a placeholder See docs/extending_cms/api_reference.rst for more info """ # validate placeholder assert isinstance(placeholder, Placeholder) # validate and normalize plugin type plugin_model, plugin_type = _verify_plugin_type(plugin_type) max_pos = CMSPlugin.objects.filter(language=language, placeholder=placeholder).aggregate(Max('position'))['position__max'] or 0 plugin_base = CMSPlugin( plugin_type=plugin_type, placeholder=placeholder, position=max_pos + 1, language=language ) plugin_base.insert_at(target, position=position, save=False) plugin = plugin_model(**data) plugin_base.set_base_attr(plugin) plugin.save() return plugin
def save_body(self, placeholder, desc): language = settings.LANGUAGE_CODE try: plugin = CMSPlugin.objects.get(placeholder=placeholder, position=0, language=language) plugin.body = desc except CMSPlugin.DoesNotExist: plugin = CMSPlugin(language=language, plugin_type='TextPlugin', position=0, placeholder=placeholder) plugin.save() if plugin: text = Text() #text.set_base_attr(plugin) text.pk = plugin.pk text.id = plugin.pk text.placeholder = placeholder text.position = plugin.position text.plugin_type = plugin.plugin_type text.tree_id = plugin.tree_id text.lft = plugin.lft text.rght = plugin.rght text.level = plugin.level text.cmsplugin_ptr = plugin text.publisher_public_id = None text.public_id = None text.published = False text.language = language text.body = desc text.save()
def test_delete_with_plugins(self): """ Check that plugins and placeholders get correctly deleted when we delete a page! """ home = create_page("home", "nav_playground.html", "en") page = create_page("page", "nav_playground.html", "en") page.rescan_placeholders() # create placeholders placeholder = page.placeholders.all()[0] plugin_base = CMSPlugin( plugin_type='TextPlugin', placeholder=placeholder, position=1, language=settings.LANGUAGES[0][0] ) plugin_base = plugin_base.add_root(instance=plugin_base) plugin = Text(body='') plugin_base.set_base_attr(plugin) plugin.save() self.assertEqual(CMSPlugin.objects.count(), 1) self.assertEqual(Text.objects.count(), 1) self.assertTrue(Placeholder.objects.count() > 2) page.delete() home.delete() self.assertEqual(CMSPlugin.objects.count(), 0) self.assertEqual(Text.objects.count(), 0) self.assertEqual(Placeholder.objects.count(), 0) self.assertEqual(Page.objects.count(), 0)
def test_delete_with_plugins(self): """ Check that plugins and placeholders get correctly deleted when we delete a page! """ home = create_page("home", "nav_playground.html", "en") page = create_page("page", "nav_playground.html", "en") page.rescan_placeholders() # create placeholders placeholder = page.placeholders.all()[0] plugin_base = CMSPlugin( plugin_type='TextPlugin', placeholder=placeholder, position=1, language=settings.LANGUAGES[0][0] ) plugin_base.insert_at(None, position='last-child', save=False) plugin = Text(body='') plugin_base.set_base_attr(plugin) plugin.save() self.assertEqual(CMSPlugin.objects.count(), 1) self.assertEqual(Text.objects.count(), 1) self.assertTrue(Placeholder.objects.count() > 2) page.delete() home.delete() self.assertEqual(CMSPlugin.objects.count(), 0) self.assertEqual(Text.objects.count(), 0) self.assertEqual(Placeholder.objects.count(), 0) self.assertEqual(Page.objects.count(), 0)
def add_plugin(self, request): # only allow POST if request.method != "POST": raise Http404 plugin_type = request.POST['plugin_type'] if not has_plugin_permission(request.user, plugin_type, "add"): return HttpResponseForbidden("You don't have permission to add plugins") placeholder_id = request.POST.get('placeholder', None) position = None language = get_language_from_request(request) parent = None # check if we got a placeholder (id) if placeholder_id: placeholder = get_object_or_404(Placeholder, pk=placeholder_id) else: # else get the parent_id parent_id = request.POST.get('parent_id', None) if not parent_id: # if we get neither a placeholder nor a parent, bail out raise Http404 parent = get_object_or_404(CMSPlugin, pk=parent_id) placeholder = parent.placeholder # check add permissions on placeholder if not placeholder.has_add_permission(request): return HttpResponseForbidden(_("You don't have permission to add content here.")) # check the limits defined in CMS_PLACEHOLDER_CONF for this placeholder limits = settings.CMS_PLACEHOLDER_CONF.get(placeholder.slot, {}).get('limits', None) if limits: count = placeholder.cmsplugin_set.count() global_limit = limits.get("global", None) type_limit = limits.get(plugin_type, None) # check the global limit first if global_limit and count >= global_limit: return HttpResponseBadRequest( "This placeholder already has the maximum number of plugins." ) elif type_limit: # then check the type specific limit type_count = CMSPlugin.objects.filter( language=language, placeholder=placeholder, plugin_type=plugin_type ).count() if type_count >= type_limit: return HttpResponseBadRequest( "This placeholder already has the maximum number (%s) " "of %s plugins." % (type_limit, plugin_type) ) # position plugin at the end of the list position = CMSPlugin.objects.filter(placeholder=placeholder).count() # actually add the plugin plugin = CMSPlugin(language=language, plugin_type=plugin_type, position=position, placeholder=placeholder, parent=parent) plugin.save() # returns it's ID as response return HttpResponse(str(plugin.pk))
def add_plugin(self, request): if request.method != "POST": raise Http404 plugin_type = request.POST['plugin_type'] placeholder_id = request.POST['placeholder'] placeholder = get_object_or_404(Placeholder, pk=placeholder_id) position = None language = get_language_from_request(request) plugin = CMSPlugin(language=language, plugin_type=plugin_type, position=position, placeholder=placeholder) plugin.save() return HttpResponse(str(plugin.pk))
def test_list_plugins(self): placeholder = Placeholder.objects.create(slot="test") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, TextPlugin, "en", body="en body") link_plugin = add_plugin(placeholder, "LinkPlugin", "en", name="A Link", url="https://www.django-cms.org") self.assertEqual( CMSPlugin.objects.filter(plugin_type=PLUGIN).count(), 2) self.assertEqual( CMSPlugin.objects.filter(plugin_type="LinkPlugin").count(), 1) # create a CMSPlugin with an unsaved instance instanceless_plugin = CMSPlugin(language="en", plugin_type="TextPlugin") instanceless_plugin.save() # create a bogus CMSPlugin to simulate one which used to exist but # is no longer installed bogus_plugin = CMSPlugin(language="en", plugin_type="BogusPlugin") bogus_plugin.save() report = plugin_report() # there should be reports for three plugin types self.assertEqual(len(report), 3) # check the bogus plugin bogus_plugins_report = report[0] self.assertEqual(bogus_plugins_report["model"], None) self.assertEqual(bogus_plugins_report["type"], u'BogusPlugin') self.assertEqual(bogus_plugins_report["instances"][0], bogus_plugin) # check the link plugin link_plugins_report = report[1] self.assertEqual(link_plugins_report["model"], link_plugin.__class__) self.assertEqual(link_plugins_report["type"], u'LinkPlugin') self.assertEqual( link_plugins_report["instances"][0].get_plugin_instance()[0], link_plugin) # check the text plugins text_plugins_report = report[2] self.assertEqual(text_plugins_report["model"], TextPlugin.model) self.assertEqual(text_plugins_report["type"], u'TextPlugin') self.assertEqual(len(text_plugins_report["instances"]), 3) self.assertEqual(text_plugins_report["instances"][2], instanceless_plugin) self.assertEqual(text_plugins_report["unsaved_instances"], [instanceless_plugin])
def test_check_plugin_instances(self): self.assertCheck(True, warnings=0, errors=0) placeholder = Placeholder.objects.create(slot="test") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, "LinkPlugin", "en", name="A Link", external_link="https://www.django-cms.org") # create a CMSPlugin with an unsaved instance instanceless_plugin = CMSPlugin(language="en", plugin_type="TextPlugin") instanceless_plugin.save() self.assertCheck(False, warnings=0, errors=2) # create a bogus CMSPlugin to simulate one which used to exist but # is no longer installed bogus_plugin = CMSPlugin(language="en", plugin_type="BogusPlugin") bogus_plugin.save() self.assertCheck(False, warnings=0, errors=3)
def test_check_plugin_instances(self): self.assertCheck(True, warnings=0, errors=0) apps = ["cms", "menus", "sekizai", "cms.test_utils.project.sampleapp"] with SettingsOverride(INSTALLED_APPS=apps): placeholder = Placeholder.objects.create(slot="test") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, TextPlugin, "en", body="en body") link_plugin = add_plugin(placeholder, "LinkPlugin", "en", name="A Link", url="https://www.django-cms.org") # create a CMSPlugin with an unsaved instance instanceless_plugin = CMSPlugin(language="en", plugin_type="TextPlugin") instanceless_plugin.save() self.assertCheck(False, warnings=0, errors=2) # create a bogus CMSPlugin to simulate one which used to exist but # is no longer installed bogus_plugin = CMSPlugin(language="en", plugin_type="BogusPlugin") bogus_plugin.save() self.assertCheck(False, warnings=0, errors=3)
def test_empty_plugin_is_ignored(self): page = create_page("page", "nav_playground.html", "en") placeholder = page.placeholders.get(slot='body') plugin = CMSPlugin(plugin_type='TextPlugin', placeholder=placeholder, position=1, language=self.FIRST_LANG) plugin.insert_at(None, position='last-child', save=True) # this should not raise any errors, but just ignore the empty plugin out = placeholder.render(self.get_context(), width=300) self.assertFalse(len(out)) self.assertFalse(len(placeholder._en_plugins_cache))
def test_delete_orphaned_plugins(self): apps = ["cms", "menus", "sekizai", "cms.test_utils.project.sampleapp"] with SettingsOverride(INSTALLED_APPS=apps): placeholder = Placeholder.objects.create(slot="test") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, TextPlugin, "en", body="en body") link_plugin = add_plugin(placeholder, "LinkPlugin", "en", name="A Link", url="https://www.django-cms.org") instanceless_plugin = CMSPlugin(language="en", plugin_type="TextPlugin") instanceless_plugin.save() # create a bogus CMSPlugin to simulate one which used to exist but # is no longer installed bogus_plugin = CMSPlugin(language="en", plugin_type="BogusPlugin") bogus_plugin.save() report = plugin_report() # there should be reports for three plugin types self.assertEqual(len(report), 3) # check the bogus plugin bogus_plugins_report = report[0] self.assertEqual(len(bogus_plugins_report["instances"]), 1) # check the link plugin link_plugins_report = report[1] self.assertEqual(len(link_plugins_report["instances"]), 1) # check the text plugins text_plugins_report = report[2] self.assertEqual(len(text_plugins_report["instances"]), 3) self.assertEqual(len(text_plugins_report["unsaved_instances"]), 1) management.call_command('cms', 'delete_orphaned_plugins', stdout=StringIO(), interactive=False) report = plugin_report() # there should be reports for two plugin types (one should have been deleted) self.assertEqual(len(report), 2) # check the link plugin link_plugins_report = report[0] self.assertEqual(len(link_plugins_report["instances"]), 1) # check the text plugins text_plugins_report = report[1] self.assertEqual(len(text_plugins_report["instances"]), 2) self.assertEqual(len(text_plugins_report["unsaved_instances"]), 0)
def test_empty_plugin_is_ignored(self): page = create_page("page", "nav_playground.html", "en") placeholder = page.placeholders.get(slot='body') plugin = CMSPlugin( plugin_type='TextPlugin', placeholder=placeholder, position=1, language=self.FIRST_LANG) plugin.insert_at(None, position='last-child', save=True) # this should not raise any errors, but just ignore the empty plugin out = placeholder.render(self.get_context(), width=300) self.assertFalse(len(out)) self.assertFalse(len(placeholder._en_plugins_cache))
def _cut_plugin(self, request, plugin, target_language, target_placeholder): if not self.has_move_plugin_permission(request, plugin, target_placeholder): message = force_str(_("You have no permission to cut this plugin")) raise PermissionDenied(message) plugin_data = { 'language': target_language, 'placeholder': target_placeholder, } source_language = plugin.language source_placeholder = plugin.placeholder source_tree_order = source_placeholder.get_plugin_tree_order( language=source_language, parent_id=plugin.parent_id, ) action_token = self._send_pre_placeholder_operation( request, operation=operations.CUT_PLUGIN, plugin=plugin, clipboard=target_placeholder, clipboard_language=target_language, source_language=source_language, source_placeholder=source_placeholder, source_parent_id=plugin.parent_id, source_order=source_tree_order, ) # Empty the clipboard target_placeholder.clear() target = CMSPlugin.get_last_root_node() updated_plugin = plugin.update(refresh=True, parent=None, **plugin_data) updated_plugin = updated_plugin.move(target, pos='right') # Update all children to match the parent's # language and placeholder (clipboard) updated_plugin.get_descendants().update(**plugin_data) # Avoid query by removing the plugin being moved # from the source order new_source_order = list(source_tree_order) new_source_order.remove(updated_plugin.pk) source_placeholder.mark_as_dirty(target_language, clear_cache=False) self._send_post_placeholder_operation( request, operation=operations.CUT_PLUGIN, token=action_token, plugin=updated_plugin.get_bound_plugin(), clipboard=target_placeholder, clipboard_language=target_language, source_language=source_language, source_placeholder=source_placeholder, source_parent_id=plugin.parent_id, source_order=new_source_order, ) return updated_plugin
def _copy_plugin_to_clipboard(self, request, source_placeholder, target_placeholder): source_language = request.POST['source_language'] source_plugin_id = request.POST.get('source_plugin_id') target_language = request.POST['target_language'] source_plugin = get_object_or_404( CMSPlugin, pk=source_plugin_id, language=source_language, ) old_plugins = (CMSPlugin.get_tree(parent=source_plugin).filter( placeholder=source_placeholder).order_by('path')) if not self.has_copy_plugins_permission(request, old_plugins): message = _('You do not have permission to copy these plugins.') raise PermissionDenied(force_text(message)) # Empty the clipboard target_placeholder.clear() plugin_pairs = copy_plugins.copy_plugins_to( old_plugins, to_placeholder=target_placeholder, to_language=target_language, ) return plugin_pairs[0][0]
def test_delete_orphaned_plugins(self): placeholder = Placeholder.objects.create(slot="test") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, "LinkPlugin", "en", name="A Link", external_link="https://www.django-cms.org") instanceless_plugin = CMSPlugin(language="en", plugin_type="TextPlugin") instanceless_plugin.save() # create a bogus CMSPlugin to simulate one which used to exist but # is no longer installed bogus_plugin = CMSPlugin(language="en", plugin_type="BogusPlugin") bogus_plugin.save() report = plugin_report() # there should be reports for three plugin types self.assertEqual(len(report), 3) # check the bogus plugin bogus_plugins_report = report[0] self.assertEqual(len(bogus_plugins_report["instances"]), 1) # check the link plugin link_plugins_report = report[1] self.assertEqual(len(link_plugins_report["instances"]), 1) # check the text plugins text_plugins_report = report[2] self.assertEqual(len(text_plugins_report["instances"]), 3) self.assertEqual(len(text_plugins_report["unsaved_instances"]), 1) out = io.StringIO() management.call_command('cms', 'delete-orphaned-plugins', interactive=False, stdout=out) report = plugin_report() # there should be reports for two plugin types (one should have been deleted) self.assertEqual(len(report), 2) # check the link plugin link_plugins_report = report[0] self.assertEqual(len(link_plugins_report["instances"]), 1) # check the text plugins text_plugins_report = report[1] self.assertEqual(len(text_plugins_report["instances"]), 2) self.assertEqual(len(text_plugins_report["unsaved_instances"]), 0)
def add_plugin(self, request): """ POST request should have the following data: - placeholder_id - plugin_type - plugin_language - plugin_parent (optional) """ parent = None plugin_type = request.POST['plugin_type'] placeholder_id = request.POST.get('placeholder_id', None) placeholder = get_object_or_404(Placeholder, pk=placeholder_id) parent_id = request.POST.get('plugin_parent', None) language = request.POST.get('plugin_language') or get_language_from_request(request) if not self.has_add_plugin_permission(request, placeholder, plugin_type): return HttpResponseForbidden(force_text(_('You do not have permission to add a plugin'))) try: has_reached_plugin_limit(placeholder, plugin_type, language, template=self.get_placeholder_template(request, placeholder)) except PluginLimitReached as er: return HttpResponseBadRequest(er) # page add-plugin if not parent_id: position = request.POST.get('plugin_order', CMSPlugin.objects.filter(language=language, placeholder=placeholder).count()) # in-plugin add-plugin else: parent = get_object_or_404(CMSPlugin, pk=parent_id) placeholder = parent.placeholder position = request.POST.get('plugin_order', CMSPlugin.objects.filter(language=language, parent=parent).count()) # placeholder (non-page) add-plugin # Sanity check to make sure we're not getting bogus values from JavaScript: if settings.USE_I18N: if not language or not language in [lang[0] for lang in settings.LANGUAGES]: return HttpResponseBadRequest(force_text(_("Language must be set to a supported language!"))) if parent and parent.language != language: return HttpResponseBadRequest(force_text(_("Parent plugin language must be same as language!"))) else: language = settings.LANGUAGE_CODE plugin = CMSPlugin(language=language, plugin_type=plugin_type, position=position, placeholder=placeholder) if parent: plugin.position = CMSPlugin.objects.filter(parent=parent).count() plugin.parent_id = parent.pk plugin.save() self.post_add_plugin(request, placeholder, plugin) response = { 'url': force_text( admin_reverse("%s_%s_edit_plugin" % (self.model._meta.app_label, self.model._meta.model_name), args=[plugin.pk])), 'delete': force_text( admin_reverse("%s_%s_delete_plugin" % (self.model._meta.app_label, self.model._meta.model_name), args=[plugin.pk])), 'breadcrumb': plugin.get_breadcrumb(), } return HttpResponse(json.dumps(response), content_type='application/json')
def add_plugin(placeholder, plugin_type, language, position='last-child', **data): """ Taken from django-cms api (in newer versions) https://github.com/divio/django-cms/blob/b8633b42efcd137d96e1e3f42e004cb7595768fe/cms/api.py """ assert isinstance(placeholder, Placeholder) plugin_model = plugin_type.model plugin_type = plugin_type.__name__ plugin_base = CMSPlugin( plugin_type=plugin_type, placeholder=placeholder, position=1, language=language ) plugin_base.insert_at(None, position='last-child', commit=False) plugin = plugin_model(**data) plugin_base.set_base_attr(plugin) plugin.save() return plugin
def move_plugin(self, request): """ POST request with following parameters: -plugin_id -placeholder_id -plugin_language (optional) -plugin_parent (optional) -plugin_order (array, optional) """ plugin = CMSPlugin.objects.get(pk=int(request.POST['plugin_id'])) placeholder = Placeholder.objects.get(pk=request.POST['placeholder_id']) parent_id = request.POST.get('plugin_parent', None) language = request.POST.get('plugin_language', None) source_placeholder = plugin.placeholder if not parent_id: parent_id = None else: parent_id = int(parent_id) if not language and plugin.language: language = plugin.language order = request.POST.getlist("plugin_order[]") if not self.has_move_plugin_permission(request, plugin, placeholder): return HttpResponseForbidden(force_text(_("You have no permission to move this plugin"))) if not placeholder == source_placeholder: try: template = self.get_placeholder_template(request, placeholder) has_reached_plugin_limit(placeholder, plugin.plugin_type, plugin.language, template=template) except PluginLimitReached as er: return HttpResponseBadRequest(er) if parent_id: if plugin.parent_id != parent_id: parent = CMSPlugin.objects.get(pk=parent_id) if parent.placeholder_id != placeholder.pk: return HttpResponseBadRequest(force_text('parent must be in the same placeholder')) if parent.language != language: return HttpResponseBadRequest(force_text('parent must be in the same language as plugin_language')) plugin.parent_id = parent.pk plugin.save() plugin = plugin.move(parent, pos='last-child') else: sibling = CMSPlugin.get_last_root_node() plugin.parent_id = None plugin.save() plugin = plugin.move(sibling, pos='right') for child in [plugin] + list(plugin.get_descendants()): child.placeholder = placeholder child.language = language child.save() plugins = reorder_plugins(placeholder, parent_id, language, order) if not plugins: return HttpResponseBadRequest('order parameter did not have all plugins of the same level in it') self.post_move_plugin(request, source_placeholder, placeholder, plugin) json_response = {'reload': requires_reload(PLUGIN_MOVE_ACTION, [plugin])} return HttpResponse(json.dumps(json_response), content_type='application/json')
def add_plugin(self, request): if request.method != "POST": raise Http404 plugin_type = request.POST['plugin_type'] placeholder_id = request.POST.get('placeholder', None) position = None language = get_language_from_request(request) if not placeholder_id: parent_id = request.POST.get('parent_id', None) if not parent_id: raise Http404 parent = get_object_or_404(CMSPlugin, pk=parent_id) plugin = CMSPlugin(language=language, plugin_type=plugin_type, position=position, parent=parent, placeholder=parent.placeholder) else: placeholder = get_object_or_404(Placeholder, pk=placeholder_id) plugin = CMSPlugin(language=language, plugin_type=plugin_type, position=position, placeholder=placeholder) plugin.save() return HttpResponse(str(plugin.pk))
def add_plugin(placeholder, plugin_type, language, position='last-child', target=None, **data): """ Add a plugin to a placeholder See docs/extending_cms/api_reference.rst for more info """ # validate placeholder assert isinstance(placeholder, Placeholder) # validate and normalize plugin type plugin_model, plugin_type = _verify_plugin_type(plugin_type) if target: if position == 'last-child': new_pos = CMSPlugin.objects.filter(language=language, parent=target, tree_id=target.tree_id).count() elif position == 'first-child': new_pos = 0 elif position == 'left': new_pos = target.position elif position == 'right': new_pos = target.position + 1 else: raise Exception('position not supported: %s' % position) for pl in CMSPlugin.objects.filter(language=language, parent=target.parent_id, tree_id=target.tree_id, position__gte=new_pos): pl.position += 1 pl.save() else: new_pos = CMSPlugin.objects.filter(language=language, parent__isnull=True, placeholder=placeholder).count() plugin_base = CMSPlugin( plugin_type=plugin_type, placeholder=placeholder, position=new_pos, language=language ) plugin_base.insert_at(target, position=position, save=False) plugin = plugin_model(**data) plugin_base.set_base_attr(plugin) plugin.save() return plugin
def add_plugin(placeholder, plugin_type, language, position='last-child', target=None, **data): """ Add a plugin to a placeholder See docs/extending_cms/api_reference.rst for more info """ # validate placeholder assert isinstance(placeholder, Placeholder) # validate and normalize plugin type plugin_model, plugin_type = _verify_plugin_type(plugin_type) max_pos = CMSPlugin.objects.filter( language=language, placeholder=placeholder).aggregate( Max('position'))['position__max'] or 0 plugin_base = CMSPlugin(plugin_type=plugin_type, placeholder=placeholder, position=max_pos + 1, language=language) plugin_base.insert_at(target, position=position, save=False) plugin = plugin_model(**data) plugin_base.set_base_attr(plugin) plugin.save() return plugin
def add_plugin(self, request): """ POST request should have the following data: - placeholder_id - plugin_type - plugin_language - plugin_parent (optional) """ parent = None plugin_type = request.POST['plugin_type'] placeholder_id = request.POST.get('placeholder_id', None) placeholder = get_object_or_404(Placeholder, pk=placeholder_id) parent_id = request.POST.get('plugin_parent', None) language = request.POST.get('plugin_language') or get_language_from_request(request) if not self.has_add_plugin_permission(request, placeholder, plugin_type): return HttpResponseForbidden(force_unicode(_('You do not have permission to add a plugin'))) try: has_reached_plugin_limit(placeholder, plugin_type, language, template=self.get_placeholder_template(request, placeholder)) except PluginLimitReached as er: return HttpResponseBadRequest(er) # page add-plugin if not parent_id: position = request.POST.get('plugin_order', CMSPlugin.objects.filter(language=language, placeholder=placeholder).count()) # in-plugin add-plugin else: parent = get_object_or_404(CMSPlugin, pk=parent_id) placeholder = parent.placeholder position = request.POST.get('plugin_order', CMSPlugin.objects.filter(language=language, parent=parent).count()) # placeholder (non-page) add-plugin # Sanity check to make sure we're not getting bogus values from JavaScript: if settings.USE_I18N: if not language or not language in [lang[0] for lang in settings.LANGUAGES]: return HttpResponseBadRequest(force_unicode(_("Language must be set to a supported language!"))) if parent and parent.language != language: return HttpResponseBadRequest(force_unicode(_("Parent plugin language must be same as language!"))) else: language = settings.LANGUAGE_CODE plugin = CMSPlugin(language=language, plugin_type=plugin_type, position=position, placeholder=placeholder) if parent: plugin.position = CMSPlugin.objects.filter(parent=parent).count() plugin.parent_id = parent.pk plugin.save() self.post_add_plugin(request, placeholder, plugin) response = { 'url': force_unicode( admin_reverse("%s_%s_edit_plugin" % (self.model._meta.app_label, self.model._meta.model_name), args=[plugin.pk])), 'delete': force_unicode( admin_reverse("%s_%s_delete_plugin" % (self.model._meta.app_label, self.model._meta.model_name), args=[plugin.pk])), 'breadcrumb': plugin.get_breadcrumb(), } return HttpResponse(json.dumps(response), content_type='application/json')
def setUp(self): super().setUp() self.hats = Theme.objects.create( name='Hats', slug='hats', blurb='People must wear hats to the party', description='Any hat goes but Red Hat or Fedora get extra points') self.orange = Theme.objects.create( name='Orange clothes', slug='orange-clothes', blurb='People must wear orange clothes to the party', description='Come dressed as an orange for extra points') self.instance = CMSPlugin()
def copy_plugins_to_placeholder(plugins, placeholder, language=None, root_plugin=None): plugin_pairs = [] plugins_by_id = {} for source_plugin in get_bound_plugins(plugins): parent = plugins_by_id.get(source_plugin.parent_id, root_plugin) plugin_model = get_plugin_model(source_plugin.plugin_type) if plugin_model != CMSPlugin: new_plugin = deepcopy(source_plugin) new_plugin.pk = None new_plugin.id = None new_plugin._state.adding = True new_plugin.language = language or new_plugin.language new_plugin.placeholder = placeholder new_plugin.parent = parent new_plugin.numchild = 0 else: new_plugin = plugin_model( language=(language or source_plugin.language), parent=parent, plugin_type=source_plugin.plugin_type, placeholder=placeholder, position=source_plugin.position, ) if parent: new_plugin = parent.add_child(instance=new_plugin) else: new_plugin = CMSPlugin.add_root(instance=new_plugin) if plugin_model != CMSPlugin: new_plugin.copy_relations(source_plugin) plugin_pairs.append((new_plugin, source_plugin)) plugins_by_id[source_plugin.pk] = new_plugin # Backwards compatibility # This magic is needed for advanced plugins like Text Plugins that can have # nested plugins and need to update their content based on the new plugins. for new_plugin, old_plugin in plugin_pairs: new_plugin.post_copy(old_plugin, plugin_pairs) return [pair[0] for pair in plugin_pairs]
def test_list_plugins(self): out = StringIO() apps = ["cms", "menus", "sekizai", "cms.test_utils.project.sampleapp"] with SettingsOverride(INSTALLED_APPS=apps): placeholder = Placeholder.objects.create(slot="test") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, TextPlugin, "en", body="en body") link_plugin = add_plugin(placeholder, "LinkPlugin", "en", name="A Link", url="https://www.django-cms.org") self.assertEqual(CMSPlugin.objects.filter(plugin_type=PLUGIN).count(), 2) self.assertEqual(CMSPlugin.objects.filter(plugin_type="LinkPlugin").count(), 1) # create a CMSPlugin with an unsaved instance instanceless_plugin = CMSPlugin(language="en", plugin_type="TextPlugin") instanceless_plugin.save() # create a bogus CMSPlugin to simulate one which used to exist but # is no longer installed bogus_plugin = CMSPlugin(language="en", plugin_type="BogusPlugin") bogus_plugin.save() report = plugin_report() # there should be reports for three plugin types self.assertEqual(len(report), 3) # check the bogus plugin bogus_plugins_report = report[0] self.assertEqual(bogus_plugins_report["model"], None) self.assertEqual(bogus_plugins_report["type"], u"BogusPlugin") self.assertEqual(bogus_plugins_report["instances"][0], bogus_plugin) # check the link plugin link_plugins_report = report[1] self.assertEqual(link_plugins_report["model"], link_plugin.__class__) self.assertEqual(link_plugins_report["type"], u"LinkPlugin") self.assertEqual(link_plugins_report["instances"][0].get_plugin_instance()[0], link_plugin) # check the text plugins text_plugins_report = report[2] self.assertEqual(text_plugins_report["model"], TextPlugin.model) self.assertEqual(text_plugins_report["type"], u"TextPlugin") self.assertEqual(len(text_plugins_report["instances"]), 3) self.assertEqual(text_plugins_report["instances"][2], instanceless_plugin) self.assertEqual(text_plugins_report["unsaved_instances"], [instanceless_plugin])
def test_delete_orphaned_plugins(self): apps = ["cms", "menus", "sekizai", "cms.test_utils.project.sampleapp"] with SettingsOverride(INSTALLED_APPS=apps): placeholder = Placeholder.objects.create(slot="test") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, TextPlugin, "en", body="en body") link_plugin = add_plugin(placeholder, "LinkPlugin", "en", name="A Link", url="https://www.django-cms.org") instanceless_plugin = CMSPlugin(language="en", plugin_type="TextPlugin") instanceless_plugin.save() # create a bogus CMSPlugin to simulate one which used to exist but # is no longer installed bogus_plugin = CMSPlugin(language="en", plugin_type="BogusPlugin") bogus_plugin.save() report = plugin_report() # there should be reports for three plugin types self.assertEqual(len(report), 3) # check the bogus plugin bogus_plugins_report = report[0] self.assertEqual(len(bogus_plugins_report["instances"]), 1) # check the link plugin link_plugins_report = report[1] self.assertEqual(len(link_plugins_report["instances"]), 1) # check the text plugins text_plugins_report = report[2] self.assertEqual(len(text_plugins_report["instances"]), 3) self.assertEqual(len(text_plugins_report["unsaved_instances"]), 1) management.call_command("cms", "delete_orphaned_plugins", stdout=StringIO(), interactive=False) report = plugin_report() # there should be reports for two plugin types (one should have been deleted) self.assertEqual(len(report), 2) # check the link plugin link_plugins_report = report[0] self.assertEqual(len(link_plugins_report["instances"]), 1) # check the text plugins text_plugins_report = report[1] self.assertEqual(len(text_plugins_report["instances"]), 2) self.assertEqual(len(text_plugins_report["unsaved_instances"]), 0)
def add_plugin(placeholder, plugin_type, language, position='last-child', target=None, **data): """ Add a plugin to a placeholder See docs/extending_cms/api_reference.rst for more info """ # validate placeholder assert isinstance(placeholder, Placeholder) # validate and normalize plugin type plugin_model, plugin_type = _verify_plugin_type(plugin_type) if target: if position == 'last-child': new_pos = CMSPlugin.objects.filter(language=language, parent=target, tree_id=target.tree_id).count() elif position == 'first-child': new_pos = 0 elif position == 'left': new_pos = target.position elif position == 'right': new_pos = target.position + 1 else: raise Exception('position not supported: %s' % position) for pl in CMSPlugin.objects.filter(language=language, parent=target.parent_id, tree_id=target.tree_id, position__gte=new_pos): pl.position += 1 pl.save() else: new_pos = CMSPlugin.objects.filter(language=language, parent__isnull=True, placeholder=placeholder).count() plugin_base = CMSPlugin(plugin_type=plugin_type, placeholder=placeholder, position=new_pos, language=language) plugin_base.insert_at(target, position=position, save=False) plugin = plugin_model(**data) plugin_base.set_base_attr(plugin) plugin.save() return plugin
def add_plugin(self, user=None, page=None, placeholder=None, language='en', body=''): if not placeholder: if page: placeholder = page.placeholders.get(slot__iexact='Right-Column') else: placeholder = page.placeholders.get(slot__iexact='Right-Column') plugin_base = CMSPlugin( plugin_type='TextPlugin', placeholder=placeholder, position=1, language=language ) plugin_base.insert_at(None, position='last-child', commit=False) plugin = Text(body=body) plugin_base.set_base_attr(plugin) plugin.save() return plugin.pk
def add_plugin(placeholder, plugin_type, language, position='last-child', **data): """ Taken from django-cms api (in newer versions) https://github.com/divio/django-cms/blob/b8633b42efcd137d96e1e3f42e004cb7595768fe/cms/api.py """ assert isinstance(placeholder, Placeholder) plugin_model = plugin_type.model plugin_type = plugin_type.__name__ plugin_base = CMSPlugin(plugin_type=plugin_type, placeholder=placeholder, position=1, language=language) plugin_base.insert_at(None, position='last-child', commit=False) plugin = plugin_model(**data) plugin_base.set_base_attr(plugin) plugin.save() return plugin
def test_check_plugin_instances(self): self.assertCheck(True, warnings=0, errors=0 ) placeholder = Placeholder.objects.create(slot="test") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, "LinkPlugin", "en", name="A Link", external_link="https://www.django-cms.org") # create a CMSPlugin with an unsaved instance instanceless_plugin = CMSPlugin(language="en", plugin_type="TextPlugin") instanceless_plugin.save() self.assertCheck(False, warnings=0, errors=2) # create a bogus CMSPlugin to simulate one which used to exist but # is no longer installed bogus_plugin = CMSPlugin(language="en", plugin_type="BogusPlugin") bogus_plugin.save() self.assertCheck(False, warnings=0, errors=3)
def test_check_plugin_instances(self): self.assertCheck(True, warnings=0, errors=0 ) apps = ["cms", "menus", "sekizai", "cms.test_utils.project.sampleapp", "treebeard"] with self.settings(INSTALLED_APPS=apps): placeholder = Placeholder.objects.create(slot="test") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, "LinkPlugin", "en", name="A Link", url="https://www.django-cms.org") # create a CMSPlugin with an unsaved instance instanceless_plugin = CMSPlugin(language="en", plugin_type="TextPlugin") instanceless_plugin.save() self.assertCheck(False, warnings=0, errors=2) # create a bogus CMSPlugin to simulate one which used to exist but # is no longer installed bogus_plugin = CMSPlugin(language="en", plugin_type="BogusPlugin") bogus_plugin.save() self.assertCheck(False, warnings=0, errors=3)
def test_16_delete_with_plugins(self): """ Check that plugins and placeholders get correctly deleted when we delete a page! """ page = self.create_page() page.rescan_placeholders() # create placeholders placeholder = page.placeholders.all()[0] plugin_base = CMSPlugin(plugin_type='TextPlugin', placeholder=placeholder, position=1, language=settings.LANGUAGES[0][0]) plugin_base.insert_at(None, position='last-child', save=False) plugin = Text(body='') plugin_base.set_base_attr(plugin) plugin.save() self.assertEqual(CMSPlugin.objects.count(), 1) self.assertEqual(Text.objects.count(), 1) self.assertTrue(Placeholder.objects.count() > 0) page.delete() self.assertEqual(CMSPlugin.objects.count(), 0) self.assertEqual(Text.objects.count(), 0) self.assertEqual(Placeholder.objects.count(), 0)
def _move_plugin(self, request, plugin, target_language, target_placeholder, tree_order, target_parent=None): if not self.has_move_plugin_permission(request, plugin, target_placeholder): message = force_text(_("You have no permission to move this plugin")) raise PermissionDenied(message) plugin_data = { 'language': target_language, 'placeholder': target_placeholder, } source_language = plugin.language source_placeholder = plugin.placeholder source_tree_order = source_placeholder.get_plugin_tree_order( language=source_language, parent_id=plugin.parent_id, ) if target_parent: target_parent_id = target_parent.pk else: target_parent_id = None if target_placeholder != source_placeholder: target_tree_order = target_placeholder.get_plugin_tree_order( language=target_language, parent_id=target_parent_id, ) else: target_tree_order = source_tree_order action_token = self._send_pre_placeholder_operation( request, operation=operations.MOVE_PLUGIN, plugin=plugin, source_language=source_language, source_placeholder=source_placeholder, source_parent_id=plugin.parent_id, source_order=source_tree_order, target_language=target_language, target_placeholder=target_placeholder, target_parent_id=target_parent_id, target_order=target_tree_order, ) if target_parent and plugin.parent != target_parent: # Plugin is being moved to another tree (under another parent) updated_plugin = plugin.update(refresh=True, parent=target_parent, **plugin_data) updated_plugin = updated_plugin.move(target_parent, pos='last-child') elif target_parent: # Plugin is being moved within the same tree (different position, same parent) updated_plugin = plugin.update(refresh=True, **plugin_data) else: # Plugin is being moved to the root (no parent) target = CMSPlugin.get_last_root_node() updated_plugin = plugin.update(refresh=True, parent=None, **plugin_data) updated_plugin = updated_plugin.move(target, pos='right') # Update all children to match the parent's # language and placeholder updated_plugin.get_descendants().update(**plugin_data) # Avoid query by removing the plugin being moved # from the source order new_source_order = list(source_tree_order) new_source_order.remove(updated_plugin.pk) # Reorder all plugins in the target placeholder according to the # passed order new_target_order = [int(pk) for pk in tree_order] reorder_plugins( target_placeholder, parent_id=target_parent_id, language=target_language, order=new_target_order, ) # Refresh plugin to get new tree and position values updated_plugin.refresh_from_db() self._send_post_placeholder_operation( request, operation=operations.MOVE_PLUGIN, plugin=updated_plugin.get_bound_plugin(), token=action_token, source_language=source_language, source_placeholder=source_placeholder, source_parent_id=plugin.parent_id, source_order=new_source_order, target_language=target_language, target_placeholder=target_placeholder, target_parent_id=target_parent_id, target_order=new_target_order, ) return updated_plugin
class PlaceholderAdmin(ModelAdmin): render_placeholder_language_tabs = True change_form_template = 'admin/placeholders/placeholder/change_form.html' class Media: css = { 'all': [ cms_static_url(path) for path in ( 'css/rte.css', 'css/change_form.css', 'css/jquery.dialog.css', 'css/plugin_editor.css', ) ] } js = [ cms_static_url(path) for path in [ 'js/plugins/admincompat.js', 'js/csrf.js', 'js/libs/jquery.query.js', 'js/libs/jquery.ui.core.js', 'js/libs/jquery.ui.dialog.js', ] ] def get_fieldsets(self, request, obj=None): """ Get fieldsets to enforce correct fieldsetting of placeholder fields """ form = self.get_form(request, obj) placeholder_fields = self._get_placeholder_fields(form) if self.declared_fieldsets: # check those declared fieldsets fieldsets = list(deepcopy(self.declared_fieldsets)) for label, fieldset in fieldsets: fields = list(fieldset['fields']) for field in fieldset['fields']: if field in placeholder_fields: if (len(fieldset['fields']) == 1 and 'classes' in fieldset and 'plugin-holder' in fieldset['classes'] and 'plugin-holder-nopage' in fieldset['classes']): placeholder_fields.remove(field) else: fields.remove(field) if fields: fieldset['fields'] = fields else: # no fields in the fieldset anymore, delete the fieldset fieldsets.remove((label, fieldset)) for placeholder in placeholder_fields: fieldsets.append(( self.get_label_for_placeholder(placeholder), { 'fields': (placeholder, ), 'classes': ( 'plugin-holder', 'plugin-holder-nopage', ), }, )) return fieldsets fieldsets = [] fieldsets.append((None, { 'fields': [ f for f in form.base_fields.keys() if not f in placeholder_fields ] })) for placeholder in placeholder_fields: fieldsets.append((self.get_label_for_placeholder(placeholder), { 'fields': (placeholder, ), 'classes': ( 'plugin-holder', 'plugin-holder-nopage', ), })) readonly_fields = self.get_readonly_fields(request, obj) if readonly_fields: fieldsets.append((None, {'fields': list(readonly_fields)})) return fieldsets def get_label_for_placeholder(self, placeholder): return ' '.join([ x.capitalize() for x in self.model._meta.get_field_by_name( placeholder)[0].verbose_name.split(' ') ]) def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ if isinstance(db_field, PlaceholderField): request = kwargs.pop("request", None) return db_field.formfield_for_admin(request, self.placeholder_plugin_filter, **kwargs) return super(PlaceholderAdmin, self).formfield_for_dbfield(db_field, **kwargs) def get_language_from_request(self, request): language = request.REQUEST.get('language', None) if not language: language = get_language() return language def placeholder_plugin_filter(self, request, queryset): if self.render_placeholder_language_tabs: language = self.get_language_from_request(request) if language: queryset = queryset.filter(language=language) return queryset def change_view(self, request, object_id, form_url='', extra_context=None): extra_context = extra_context or {} extra_context.update(self.language_tab_context(request)) tab_language = request.GET.get("language", None) response = super(PlaceholderAdmin, self).change_view(request, object_id, extra_context=extra_context) if tab_language and response.status_code == 302 and response._headers[ 'location'][1] == request.path: location = response._headers['location'] response._headers['location'] = (location[0], "%s?language=%s" % (location[1], tab_language)) return response def language_tab_context(self, request): language = self.get_language_from_request(request) languages = [(lang, lang_name) for lang, lang_name in settings.LANGUAGES] context = { 'language': language, 'language_tabs': languages, 'show_language_tabs': len(languages) > 1 and self.render_placeholder_language_tabs, } return context def _get_placeholder_fields(self, form): placeholder_fields = [] for key, value in form.base_fields.items(): if isinstance(value, PlaceholderFormField): placeholder_fields.append(key) return placeholder_fields def get_urls(self): """ Register the plugin specific urls (add/edit/copy/remove/move) """ from django.conf.urls.defaults import patterns, url info = "%s_%s" % (self.model._meta.app_label, self.model._meta.module_name) pat = lambda regex, fn: url(regex, self.admin_site.admin_view(fn), name='%s_%s' % (info, fn.__name__)) url_patterns = patterns( '', pat(r'add-plugin/$', self.add_plugin), pat(r'edit-plugin/([0-9]+)/$', self.edit_plugin), pat(r'remove-plugin/$', self.remove_plugin), pat(r'move-plugin/$', self.move_plugin), pat(r'copy-plugins/$', self.copy_plugins), ) return url_patterns + super(PlaceholderAdmin, self).get_urls() @xframe_options_sameorigin def add_plugin(self, request): # only allow POST if request.method != "POST": raise Http404 plugin_type = request.POST['plugin_type'] if not has_plugin_permission(request.user, plugin_type, "add"): return HttpResponseForbidden( "You don't have permission to add plugins") placeholder_id = request.POST.get('placeholder', None) position = None language = self.get_language_from_request(request) parent = None # check if we got a placeholder (id) if placeholder_id: placeholder = get_object_or_404(Placeholder, pk=placeholder_id) else: # else get the parent_id parent_id = request.POST.get('parent_id', None) if not parent_id: # if we get neither a placeholder nor a parent, bail out raise Http404 parent = get_object_or_404(CMSPlugin, pk=parent_id) placeholder = parent.placeholder # check add permissions on placeholder if not placeholder.has_add_permission(request): return HttpResponseForbidden( _("You don't have permission to add content here.")) try: has_reached_plugin_limit(placeholder, plugin_type, language) except PluginLimitReached, e: return HttpResponseBadRequest(str(e)) # actually add the plugin plugin = CMSPlugin(language=language, plugin_type=plugin_type, position=position, placeholder=placeholder, parent=parent) plugin.save() # returns it's ID as response return HttpResponse(str(plugin.pk))
def test_11_copy_textplugin(self): """ Test that copying of textplugins replaces references to copied plugins """ page = self.create_page() placeholder = page.placeholders.get(slot='body') plugin_base = CMSPlugin( plugin_type='TextPlugin', placeholder=placeholder, position=1, language=self.FIRST_LANG) plugin_base.insert_at(None, position='last-child', commit=False) plugin = Text(body='') plugin_base.set_base_attr(plugin) plugin.save() plugin_ref_1_base = CMSPlugin( plugin_type='TextPlugin', placeholder=placeholder, position=1, language=self.FIRST_LANG) plugin_ref_1_base.insert_at(plugin_base, position='last-child', commit=False) plugin_ref_1 = Text(body='') plugin_ref_1_base.set_base_attr(plugin_ref_1) plugin_ref_1.save() plugin_ref_2_base = CMSPlugin( plugin_type='TextPlugin', placeholder=placeholder, position=2, language=self.FIRST_LANG) plugin_ref_2_base.insert_at(plugin_base, position='last-child', commit=False) plugin_ref_2 = Text(body='') plugin_ref_2_base.set_base_attr(plugin_ref_2) plugin_ref_2.save() plugin.body = plugin_tags_to_admin_html(' {{ plugin_object %s }} {{ plugin_object %s }} ' % (str(plugin_ref_1.pk), str(plugin_ref_2.pk))) plugin.save() self.assertEquals(plugin.pk, 1) page_data = self.get_new_page_data() #create 2nd language page page_data.update({ 'language': self.SECOND_LANG, 'title': "%s %s" % (page.get_title(), self.SECOND_LANG), }) response = self.client.post(URL_CMS_PAGE_CHANGE % page.pk + "?language=%s" % self.SECOND_LANG, page_data) self.assertRedirects(response, URL_CMS_PAGE) self.assertEquals(CMSPlugin.objects.filter(language=self.FIRST_LANG).count(), 3) self.assertEquals(CMSPlugin.objects.filter(language=self.SECOND_LANG).count(), 0) self.assertEquals(CMSPlugin.objects.count(), 3) self.assertEquals(Page.objects.all().count(), 1) copy_data = { 'placeholder': placeholder.pk, 'language': self.SECOND_LANG, 'copy_from': self.FIRST_LANG, } response = self.client.post(URL_CMS_PAGE + "copy-plugins/", copy_data) self.assertEquals(response.status_code, 200) self.assertEqual(response.content.count('<li '), 3) # assert copy success self.assertEquals(CMSPlugin.objects.filter(language=self.FIRST_LANG).count(), 3) self.assertEquals(CMSPlugin.objects.filter(language=self.SECOND_LANG).count(), 3) self.assertEquals(CMSPlugin.objects.count(), 6) new_plugin = Text.objects.get(pk=6) self.assertEquals(plugin_tags_to_id_list(new_plugin.body), [u'4', u'5'])
""" must return a unicode string """ return str(self.latest_entries).decode('utf8') def copy_relations(self, oldinstance): self.tags = oldinstance.tags.all() def get_posts(self): posts = Post.published.filter_by_language(self.language) tags = list(self.tags.all()) if tags: posts = posts.filter(tags__in=tags) return posts[:self.latest_entries] class AuthorsPlugin(CMSPlugin): def get_authors(self): return generate_slugs(get_blog_authors()) def force_language(sender, instance, **kwargs): if issubclass( sender, CMSPlugin ) and instance.placeholder and instance.placeholder.slot == 'aldryn_blog_post_content': instance.language = settings.ALDRYN_BLOG_PLUGIN_LANGUAGE for model in CMSPlugin.__subclasses__(): models.signals.pre_save.connect(force_language, sender=model)
def add_plugin(placeholder, plugin_type, language, position='last-child', target=None, **data): """ Add a plugin to a placeholder See docs/extending_cms/api_reference.rst for more info """ # validate placeholder assert isinstance(placeholder, Placeholder) # validate and normalize plugin type plugin_model, plugin_type = _verify_plugin_type(plugin_type) if target: if position == 'last-child': if CMSPlugin.node_order_by: position = 'sorted-child' new_pos = CMSPlugin.objects.filter(parent=target).count() parent_id = target.pk elif position == 'first-child': new_pos = 0 if CMSPlugin.node_order_by: position = 'sorted-child' parent_id = target.pk elif position == 'left': new_pos = target.position if CMSPlugin.node_order_by: position = 'sorted-sibling' parent_id = target.parent_id elif position == 'right': new_pos = target.position + 1 if CMSPlugin.node_order_by: position = 'sorted-sibling' parent_id = target.parent_id else: raise Exception('position not supported: %s' % position) if position == 'last-child' or position == 'first-child': qs = CMSPlugin.objects.filter(language=language, parent=target, position__gte=new_pos, placeholder=placeholder) else: qs = CMSPlugin.objects.filter(language=language, parent=target.parent_id, position__gte=new_pos, placeholder=placeholder) for pl in qs: pl.position += 1 pl.save() else: if position == 'last-child': new_pos = CMSPlugin.objects.filter(language=language, parent__isnull=True, placeholder=placeholder).count() else: new_pos = 0 for pl in CMSPlugin.objects.filter(language=language, parent__isnull=True, position__gte=new_pos, placeholder=placeholder): pl.position += 1 pl.save() parent_id = None plugin_base = CMSPlugin( plugin_type=plugin_type, placeholder=placeholder, position=new_pos, language=language, parent_id=parent_id, ) plugin_base = plugin_base.add_root(instance=plugin_base) if target: plugin_base = plugin_base.move(target, pos=position) plugin = plugin_model(**data) plugin_base.set_base_attr(plugin) plugin.save() return plugin
def move_plugin(self, request): """ Performs a move or a "paste" operation (when «move_a_copy» is set) POST request with following parameters: - plugin_id - placeholder_id - plugin_language (optional) - plugin_parent (optional) - plugin_order (array, optional) - move_a_copy (Boolean, optional) (anything supplied here except a case- insensitive "false" is True) NOTE: If move_a_copy is set, the plugin_order should contain an item '__COPY__' with the desired destination of the copied plugin. """ # plugin_id and placeholder_id are required, so, if nothing is supplied, # an ValueError exception will be raised by get_int(). try: plugin_id = get_int(request.POST.get('plugin_id')) except TypeError: raise RuntimeError("'plugin_id' is a required parameter.") plugin = (CMSPlugin.objects.select_related('placeholder').get( pk=plugin_id)) try: placeholder_id = get_int(request.POST.get('placeholder_id')) except TypeError: raise RuntimeError("'placeholder_id' is a required parameter.") except ValueError: raise RuntimeError("'placeholder_id' must be an integer string.") placeholder = Placeholder.objects.get(pk=placeholder_id) # The rest are optional parent_id = get_int(request.POST.get('plugin_parent', ""), None) language = request.POST.get('plugin_language', None) move_a_copy = request.POST.get('move_a_copy', False) move_a_copy = (move_a_copy and move_a_copy != "0" and move_a_copy.lower() != "false") source_language = plugin.language source_placeholder = plugin.placeholder if not language and plugin.language: language = plugin.language order = request.POST.getlist("plugin_order[]") if placeholder != source_placeholder: try: template = self.get_placeholder_template(request, placeholder) has_reached_plugin_limit(placeholder, plugin.plugin_type, plugin.language, template=template) except PluginLimitReached as er: return HttpResponseBadRequest(er) if move_a_copy: # "paste" if plugin.plugin_type == "PlaceholderPlugin": parent_id = None inst = plugin.get_plugin_instance()[0] plugins = inst.placeholder_ref.get_plugins() else: plugins = [plugin] + list(plugin.get_descendants()) if not self.has_copy_from_clipboard_permission( request, placeholder, plugins): return HttpResponseForbidden( force_text( _("You have no permission to paste this plugin"))) new_plugins = copy_plugins.copy_plugins_to( plugins, placeholder, language, parent_plugin_id=parent_id, ) top_plugins = [] top_parent = new_plugins[0][0].parent_id for new_plugin, old_plugin in new_plugins: if new_plugin.parent_id == top_parent: # NOTE: There is no need to save() the plugins here. new_plugin.position = old_plugin.position top_plugins.append(new_plugin) # Creates a list of string PKs of the top-level plugins ordered by # their position. top_plugins_pks = [ str(p.pk) for p in sorted(top_plugins, key=lambda x: x.position) ] if parent_id: parent = CMSPlugin.objects.get(pk=parent_id) for plugin in top_plugins: plugin.parent = parent plugin.placeholder = placeholder plugin.language = language plugin.save() # If an ordering was supplied, we should replace the item that has # been copied with the new copy if order: if '__COPY__' in order: copy_idx = order.index('__COPY__') del order[copy_idx] order[copy_idx:0] = top_plugins_pks else: order.extend(top_plugins_pks) # Set the plugin variable to point to the newly created plugin. plugin = new_plugins[0][0] else: # Regular move if not self.has_move_plugin_permission(request, plugin, placeholder): return HttpResponseForbidden( force_text( _("You have no permission to move this plugin"))) plugin_data = { 'language': language, 'placeholder': placeholder, } if parent_id: if plugin.parent_id != parent_id: parent = CMSPlugin.objects.get(pk=parent_id) if parent.placeholder_id != placeholder.pk: return HttpResponseBadRequest( force_text( _('parent must be in the same placeholder'))) if parent.language != language: return HttpResponseBadRequest( force_text( _('parent must be in the same language as ' 'plugin_language'))) plugin = plugin.update(refresh=True, parent=parent, **plugin_data) plugin = plugin.move(parent, pos='last-child') else: plugin = plugin.update(refresh=True, **plugin_data) else: target = CMSPlugin.get_last_root_node() plugin = plugin.update(refresh=True, parent=None, **plugin_data) plugin = plugin.move(target, pos='right') # Update all children to match the parent's # language and placeholder plugin.get_descendants().update(**plugin_data) if order: # order should be a list of plugin primary keys # it's important that the plugins being referenced # are all part of the same tree. order = [int(pk) for pk in order] plugins_in_tree = CMSPlugin.objects.filter( parent=parent_id, placeholder=placeholder, language=language, pk__in=order, ) if len(order) != plugins_in_tree.count(): # Seems like order does not match the tree on the db message = _( 'order parameter references plugins in different trees') return HttpResponseBadRequest(force_text(message)) # Mark the target placeholder as dirty placeholder.mark_as_dirty(language) if placeholder != source_placeholder: # Plugin is being moved or copied into a separate placeholder # Mark source placeholder as dirty source_placeholder.mark_as_dirty(source_language) reorder_plugins(placeholder, parent_id, language, order) # When this is executed we are in the admin class of the source placeholder # It can be a page or a model with a placeholder field. # Because of this we need to get the admin class instance of the # target placeholder and call post_move_plugin() on it. # By doing this we make sure that both the source and target are # informed of the operation. target_placeholder_admin = self._get_attached_admin(placeholder) if move_a_copy: # "paste" plugins = list(plugin.get_tree()) self.post_copy_plugins(request, source_placeholder, placeholder, plugins) if (target_placeholder_admin and target_placeholder_admin.model != self.model): target_placeholder_admin.post_copy_plugins( request, source_placeholder=source_placeholder, target_placeholder=placeholder, plugins=plugins, ) else: self.post_move_plugin(request, source_placeholder, placeholder, plugin) if (target_placeholder_admin and target_placeholder_admin.model != self.model): target_placeholder_admin.post_move_plugin( request, source_placeholder=source_placeholder, target_placeholder=placeholder, plugin=plugin, ) try: language = request.toolbar.toolbar_language except AttributeError: language = get_language_from_request(request) with force_language(language): plugin_urls = plugin.get_action_urls() json_response = { 'urls': plugin_urls, 'reload': move_a_copy or requires_reload(PLUGIN_MOVE_ACTION, [plugin]) } return HttpResponse(json.dumps(json_response), content_type='application/json')
def _paste_plugin(self, request, plugin, target_language, target_placeholder, tree_order, target_parent=None): plugins = (CMSPlugin.get_tree(parent=plugin).filter( placeholder=plugin.placeholder_id).order_by('path')) plugins = list(plugins) if not self.has_copy_from_clipboard_permission( request, target_placeholder, plugins): message = force_text( _("You have no permission to paste this plugin")) raise PermissionDenied(message) if target_parent: target_parent_id = target_parent.pk else: target_parent_id = None target_tree_order = [ int(pk) for pk in tree_order if not pk == '__COPY__' ] action_token = self._send_pre_placeholder_operation( request, operation=operations.PASTE_PLUGIN, plugin=plugin, target_language=target_language, target_placeholder=target_placeholder, target_parent_id=target_parent_id, target_order=target_tree_order, ) plugin_pairs = copy_plugins.copy_plugins_to( plugins, to_placeholder=target_placeholder, to_language=target_language, parent_plugin_id=target_parent_id, ) root_plugin = plugin_pairs[0][0] # If an ordering was supplied, replace the item that has # been copied with the new copy target_tree_order.insert(tree_order.index('__COPY__'), root_plugin.pk) reorder_plugins( target_placeholder, parent_id=target_parent_id, language=target_language, order=target_tree_order, ) target_placeholder.mark_as_dirty(target_language, clear_cache=False) # Fetch from db to update position and other tree values root_plugin.refresh_from_db() self._send_post_placeholder_operation( request, operation=operations.PASTE_PLUGIN, plugin=root_plugin.get_bound_plugin(), token=action_token, target_language=target_language, target_placeholder=target_placeholder, target_parent_id=target_parent_id, target_order=target_tree_order, ) return root_plugin
def convert(request, slug = "dryrun"): # this dictionary store the information for the conversions execute=slug models_dictionary = { "messages": {}, # a general set of messages for the user "modules": { "news_and_events.models": { # each module containing the models must be represented, like this "application": "News & Events", # this is the human-friendly name of the module "models": { # a dictionary with each model in that module "NewsArticle": { # the actual name of the class "fields": [ # a list of the fields we're working on { # a dictionary for each field "old_field": "content", "new_field": "body", "slot": "body", }, ], "model": "News articles", # the human-friendly name of the model "actions": {}, # an empty dictionary where we we store the results }, "Event": { # a second model in that module "fields": [ { "old_field": "content", "new_field": "body", "slot": "body", }, ], "model": "Events", "actions": {}, }, }, }, "vacancies_and_studentships.models": { # and a second module "application": "Vacancies & Studentships", "models": { "Vacancy": { "fields": [ { "old_field": "description", "new_field": "body", "slot": "body", }, ], "model": "Vacancies", "actions": {}, }, "Studentship": { "fields": [ { "old_field": "description", "new_field": "body", "slot": "body", }, ], "model": "Studentships", "actions": {}, }, }, }, "publications.models": { "application": "Publications", "models": { "Researcher": { "fields": [ { "old_field": "research_synopsis", "new_field": "synopsis_of_research", "slot": "body", }, { "old_field": "research_description", "new_field": "description_of_research", "slot": "body", }, ], "model": "Researcher", "actions": {}, }, }, }, }, } # loop over the modules for module, module_values in models_dictionary["modules"].items(): # loop over the models in the module for model, model_values in module_values["models"].items(): # mmodel is the human-readable name of the model, used for the report summary mmodel = models_dictionary["modules"][module]["models"][model]["model"] models_dictionary["messages"][mmodel]={} # import the model actual_model = getattr(__import__(module, globals(), locals(), module_values["models"], -1), model) # loop over the fields that need converting for field in model_values["fields"]: print field old_field = field["old_field"] new_field = field["new_field"] slot = field["slot"] # create a summary report for this field models_dictionary["messages"][mmodel][old_field]={} try: getattr(actual_model, new_field) except AttributeError: message = "field " + new_field + " is missing - check the model and try agin" models_dictionary["messages"][mmodel][old_field]["Error"]=message continue junk_content = [] # a record of those items with nothing but <br /> in them moved_items =[] # a record of the items we migrated to placeholders # loop over each item in the class for item in actual_model.objects.all(): old_field_content = getattr(item, old_field) # the old field we want to convert # first get rid of junk content (change "<br />" to "") if old_field_content == "<br />": old_field_content = "" setattr(item, old_field, "") # item.content = "" if execute == "convert": item.save() # now the serious business of converting the fields # if the item lacks a placeholder, create the placeholder and the reference to it if old_field_content and not getattr(item, new_field, None): # check to see if it's worth converting if len(old_field_content) > 60: # create the placeholder placeholder=Placeholder(slot=slot) if execute == "convert": placeholder.save() # refer to the placeholder from the item setattr(item, new_field, placeholder) # I copied this from one of the test files plugin_base = CMSPlugin( plugin_type='TextPlugin', placeholder=placeholder, position=1, language=settings.LANGUAGES[0][0]) # we assume the original field was in the first language plugin_base.insert_at(None, position='last-child', commit=False) # create a text plugin plugin = Text(body='') plugin_base.set_base_attr(plugin) plugin.body = getattr(item, old_field) if execute == "convert": plugin.save() # set the old field to "" setattr(item, old_field, "") if execute == "convert": item.save() item.status = "Converted to placeholder" else: item.status = "Unconverted" else: print "too short", old_field_content # this item is so short it must be junk if execute == "convert": setattr(item, old_field, "") item.status = "Junk field - too short; was deleted instead of converted:" + old_field_content item.save() else: item.status = "Junk field - too short; will be deleted instead of converted:" + old_field_content # make a note that this was a junk item junk_content.append(item) # make a note that we moved this item moved_items.append(item) # information about junk content items if execute == "convert": message = " ".join((str(len(junk_content)), "junk items not converted items")) else: message = " ".join((str(len(junk_content)), "junk items found")) models_dictionary["messages"][mmodel][old_field]["Junk fields"]=message # information about items that have been/need to be converted if execute == "convert": message = str(len(moved_items)) + " items were converted to placeholder " + new_field else: message = str(len(moved_items)) + " items need to be converted to placeholder " + new_field models_dictionary["messages"][mmodel][old_field]["Conversions"]=message # list every item that was copied for the full report if execute == "convert": action = "Fields that were copied" else: action = "Fields to be copied" models_dictionary["modules"][module]["models"][model]["actions"][action]=moved_items return shortcuts.render_to_response( "housekeeping/convert_to_placeholders.html", { "execute": execute, "converted": models_dictionary, }, RequestContext(request), )
def test_delete_orphaned_plugins(self): placeholder = Placeholder.objects.create(slot="test") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, "LinkPlugin", "en", name="A Link", url="https://www.django-cms.org") instanceless_plugin = CMSPlugin( language="en", plugin_type="TextPlugin") instanceless_plugin.save() # create a bogus CMSPlugin to simulate one which used to exist but # is no longer installed bogus_plugin = CMSPlugin(language="en", plugin_type="BogusPlugin") bogus_plugin.save() report = plugin_report() # there should be reports for three plugin types self.assertEqual( len(report), 3) # check the bogus plugin bogus_plugins_report = report[0] self.assertEqual( len(bogus_plugins_report["instances"]), 1) # check the link plugin link_plugins_report = report[1] self.assertEqual( len(link_plugins_report["instances"]), 1) # check the text plugins text_plugins_report = report[2] self.assertEqual( len(text_plugins_report["instances"]), 3) self.assertEqual( len(text_plugins_report["unsaved_instances"]), 1) out = StringIO() management.call_command('cms', 'delete-orphaned-plugins', interactive=False, stdout=out) report = plugin_report() # there should be reports for two plugin types (one should have been deleted) self.assertEqual( len(report), 2) # check the link plugin link_plugins_report = report[0] self.assertEqual( len(link_plugins_report["instances"]), 1) # check the text plugins text_plugins_report = report[1] self.assertEqual( len(text_plugins_report["instances"]), 2) self.assertEqual( len(text_plugins_report["unsaved_instances"]), 0)
must return a unicode string """ return str(self.latest_entries).decode('utf8') def copy_relations(self, oldinstance): self.tags = oldinstance.tags.all() def get_posts(self): posts = Post.published.filter_by_language(self.language) tags = self.tags.values_list('pk', flat=True) if tags.exists(): posts = posts.filter(tags__in=tags) return posts[:self.latest_entries] class AuthorsPlugin(CMSPlugin): def get_authors(self): return generate_slugs(get_blog_authors()) def force_language(sender, instance, **kwargs): if issubclass(sender, CMSPlugin) and instance.placeholder \ and instance.placeholder.slot == 'aldryn_blog_post_content': instance.language = settings.ALDRYN_BLOG_PLUGIN_LANGUAGE for model in CMSPlugin.__subclasses__(): models.signals.pre_save.connect(force_language, sender=model)
def move_plugin(self, request): """ Performs a move or a "paste" operation (when «move_a_copy» is set) POST request with following parameters: - plugin_id - placeholder_id - plugin_language (optional) - plugin_parent (optional) - plugin_order (array, optional) - move_a_copy (Boolean, optional) (anything supplied here except a case- insensitive "false" is True) NOTE: If move_a_copy is set, the plugin_order should contain an item '__COPY__' with the desired destination of the copied plugin. """ # plugin_id and placeholder_id are required, so, if nothing is supplied, # an ValueError exception will be raised by get_int(). try: plugin_id = get_int(request.POST.get('plugin_id')) except TypeError: raise RuntimeError("'plugin_id' is a required parameter.") plugin = CMSPlugin.objects.get(pk=plugin_id) try: placeholder_id = get_int(request.POST.get('placeholder_id')) except TypeError: raise RuntimeError("'placeholder_id' is a required parameter.") except ValueError: raise RuntimeError("'placeholder_id' must be an integer string.") placeholder = Placeholder.objects.get(pk=placeholder_id) # The rest are optional parent_id = get_int(request.POST.get('plugin_parent', ""), None) language = request.POST.get('plugin_language', None) move_a_copy = request.POST.get('move_a_copy', False) move_a_copy = (move_a_copy and move_a_copy != "0" and move_a_copy.lower() != "false") source_placeholder = plugin.placeholder if not language and plugin.language: language = plugin.language order = request.POST.getlist("plugin_order[]") if not self.has_move_plugin_permission(request, plugin, placeholder): return HttpResponseForbidden( force_text(_("You have no permission to move this plugin"))) if placeholder != source_placeholder: try: template = self.get_placeholder_template(request, placeholder) has_reached_plugin_limit(placeholder, plugin.plugin_type, plugin.language, template=template) except PluginLimitReached as er: return HttpResponseBadRequest(er) if move_a_copy: # "paste" if plugin.plugin_type == "PlaceholderPlugin": parent_id = None inst = plugin.get_plugin_instance()[0] plugins = inst.placeholder_ref.get_plugins() else: plugins = [plugin] + list(plugin.get_descendants()) new_plugins = copy_plugins.copy_plugins_to( plugins, placeholder, language, parent_plugin_id=parent_id, ) top_plugins = [] top_parent = new_plugins[0][0].parent_id for new_plugin, old_plugin in new_plugins: if new_plugin.parent_id == top_parent: # NOTE: There is no need to save() the plugins here. new_plugin.position = old_plugin.position top_plugins.append(new_plugin) # Creates a list of string PKs of the top-level plugins ordered by # their position. top_plugins_pks = [str(p.pk) for p in sorted( top_plugins, key=lambda x: x.position)] if parent_id: parent = CMSPlugin.objects.get(pk=parent_id) for plugin in top_plugins: plugin.parent = parent plugin.placeholder = placeholder plugin.language = language plugin.save() # If an ordering was supplied, we should replace the item that has # been copied with the new copy if order: if '__COPY__' in order: copy_idx = order.index('__COPY__') del order[copy_idx] order[copy_idx:0] = top_plugins_pks else: order.extend(top_plugins_pks) # Set the plugin variable to point to the newly created plugin. plugin = new_plugins[0][0] else: # Regular move if parent_id: if plugin.parent_id != parent_id: parent = CMSPlugin.objects.get(pk=parent_id) if parent.placeholder_id != placeholder.pk: return HttpResponseBadRequest(force_text( _('parent must be in the same placeholder'))) if parent.language != language: return HttpResponseBadRequest(force_text( _('parent must be in the same language as ' 'plugin_language'))) plugin.parent_id = parent.pk plugin.language = language plugin.save() plugin = plugin.move(parent, pos='last-child') else: sibling = CMSPlugin.get_last_root_node() plugin.parent = plugin.parent_id = None plugin.placeholder = placeholder plugin.save() plugin = plugin.move(sibling, pos='right') plugins = [plugin] + list(plugin.get_descendants()) # Don't neglect the children for child in plugins: child.placeholder = placeholder child.language = language child.save() reorder_plugins(placeholder, parent_id, language, order) # When this is executed we are in the admin class of the source placeholder # It can be a page or a model with a placeholder field. # Because of this we need to get the admin class instance of the # target placeholder and call post_move_plugin() on it. # By doing this we make sure that both the source and target are # informed of the operation. target_placeholder_admin = self._get_attached_admin(placeholder) if move_a_copy: # "paste" self.post_copy_plugins(request, source_placeholder, placeholder, plugins) if (target_placeholder_admin and target_placeholder_admin.model != self.model): target_placeholder_admin.post_copy_plugins( request, source_placeholder=source_placeholder, target_placeholder=placeholder, plugins=plugins, ) else: self.post_move_plugin(request, source_placeholder, placeholder, plugin) if (target_placeholder_admin and target_placeholder_admin.model != self.model): target_placeholder_admin.post_move_plugin( request, source_placeholder=source_placeholder, target_placeholder=placeholder, plugin=plugin, ) try: language = request.toolbar.toolbar_language except AttributeError: language = get_language_from_request(request) with force_language(language): plugin_urls = plugin.get_action_urls() json_response = { 'urls': plugin_urls, 'reload': move_a_copy or requires_reload( PLUGIN_MOVE_ACTION, [plugin]) } return HttpResponse( json.dumps(json_response), content_type='application/json')
def test_list_plugins(self): out = io.StringIO() placeholder = Placeholder.objects.create(slot="test") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, TextPlugin, "en", body="en body") link_plugin = add_plugin(placeholder, "LinkPlugin", "en", name="A Link", external_link="https://www.django-cms.org") self.assertEqual( CMSPlugin.objects.filter(plugin_type=PLUGIN).count(), 2) self.assertEqual( CMSPlugin.objects.filter(plugin_type="LinkPlugin").count(), 1) # create a CMSPlugin with an unsaved instance instanceless_plugin = CMSPlugin(language="en", plugin_type="TextPlugin") instanceless_plugin.save() # create a bogus CMSPlugin to simulate one which used to exist but # is no longer installed bogus_plugin = CMSPlugin(language="en", plugin_type="BogusPlugin") bogus_plugin.save() with mock.patch( 'cms.management.commands.subcommands.list.plugin_report' ) as report_fn: management.call_command('cms', 'list', 'plugins', interactive=False, stdout=out) report_fn.assert_called_once() report = plugin_report() # there should be reports for three plugin types self.assertEqual(len(report), 3) # check the bogus plugin bogus_plugins_report = report[0] self.assertEqual(bogus_plugins_report["model"], None) self.assertEqual(bogus_plugins_report["type"], u'BogusPlugin') self.assertEqual(bogus_plugins_report["instances"][0], bogus_plugin) # check the link plugin link_plugins_report = report[1] self.assertEqual(link_plugins_report["model"], link_plugin.__class__) self.assertEqual(link_plugins_report["type"], u'LinkPlugin') self.assertEqual( link_plugins_report["instances"][0].get_plugin_instance()[0], link_plugin) # check the text plugins text_plugins_report = report[2] self.assertEqual(text_plugins_report["model"], TextPlugin.model) self.assertEqual(text_plugins_report["type"], u'TextPlugin') self.assertEqual(len(text_plugins_report["instances"]), 3) self.assertEqual(text_plugins_report["instances"][2], instanceless_plugin) self.assertEqual(text_plugins_report["unsaved_instances"], [instanceless_plugin])
def test_list_plugins(self): out = StringIO() placeholder = Placeholder.objects.create(slot="test") add_plugin(placeholder, TextPlugin, "en", body="en body") add_plugin(placeholder, TextPlugin, "en", body="en body") link_plugin = add_plugin(placeholder, "LinkPlugin", "en", name="A Link", url="https://www.django-cms.org") self.assertEqual( CMSPlugin.objects.filter(plugin_type=PLUGIN).count(), 2) self.assertEqual( CMSPlugin.objects.filter(plugin_type="LinkPlugin").count(), 1) # create a CMSPlugin with an unsaved instance instanceless_plugin = CMSPlugin(language="en", plugin_type="TextPlugin") instanceless_plugin.save() # create a bogus CMSPlugin to simulate one which used to exist but # is no longer installed bogus_plugin = CMSPlugin(language="en", plugin_type="BogusPlugin") bogus_plugin.save() management.call_command('cms', 'list', 'plugins', interactive=False, stdout=out) report = plugin_report() # there should be reports for three plugin types self.assertEqual( len(report), 3) # check the bogus plugin bogus_plugins_report = report[0] self.assertEqual( bogus_plugins_report["model"], None) self.assertEqual( bogus_plugins_report["type"], u'BogusPlugin') self.assertEqual( bogus_plugins_report["instances"][0], bogus_plugin) # check the link plugin link_plugins_report = report[1] self.assertEqual( link_plugins_report["model"], link_plugin.__class__) self.assertEqual( link_plugins_report["type"], u'LinkPlugin') self.assertEqual( link_plugins_report["instances"][0].get_plugin_instance()[0], link_plugin) # check the text plugins text_plugins_report = report[2] self.assertEqual( text_plugins_report["model"], TextPlugin.model) self.assertEqual( text_plugins_report["type"], u'TextPlugin') self.assertEqual( len(text_plugins_report["instances"]), 3) self.assertEqual( text_plugins_report["instances"][2], instanceless_plugin) self.assertEqual( text_plugins_report["unsaved_instances"], [instanceless_plugin])
def add_plugin(self, request): """ POST request should have the following data: - placeholder_id - plugin_type - plugin_language - plugin_parent (optional) """ plugin_type = request.POST["plugin_type"] placeholder_id = request.POST.get("placeholder_id", None) parent_id = request.POST.get("parent_id", None) if parent_id: warnings.warn( "parent_id is deprecated and will be removed in 3.1, use plugin_parent instead", DeprecationWarning ) if not parent_id: parent_id = request.POST.get("plugin_parent", None) placeholder = get_object_or_404(Placeholder, pk=placeholder_id) if not self.has_add_plugin_permission(request, placeholder, plugin_type): return HttpResponseForbidden(force_unicode(_("You do not have permission to add a plugin"))) parent = None language = request.POST.get("plugin_language") or get_language_from_request(request) try: has_reached_plugin_limit( placeholder, plugin_type, language, template=self.get_placeholder_template(request, placeholder) ) except PluginLimitReached as er: return HttpResponseBadRequest(er) # page add-plugin if not parent_id: position = request.POST.get( "plugin_order", CMSPlugin.objects.filter(language=language, placeholder=placeholder).count() ) # in-plugin add-plugin else: parent = get_object_or_404(CMSPlugin, pk=parent_id) placeholder = parent.placeholder position = request.POST.get( "plugin_order", CMSPlugin.objects.filter(language=language, parent=parent).count() ) # placeholder (non-page) add-plugin # Sanity check to make sure we're not getting bogus values from JavaScript: if settings.USE_I18N: if not language or not language in [lang[0] for lang in settings.LANGUAGES]: return HttpResponseBadRequest(force_unicode(_("Language must be set to a supported language!"))) if parent and parent.language != language: return HttpResponseBadRequest(force_unicode(_("Parent plugin language must be same as language!"))) else: language = settings.LANGUAGE_CODE plugin = CMSPlugin(language=language, plugin_type=plugin_type, position=position, placeholder=placeholder) if parent: plugin.position = CMSPlugin.objects.filter(parent=parent).count() plugin.insert_at(parent, position="last-child", save=False) plugin.save() self.post_add_plugin(request, placeholder, plugin) response = { "url": force_unicode( reverse( "admin:%s_%s_edit_plugin" % (self.model._meta.app_label, self.model._meta.module_name), args=[plugin.pk], ) ), "delete": force_unicode( reverse( "admin:%s_%s_delete_plugin" % (self.model._meta.app_label, self.model._meta.module_name), args=[plugin.pk], ) ), "breadcrumb": plugin.get_breadcrumb(), } return HttpResponse(json.dumps(response), content_type="application/json")