def _prepare_pos_var(self, pos, method_name, valid_pos, valid_sorted_pos): if pos is None: if self.node_order_by: pos = 'sorted-sibling' else: pos = 'last-sibling' if pos not in valid_pos: raise InvalidPosition('Invalid relative position: %s' % (pos, )) if self.node_order_by and pos not in valid_sorted_pos: raise InvalidPosition( 'Must use %s in %s when node_order_by is enabled' % (' or '.join(valid_sorted_pos), method_name)) if pos in valid_sorted_pos and not self.node_order_by: raise MissingNodeOrderBy('Missing node_order_by attribute.') return pos
def _fix_add_sibling_opts(self, pos): "prepare the pos variable for the add_sibling method" if pos is None: if self.node_order_by: pos = 'sorted-sibling' else: pos = 'last-sibling' if pos not in ('first-sibling', 'left', 'right', 'last-sibling', 'sorted-sibling'): raise InvalidPosition('Invalid relative position: %s' % (pos, )) if self.node_order_by and pos != 'sorted-sibling': raise InvalidPosition('Must use %s in add_sibling when' ' node_order_by is enabled' % ('sorted-sibling', )) if pos == 'sorted-sibling' and not self.node_order_by: raise MissingNodeOrderBy('Missing node_order_by attribute.') return pos
def move_language_tree_node( request, region_slug, language_tree_node_id, target_id, target_position ): """ This action moves the given language tree node to the given position relative to the given target. :param request: The current request :type request: ~django.http.HttpResponse :param region_slug: The slug of the region which language tree should be modified :type region_slug: str :param language_tree_node_id: The id of the language tree node which should be moved :type language_tree_node_id: int :param target_id: The id of the target language tree node :type target_id: int :param target_position: The desired position (choices: :mod:`~integreat_cms.cms.constants.position`) :type target_position: str :return: A redirection to the language tree :rtype: ~django.http.HttpResponseRedirect """ region = request.region language_tree_node = get_object_or_404( region.language_tree_nodes, id=language_tree_node_id ) target = get_object_or_404(region.language_tree_nodes, id=target_id) try: if target.depth == 1 and target_position in [position.LEFT, position.RIGHT]: raise InvalidPosition(_("A region can only have one root language.")) language_tree_node.move(target, target_position) # Call the save method on the (reloaded) node in order to trigger possible signal handlers etc. # (The move()-method executes raw sql which might cause problems if the instance isn't fetched again) language_tree_node = LanguageTreeNode.objects.get(id=language_tree_node_id) language_tree_node.save() messages.success( request, _('The language tree node "{}" was successfully moved.').format( language_tree_node.translated_name ), ) logger.debug( "%r moved to %r of %r by %r", language_tree_node, target_position, target, request.user, ) except (ValueError, InvalidPosition, InvalidMoveToDescendant) as e: messages.error(request, e) logger.exception(e) return redirect("language_tree", **{"region_slug": region_slug})
def move(self, target, pos=None): """ Moves the current node and all it's descendants to a new position relative to another node. :param target: The target mode which determines the new position :type target: ~integreat_cms.cms.models.abstract_tree_node.AbstractTreeNode :param pos: The new position of the page relative to the target (choices: :mod:`~integreat_cms.cms.constants.position`) :type pos: str :raises ~treebeard.exceptions.InvalidPosition: If the node is moved to another region """ logger.debug("Moving %r to position %r of %r", self, pos, target) # Do not allow to move a node outside its region if self.region != target.region: # Allow moving as siblings of root nodes (because it's a separate tree) if not (target.is_root() and pos in [ position.LEFT, position.RIGHT, position.FIRST_SIBLING, position.LAST_SIBLING, ]): raise InvalidPosition( _('The node "{}" in region "{}" cannot be moved to "{}".'). format(self, self.region, target.region)) # Moving a node can modify all other nodes via raw sql queries (which are not recognized by cachalot), # so we have to invalidate the whole model manually. invalidate_model(self.__class__) super().move(target=target, pos=pos) invalidate_model(self.__class__) # Reload 'self' because lft/rgt may have changed self.refresh_from_db() # Update parent to fix inconsistencies between tree fields new_parent = self.get_parent(update=True) logger.debug("Updating parent field from %r to %r", self.parent, new_parent) self.parent = new_parent self.save()
def move(self, target, pos=None): """ Extension to the treebeard 'move' method to ensure that Page will be places to allowed position. """ # todo: maybe move it to the special admin method cpos = ( 'first-child', 'last-child', 'sorted-child', ) spos = ( 'first-sibling', 'left', 'right', 'last-sibling', 'sorted-sibling', ) page = self.specific if (pos in cpos and not page.can_move_to(target)) or ( pos in spos and target.get_parent() and not page.can_move_to(target.get_parent())): raise InvalidPosition( 'Can not move "%s" (%s) to %s (%s), ' 'allowed parent types are (%s).' % ( page, type(page).__name__, target, target.specific_class.__name__, ', '.join(i.__name__ for i in page.allowed_parent_page_models()), )) super().move(target, pos=pos) type(page).objects.get(id=page.id).save(is_moved=True) logger.info('Page moved: #%d "%s" to #%d: "%s" as "%s"', page.id, page.title, target.id, target.title, pos)