Beispiel #1
0
    def fix_tree(cls, destructive=False):
        """
        Fixes the plugin tree by first calling treebeard fix_tree and the
        recalculating the correct position property for each plugin.
        """
        from cms.utils.plugins import reorder_plugins

        super(CMSPlugin, cls).fix_tree(destructive)
        for placeholder in Placeholder.objects.all():
            for language, __ in settings.LANGUAGES:
                order = CMSPlugin.objects.filter(
                    placeholder_id=placeholder.pk,
                    language=language,
                    parent_id__isnull=True).order_by(
                        'position', 'path').values_list('pk', flat=True)
                reorder_plugins(placeholder, None, language, order)

                for plugin in CMSPlugin.objects.filter(
                        placeholder_id=placeholder.pk,
                        language=language).order_by('depth', 'path'):

                    order = CMSPlugin.objects.filter(
                        parent_id=plugin.pk).order_by(
                            'position', 'path').values_list('pk', flat=True)
                    reorder_plugins(placeholder, plugin.pk, language, order)
def _reorder_plugins(action, parent_id=None, order=None):
    if not order:
        return

    reorder_plugins(
        action.placeholder,
        parent_id=parent_id,
        language=action.language,
        order=order,
    )
Beispiel #3
0
 def _post_save(self):
     """
     Reorder plugins according to the post_date value. All (and only)
     subclasses of LiveblogInterface are taken into consideration and
     reordered together
     """
     items = []
     for model in LiveblogInterface.__subclasses__():
         items.extend(
             model.objects.filter(placeholder=self.placeholder).values('pk', 'post_date')
         )
     order = reversed([item['pk'] for item in sorted(items, key=itemgetter('post_date'))])
     reorder_plugins(self.placeholder, None, self.language, order)
Beispiel #4
0
def import_plugins(plugins, placeholder, language, root_plugin_id=None):
    source_map = {}
    new_plugins = []

    if root_plugin_id:
        root_plugin = CMSPlugin.objects.get(pk=root_plugin_id)
        source_map[root_plugin_id] = root_plugin
    else:
        root_plugin = None

    tree_order = placeholder.get_plugin_tree_order(language,
                                                   parent_id=root_plugin_id)

    for archived_plugin in plugins:
        if archived_plugin.parent_id:
            parent = source_map[archived_plugin.parent_id]
        else:
            parent = root_plugin

        if parent and parent.__class__ != CMSPlugin:
            parent = parent.cmsplugin_ptr

        plugin = archived_plugin.restore(
            placeholder=placeholder,
            language=language,
            parent=parent,
        )
        source_map[archived_plugin.pk] = plugin

        if parent == root_plugin:
            tree_order.append(plugin.pk)
        new_plugins.append(plugin)

    for new_plugin in new_plugins:
        plugin_class = get_plugin_class(new_plugin.plugin_type)

        if getattr(plugin_class, '_has_do_post_copy', False):
            # getattr is used for django CMS 3.4 compatibility
            # apps on 3.4 wishing to leverage this callback will need
            # to manually set the _has_do_post_copy attribute.
            plugin_class.do_post_copy(new_plugin, source_map)

    reorder_plugins(
        placeholder,
        parent_id=root_plugin_id,
        language=language,
        order=tree_order,
    )
    placeholder.mark_as_dirty(language, clear_cache=False)
Beispiel #5
0
    def fix_tree(cls, destructive=False):
        """
        Fixes the plugin tree by first calling treebeard fix_tree and the recalculating
        the correct position property for each plugin.
        """
        from cms.utils.plugins import reorder_plugins

        super(CMSPlugin, cls).fix_tree(destructive)
        for placeholder in Placeholder.objects.all():
            for language, __ in settings.LANGUAGES:
                order = CMSPlugin.objects.filter(placeholder_id=placeholder.pk, language=language,
                                                 parent_id__isnull=True
                                                 ).values_list('pk', flat=True)
                reorder_plugins(placeholder, None, language, order)
                for plugin in CMSPlugin.objects.filter(placeholder_id=placeholder.pk,
                                                       language=language).order_by('depth', 'path'):
                    order = CMSPlugin.objects.filter(parent_id=plugin.pk).values_list('pk', flat=True)
                    reorder_plugins(placeholder, plugin.pk, language, order)
