Example #1
0
    def load_dump(self, request):
        throttle = throttling.ImportDumpModeRateThrottle()

        if not throttle.allow_request(request, self):
            self.throttled(request, throttle.wait())

        self.check_permissions(request, "load_dump", None)

        dump = request.FILES.get('dump', None)

        if not dump:
            raise exc.WrongArguments(_("Needed dump file"))

        reader = codecs.getreader("utf-8")

        try:
            dump = json.load(reader(dump))
            is_private = dump.get("is_private", False)
        except Exception:
            raise exc.WrongArguments(_("Invalid dump format"))

        user = request.user
        (enough_slots, not_enough_slots_error) = users_service.has_available_slot_for_project(
            user,
            project=Project(is_private=is_private, id=None)
        )
        if not enough_slots:
            raise exc.BadRequest(not_enough_slots_error)

        if Project.objects.filter(slug=dump['slug']).exists():
            del dump['slug']

        members = len(dump.get("memberships", []))
        (enough_slots, not_enough_slots_error) = users_service.has_available_slot_for_project(
            user,
            project=Project(is_private=is_private, id=None),
            members=max(members, 1)
        )
        if not enough_slots:
            raise exc.BadRequest(not_enough_slots_error)

        if settings.CELERY_ENABLED:
            task = tasks.load_project_dump.delay(user, dump)
            return response.Accepted({"import_id": task.id})

        project = dump_service.dict_to_project(dump, request.user)
        response_data = ProjectSerializer(project).data
        return response.Created(response_data)
def test_add_to_objects_timeline():
    with patch("taiga.timeline.service._add_to_object_timeline") as mock:
        users = [User(), User(), User()]
        project = Project()
        service._add_to_objects_timeline(users, project, "test")
        assert mock.call_count == 3
        assert mock.mock_calls == [
            call(users[0], project, "test", "default", {}),
            call(users[1], project, "test", "default", {}),
            call(users[2], project, "test", "default", {}),
        ]
        with pytest.raises(Exception):
            service.push_to_timeline(None, project, "test")
Example #3
0
def test_push_to_timeline_many_objects():
    with patch("taiga.timeline.service._add_to_object_timeline") as mock:
        users = [get_user_model(), get_user_model(), get_user_model()]
        owner = get_user_model()
        project = Project()
        service._push_to_timeline(users, project, "test", project.created_date)
        assert mock.call_count == 3
        assert mock.mock_calls == [
            call(users[0], project, "test", project.created_date, "default", {}),
            call(users[1], project, "test", project.created_date, "default", {}),
            call(users[2], project, "test", project.created_date, "default", {}),
        ]
        with pytest.raises(Exception):
            service._push_to_timeline(None, project, "test")
