示例#1
0
    def merge_project(cls, company, source_id: str,
                      destination_id: str) -> Tuple[int, int, Set[str]]:
        """
        Move all the tasks and sub projects from the source project to the destination
        Remove the source project
        Return the amounts of moved entities and subprojects + set of all the affected project ids
        """
        with TimingContext("mongo", "move_project"):
            if source_id == destination_id:
                raise errors.bad_request.ProjectSourceAndDestinationAreTheSame(
                    source=source_id)
            source = Project.get(company, source_id)
            destination = Project.get(company, destination_id)
            if source_id in destination.path:
                raise errors.bad_request.ProjectCannotBeMergedIntoItsChild(
                    source=source_id, destination=destination_id)

            children = _get_sub_projects([source.id],
                                         _only=("id", "name", "parent",
                                                "path"))[source.id]
            cls.validate_projects_depth(
                projects=children,
                old_parent_depth=len(source.path) + 1,
                new_parent_depth=len(destination.path) + 1,
            )

            moved_entities = 0
            for entity_type in (Task, Model):
                moved_entities += entity_type.objects(
                    company=company,
                    project=source_id,
                    system_tags__nin=[EntityVisibility.archived.value],
                ).update(upsert=False, project=destination_id)

            moved_sub_projects = 0
            for child in Project.objects(company=company, parent=source_id):
                _reposition_project_with_children(
                    project=child,
                    children=[c for c in children if c.parent == child.id],
                    parent=destination,
                )
                moved_sub_projects += 1

            affected = {source.id, *(source.path or [])}
            source.delete()

            if destination:
                destination.update(last_update=datetime.utcnow())
                affected.update({destination.id, *(destination.path or [])})

        return moved_entities, moved_sub_projects, affected
示例#2
0
    def move_project(cls, company: str, user: str, project_id: str,
                     new_location: str) -> Tuple[int, Set[str]]:
        """
        Move project with its sub projects from its current location to the target one.
        If the target location does not exist then it will be created. If it exists then
        it should be writable. The source location should be writable too.
        Return the number of moved projects + set of all the affected project ids
        """
        with TimingContext("mongo", "move_project"):
            project = Project.get(company, project_id)
            old_parent_id = project.parent
            old_parent = (Project.get_for_writing(company=project.company,
                                                  id=old_parent_id)
                          if old_parent_id else None)

            children = _get_sub_projects([project.id],
                                         _only=("id", "name",
                                                "path"))[project.id]
            cls.validate_projects_depth(
                projects=[project, *children],
                old_parent_depth=len(project.path),
                new_parent_depth=_get_project_depth(new_location),
            )

            new_parent = _ensure_project(company=company,
                                         user=user,
                                         name=new_location)
            new_parent_id = new_parent.id if new_parent else None
            if old_parent_id == new_parent_id:
                raise errors.bad_request.ProjectSourceAndDestinationAreTheSame(
                    location=new_parent.name if new_parent else "")
            if (new_parent and project_id == new_parent.id
                    or project_id in new_parent.path):
                raise errors.bad_request.ProjectCannotBeMovedUnderItself(
                    project=project_id, parent=new_parent.id)
            moved = _reposition_project_with_children(project,
                                                      children=children,
                                                      parent=new_parent)

            now = datetime.utcnow()
            affected = set()
            for p in filter(None, (old_parent, new_parent)):
                p.update(last_update=now)
                affected.update({p.id, *(p.path or [])})

            return moved, affected