Beispiel #6
0
    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 _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
    def _paste_placeholder(self, request, plugin, target_language,
                           target_placeholder, tree_order):
        plugins = plugin.placeholder_ref.get_plugins_list()

        if not self.has_copy_from_clipboard_permission(request, target_placeholder, plugins):
            message = force_text(_("You have no permission to paste this placeholder"))
            raise PermissionDenied(message)

        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_PLACEHOLDER,
            plugins=plugins,
            target_language=target_language,
            target_placeholder=target_placeholder,
            target_order=target_tree_order,
        )

        new_plugins = copy_plugins.copy_plugins_to(
            plugins,
            to_placeholder=target_placeholder,
            to_language=target_language,
        )

        new_plugin_ids = (new.pk for new, old in new_plugins)

        # Creates a list of PKs for the top-level plugins ordered by
        # their position.
        top_plugins = (pair for pair in new_plugins if not pair[0].parent_id)
        top_plugins_pks = [p[0].pk for p in sorted(top_plugins, key=lambda pair: pair[1].position)]

        # If an ordering was supplied, we should replace the item that has
        # been copied with the new plugins
        target_tree_order[tree_order.index('__COPY__'):0] = top_plugins_pks

        reorder_plugins(
            target_placeholder,
            parent_id=None,
            language=target_language,
            order=target_tree_order,
        )

        new_plugins = (
            CMSPlugin
            .objects
            .filter(pk__in=new_plugin_ids)
            .order_by('path')
            .select_related('placeholder')
        )
        new_plugins = list(new_plugins)

        self._send_post_placeholder_operation(
            request,
            operation=operations.PASTE_PLACEHOLDER,
            token=action_token,
            plugins=new_plugins,
            target_language=target_language,
            target_placeholder=target_placeholder,
            target_order=target_tree_order,
        )
        return new_plugins
    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,
        )

        # 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 _add_plugins_from_placeholder(self, request, source_placeholder, target_placeholder):
        # Plugins are being copied from a placeholder in another language
        # using the "Copy from language" placeholder operation.
        source_language = request.POST['source_language']
        target_language = request.POST['target_language']

        old_plugins = source_placeholder.get_plugins_list(language=source_language)

        # Check if the user can copy plugins from source placeholder to
        # target placeholder.
        has_permissions = self.has_copy_from_placeholder_permission(
            request,
            source_placeholder,
            target_placeholder,
            old_plugins,
        )

        if not has_permissions:
            message = _('You do not have permission to copy these plugins.')
            raise PermissionDenied(force_text(message))

        target_tree_order = target_placeholder.get_plugin_tree_order(
            language=target_language,
            parent_id=None,
        )

        operation_token = self._send_pre_placeholder_operation(
            request,
            operation=operations.ADD_PLUGINS_FROM_PLACEHOLDER,
            plugins=old_plugins,
            source_language=source_language,
            source_placeholder=source_placeholder,
            target_language=target_language,
            target_placeholder=target_placeholder,
            target_order=target_tree_order,
        )

        copied_plugins = copy_plugins.copy_plugins_to(
            old_plugins,
            to_placeholder=target_placeholder,
            to_language=target_language,
        )

        new_plugin_ids = (new.pk for new, old in copied_plugins)

        # Creates a list of PKs for the top-level plugins ordered by
        # their position.
        top_plugins = (pair for pair in copied_plugins if not pair[0].parent_id)
        top_plugins_pks = [p[0].pk for p in sorted(top_plugins, key=lambda pair: pair[1].position)]

        # All new plugins are added to the bottom
        target_tree_order = target_tree_order + top_plugins_pks

        reorder_plugins(
            target_placeholder,
            parent_id=None,
            language=target_language,
            order=target_tree_order,
        )

        new_plugins = CMSPlugin.objects.filter(pk__in=new_plugin_ids).order_by('path')
        new_plugins = list(new_plugins)

        self._send_post_placeholder_operation(
            request,
            operation=operations.ADD_PLUGINS_FROM_PLACEHOLDER,
            token=operation_token,
            plugins=new_plugins,
            source_language=source_language,
            source_placeholder=source_placeholder,
            target_language=target_language,
            target_placeholder=target_placeholder,
            target_order=target_tree_order,
        )
        return new_plugins