Example #4
0
    def _import_project_data(self, data, options):
        board = data
        labels = board['labels']
        statuses = board['lists']
        project_template = ProjectTemplate.objects.get(
            slug=options.get('template', "kanban"))
        project_template.us_statuses = []
        counter = 0
        for us_status in statuses:
            if counter == 0:
                project_template.default_options["us_status"] = us_status[
                    'name']

            counter += 1
            if us_status['name'] not in [
                    s['name'] for s in project_template.us_statuses
            ]:
                project_template.us_statuses.append({
                    "name":
                    us_status['name'],
                    "slug":
                    slugify(us_status['name']),
                    "is_closed":
                    False,
                    "is_archived":
                    True if us_status['closed'] else False,
                    "color":
                    "#999999",
                    "wip_limit":
                    None,
                    "order":
                    us_status['pos'],
                })

        project_template.task_statuses = []
        project_template.task_statuses.append({
            "name": "Incomplete",
            "slug": "incomplete",
            "is_closed": False,
            "color": "#ff8a84",
            "order": 1,
        })
        project_template.task_statuses.append({
            "name": "Complete",
            "slug": "complete",
            "is_closed": True,
            "color": "#669900",
            "order": 2,
        })
        project_template.default_options["task_status"] = "Incomplete"
        project_template.roles.append({
            "name":
            "Trello",
            "slug":
            "trello",
            "computable":
            False,
            "permissions":
            project_template.roles[0]['permissions'],
            "order":
            70,
        })

        tags_colors = []
        for label in labels:
            name = label['name']
            if not name:
                name = label['color']
            name = name.lower()
            color = self._ensure_hex_color(label['color'])
            tags_colors.append([name, color])

        project = Project(
            name=options.get('name', None) or board['name'],
            description=options.get('description', None) or board['desc'],
            owner=self._user,
            tags_colors=tags_colors,
            creation_template=project_template,
            is_private=options.get('is_private', False),
        )
        (can_create, error_message
         ) = projects_service.check_if_project_can_be_created_or_updated(
             project)
        if not can_create:
            raise exceptions.NotEnoughSlotsForProject(project.is_private, 1,
                                                      error_message)
        project.save()

        if board.get('organization', None):
            trello_avatar_template = "https://trello-logos.s3.amazonaws.com/{}/170.png"
            project_logo_url = trello_avatar_template.format(
                board['organization']['logoHash'])
            data = requests.get(project_logo_url)
            project.logo.save("logo.png", ContentFile(data.content), save=True)

        UserStoryCustomAttribute.objects.create(name="Due",
                                                description="Due date",
                                                type="date",
                                                order=1,
                                                project=project)
        import_service.create_memberships(options.get('users_bindings', {}),
                                          project, self._user, "trello")
        return project
Example #5
0
    def _import_project_data(self, data, options):
        board = data
        labels = board['labels']
        statuses = board['lists']
        project_template = ProjectTemplate.objects.get(slug=options.get('template', "kanban"))
        project_template.us_statuses = []
        counter = 0
        for us_status in statuses:
            if counter == 0:
                project_template.default_options["us_status"] = us_status['name']

            counter += 1
            if us_status['name'] not in [s['name'] for s in project_template.us_statuses]:
                project_template.us_statuses.append({
                    "name": us_status['name'],
                    "slug": slugify(us_status['name']),
                    "is_closed": False,
                    "is_archived": True if us_status['closed'] else False,
                    "color": "#999999",
                    "wip_limit": None,
                    "order": us_status['pos'],
                })

        project_template.task_statuses = []
        project_template.task_statuses.append({
            "name": "Incomplete",
            "slug": "incomplete",
            "is_closed": False,
            "color": "#ff8a84",
            "order": 1,
        })
        project_template.task_statuses.append({
            "name": "Complete",
            "slug": "complete",
            "is_closed": True,
            "color": "#669900",
            "order": 2,
        })
        project_template.default_options["task_status"] = "Incomplete"
        project_template.roles.append({
            "name": "Trello",
            "slug": "trello",
            "computable": False,
            "permissions": project_template.roles[0]['permissions'],
            "order": 70,
        })

        tags_colors = []
        for label in labels:
            name = label['name']
            if not name:
                name = label['color']
            name = name.lower()
            color = self._ensure_hex_color(label['color'])
            tags_colors.append([name, color])

        project = Project(
            name=options.get('name', None) or board['name'],
            description=options.get('description', None) or board['desc'],
            owner=self._user,
            tags_colors=tags_colors,
            creation_template=project_template,
            is_private=options.get('is_private', False),
        )
        (can_create, error_message) = projects_service.check_if_project_can_be_created_or_updated(project)
        if not can_create:
            raise exceptions.NotEnoughSlotsForProject(project.is_private, 1, error_message)
        project.save()

        if board.get('organization', None):
            trello_avatar_template = "https://trello-logos.s3.amazonaws.com/{}/170.png"
            project_logo_url = trello_avatar_template.format(board['organization']['logoHash'])
            data = requests.get(project_logo_url)
            project.logo.save("logo.png", ContentFile(data.content), save=True)

        UserStoryCustomAttribute.objects.create(
            name="Due",
            description="Due date",
            type="date",
            order=1,
            project=project
        )
        import_service.create_memberships(options.get('users_bindings', {}), project, self._user, "trello")
        return project