Beispiel #11
0
    def delete_plugin(self, request, plugin_id):
        plugin = self._get_plugin_from_id(plugin_id)

        if not self.has_delete_plugin_permission(request, plugin):
            return HttpResponseForbidden(force_str(
                _("You do not have permission to delete this plugin")))

        opts = plugin._meta
        router.db_for_write(opts.model)
        get_deleted_objects_additional_kwargs = {'request': request}
        deleted_objects, __, perms_needed, protected = get_deleted_objects(
            [plugin], admin_site=self.admin_site,
            **get_deleted_objects_additional_kwargs
        )

        if request.POST:  # The user has already confirmed the deletion.
            if perms_needed:
                raise PermissionDenied(_("You do not have permission to delete this plugin"))
            obj_display = force_str(plugin)
            placeholder = plugin.placeholder
            plugin_tree_order = placeholder.get_plugin_tree_order(
                language=plugin.language,
                parent_id=plugin.parent_id,
            )

            operation_token = self._send_pre_placeholder_operation(
                request,
                operation=operations.DELETE_PLUGIN,
                plugin=plugin,
                placeholder=placeholder,
                tree_order=plugin_tree_order,
            )

            plugin.delete()
            placeholder.mark_as_dirty(plugin.language, clear_cache=False)
            reorder_plugins(
                placeholder=placeholder,
                parent_id=plugin.parent_id,
                language=plugin.language,
            )

            self.log_deletion(request, plugin, obj_display)
            self.message_user(request, _('The %(name)s plugin "%(obj)s" was deleted successfully.') % {
                'name': force_str(opts.verbose_name), 'obj': force_str(obj_display)})

            # Avoid query by removing the plugin being deleted
            # from the tree order list
            new_plugin_tree_order = list(plugin_tree_order)
            new_plugin_tree_order.remove(plugin.pk)

            self._send_post_placeholder_operation(
                request,
                operation=operations.DELETE_PLUGIN,
                token=operation_token,
                plugin=plugin,
                placeholder=placeholder,
                tree_order=new_plugin_tree_order,
            )
            return HttpResponseRedirect(admin_reverse('index', current_app=self.admin_site.name))

        plugin_name = force_str(plugin.get_plugin_class().name)

        if perms_needed or protected:
            title = _("Cannot delete %(name)s") % {"name": plugin_name}
        else:
            title = _("Are you sure?")
        context = {
            "title": title,
            "object_name": plugin_name,
            "object": plugin,
            "deleted_objects": deleted_objects,
            "perms_lacking": perms_needed,
            "protected": protected,
            "opts": opts,
            "app_label": opts.app_label,
        }
        request.current_app = self.admin_site.name
        return TemplateResponse(
            request, "admin/cms/page/plugin/delete_confirmation.html", context
        )
    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 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')
Beispiel #14
0
    def add_module_view(cls, request, module_id):
        if not request.user.is_staff:
            raise PermissionDenied

        module_plugin = get_object_or_404(cls.model, pk=module_id)

        if request.method == 'GET':
            form = AddModuleForm(request.GET)
        else:
            form = AddModuleForm(request.POST)

        if not form.is_valid():
            return HttpResponseBadRequest('Form received unexpected values')

        if request.method == 'GET':
            opts = cls.model._meta
            context = {
                'form': form,
                'has_change_permission': True,
                'opts': opts,
                'root_path': reverse('admin:index'),
                'is_popup': True,
                'app_label': opts.app_label,
                'module': module_plugin,
            }
            return render(request, 'djangocms_modules/add_module.html',
                          context)

        language = form.cleaned_data['target_language']
        target_placeholder = form.cleaned_data.get('target_placeholder')

        if target_placeholder:
            target_plugin = None
        else:
            target_plugin = form.cleaned_data['target_plugin']
            target_placeholder = target_plugin.placeholder

        if not target_placeholder.has_add_plugin_permission(
                request.user, module_plugin.plugin_type):
            return HttpResponseForbidden(
                force_text(_('You do not have permission to add a plugin.')))

        pl_admin = target_placeholder._get_attached_admin()

        if pl_admin:
            template = pl_admin.get_placeholder_template(
                request, target_placeholder)
        else:
            template = None

        try:
            has_reached_plugin_limit(
                target_placeholder,
                module_plugin.plugin_type,
                language=language,
                template=template,
            )
        except PluginLimitReached as er:
            return HttpResponseBadRequest(er)

        tree_order = target_placeholder.get_plugin_tree_order(
            language=language,
            parent_id=target_plugin,
        )

        m_admin = module_plugin.placeholder._get_attached_admin()

        # This is needed only because we of the operation signal requiring
        # a version of the plugin that's not been committed to the db yet.
        new_module_plugin = copy.copy(module_plugin)
        new_module_plugin.pk = None
        new_module_plugin.placeholder = target_placeholder
        new_module_plugin.parent = None
        new_module_plugin.position = len(tree_order) + 1

        operation_token = m_admin._send_pre_placeholder_operation(
            request=request,
            placeholder=target_placeholder,
            tree_order=tree_order,
            operation=operations.ADD_PLUGIN,
            plugin=new_module_plugin,
        )

        new_plugins = copy_plugins_to_placeholder(
            plugins=list(module_plugin.get_unbound_plugins()),
            placeholder=target_placeholder,
            language=language,
            root_plugin=target_plugin,
        )
        tree_order.append(new_plugins[0].pk)
        reorder_plugins(
            target_placeholder,
            parent_id=target_plugin,
            language=language,
            order=tree_order,
        )
        new_module_plugin = cls.model.objects.get(pk=new_plugins[0].pk)

        m_admin._send_post_placeholder_operation(
            request,
            operation=operations.ADD_PLUGIN,
            token=operation_token,
            plugin=new_module_plugin,
            placeholder=new_module_plugin.placeholder,
            tree_order=tree_order,
        )

        response = cls().render_close_frame(request, obj=new_module_plugin)

        if form.cleaned_data.get('disable_future_confirmation'):
            response.set_cookie(key=cls.confirmation_cookie_name, value=True)
        return response
Beispiel #15
0
    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":
                inst, _plugin = plugin.get_plugin_instance()
                source_plugins = inst.placeholder_ref.get_plugins()
                new_plugins = copy_plugins.copy_plugins_to(
                    source_plugins, placeholder, language)
            else:
                source_plugins = [plugin] + list(plugin.get_descendants())
                new_plugins = copy_plugins.copy_plugins_to(
                    source_plugins, placeholder, language, 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)
        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')

            # Don't neglect the children
            for child in [plugin] + list(plugin.get_descendants()):
                child.placeholder = placeholder
                child.language = language
                child.save()

        reorder_plugins(placeholder, parent_id, language, order)

        self.post_move_plugin(request, source_placeholder, placeholder, plugin)
        json_response = {
            'reload': move_a_copy
            or requires_reload(PLUGIN_MOVE_ACTION, [plugin])
        }
        return HttpResponse(json.dumps(json_response),
                            content_type='application/json')