Example #6
0
    def create(self, request, *args, **kwargs):
        self.check_permissions(request, 'import_project', None)

        data = request.DATA.copy()
        data['owner'] = data.get('owner', request.user.email)

        is_private = data.get('is_private', False)
        (enough_slots, not_enough_slots_error) = users_service.has_available_slot_for_project(
            self.request.user,
            project=Project(is_private=is_private, id=None)
        )
        if not enough_slots:
            raise exc.BadRequest(not_enough_slots_error)

        # Create Project
        project_serialized = service.store_project(data)

        if not project_serialized:
            raise exc.BadRequest(service.get_errors())

        # Create roles
        roles_serialized = None
        if "roles" in data:
            roles_serialized = service.store_roles(project_serialized.object, data)

        if not roles_serialized:
            raise exc.BadRequest(_("We needed at least one role"))

        # Create memberships
        if "memberships" in data:
            members = len(data['memberships'])
            (enough_slots, not_enough_slots_error) = users_service.has_available_slot_for_project(
                self.request.user,
                project=Project(is_private=is_private, id=None),
                members=max(members, 1)
            )
            if not enough_slots:
                raise exc.BadRequest(not_enough_slots_error)
            service.store_memberships(project_serialized.object, data)

        try:
            owner_membership = project_serialized.object.memberships.get(user=project_serialized.object.owner)
            owner_membership.is_owner = True
            owner_membership.save()
        except Membership.DoesNotExist:
            Membership.objects.create(
                project=project_serialized.object,
                email=project_serialized.object.owner.email,
                user=project_serialized.object.owner,
                role=project_serialized.object.roles.all().first(),
                is_owner=True
            )

        # Create project values choicess
        if "points" in data:
            service.store_choices(project_serialized.object, data,
                                  "points", serializers.PointsExportSerializer)
        if "issue_types" in data:
            service.store_choices(project_serialized.object, data,
                                  "issue_types",
                                  serializers.IssueTypeExportSerializer)
        if "issue_statuses" in data:
            service.store_choices(project_serialized.object, data,
                                  "issue_statuses",
                                  serializers.IssueStatusExportSerializer,)
        if "us_statuses" in data:
            service.store_choices(project_serialized.object, data,
                                  "us_statuses",
                                  serializers.UserStoryStatusExportSerializer,)
        if "task_statuses" in data:
            service.store_choices(project_serialized.object, data,
                                  "task_statuses",
                                  serializers.TaskStatusExportSerializer)
        if "priorities" in data:
            service.store_choices(project_serialized.object, data,
                                  "priorities",
                                  serializers.PriorityExportSerializer)
        if "severities" in data:
            service.store_choices(project_serialized.object, data,
                                  "severities",
                                  serializers.SeverityExportSerializer)

        if ("points" in data or "issues_types" in data or
                "issues_statuses" in data or "us_statuses" in data or
                "task_statuses" in data or "priorities" in data or
                "severities" in data):
            service.store_default_choices(project_serialized.object, data)

        # Created custom attributes
        if "userstorycustomattributes" in data:
            service.store_custom_attributes(project_serialized.object, data,
                                            "userstorycustomattributes",
                                            serializers.UserStoryCustomAttributeExportSerializer)

        if "taskcustomattributes" in data:
            service.store_custom_attributes(project_serialized.object, data,
                                            "taskcustomattributes",
                                            serializers.TaskCustomAttributeExportSerializer)

        if "issuecustomattributes" in data:
            service.store_custom_attributes(project_serialized.object, data,
                                            "issuecustomattributes",
                                            serializers.IssueCustomAttributeExportSerializer)

        # Is there any error?
        errors = service.get_errors()
        if errors:
            raise exc.BadRequest(errors)

        # Importer process is OK
        response_data = project_serialized.data
        response_data['id'] = project_serialized.object.id
        headers = self.get_success_headers(response_data)
        return response.Created(response_data, headers=headers)
Example #7
0
def dict_to_project(data, owner=None):
    if owner:
        data["owner"] = owner.email
        members = len([
            m for m in data.get("memberships", [])
            if m.get("email", None) != data["owner"]
        ])
        (enough_slots, not_enough_slots_error
         ) = users_service.has_available_slot_for_project(
             owner, Project(is_private=data.get("is_private", False), id=None),
             members)
        if not enough_slots:
            raise TaigaImportError(not_enough_slots_error)

    project_serialized = service.store_project(data)

    if not project_serialized:
        raise TaigaImportError(_("error importing project data"))

    proj = project_serialized.object

    service.store_choices(proj, data, "points",
                          serializers.PointsExportSerializer)
    service.store_choices(proj, data, "issue_types",
                          serializers.IssueTypeExportSerializer)
    service.store_choices(proj, data, "issue_statuses",
                          serializers.IssueStatusExportSerializer)
    service.store_choices(proj, data, "us_statuses",
                          serializers.UserStoryStatusExportSerializer)
    service.store_choices(proj, data, "task_statuses",
                          serializers.TaskStatusExportSerializer)
    service.store_choices(proj, data, "priorities",
                          serializers.PriorityExportSerializer)
    service.store_choices(proj, data, "severities",
                          serializers.SeverityExportSerializer)

    if service.get_errors(clear=False):
        raise TaigaImportError(
            _("error importing lists of project attributes"))

    service.store_default_choices(proj, data)

    if service.get_errors(clear=False):
        raise TaigaImportError(
            _("error importing default project attributes values"))

    service.store_custom_attributes(
        proj, data, "userstorycustomattributes",
        serializers.UserStoryCustomAttributeExportSerializer)
    service.store_custom_attributes(
        proj, data, "taskcustomattributes",
        serializers.TaskCustomAttributeExportSerializer)
    service.store_custom_attributes(
        proj, data, "issuecustomattributes",
        serializers.IssueCustomAttributeExportSerializer)

    if service.get_errors(clear=False):
        raise TaigaImportError(_("error importing custom attributes"))

    service.store_roles(proj, data)

    if service.get_errors(clear=False):
        raise TaigaImportError(_("error importing roles"))

    service.store_memberships(proj, data)

    if proj.memberships.filter(user=proj.owner).count() == 0:
        if proj.roles.all().count() > 0:
            Membership.objects.create(project=proj,
                                      email=proj.owner.email,
                                      user=proj.owner,
                                      role=proj.roles.all().first(),
                                      is_admin=True)

    if service.get_errors(clear=False):
        raise TaigaImportError(_("error importing memberships"))

    store_milestones(proj, data)

    if service.get_errors(clear=False):
        raise TaigaImportError(_("error importing sprints"))

    store_wiki_pages(proj, data)

    if service.get_errors(clear=False):
        raise TaigaImportError(_("error importing wiki pages"))

    store_wiki_links(proj, data)

    if service.get_errors(clear=False):
        raise TaigaImportError(_("error importing wiki links"))

    store_issues(proj, data)

    if service.get_errors(clear=False):
        raise TaigaImportError(_("error importing issues"))

    store_user_stories(proj, data)

    if service.get_errors(clear=False):
        raise TaigaImportError(_("error importing user stories"))

    store_tasks(proj, data)

    if service.get_errors(clear=False):
        raise TaigaImportError(_("error importing tasks"))

    store_tags_colors(proj, data)

    if service.get_errors(clear=False):
        raise TaigaImportError(_("error importing tags"))

    store_timeline_entries(proj, data)
    if service.get_errors(clear=False):
        raise TaigaImportError(_("error importing timelines"))

    proj.refresh_totals()
    return proj