Exemple #1
0
    def _bulk_update_order(self, order_field, request, **kwargs):
        validator = validators.UpdateTasksOrderBulkValidator(data=request.DATA)
        if not validator.is_valid():
            return response.BadRequest(validator.errors)

        data = validator.data
        project = get_object_or_404(Project, pk=data["project_id"])

        self.check_permissions(request, "bulk_update_order", project)
        if project.blocked_code is not None:
            raise exc.Blocked(_("Blocked element"))

        user_story = None
        user_story_id = data.get("user_story_id", None)
        if user_story_id is not None:
            user_story = get_object_or_404(UserStory, pk=user_story_id)

        status = None
        status_id = data.get("status_id", None)
        if status_id is not None:
            status = get_object_or_404(TaskStatus, pk=status_id)

        milestone = None
        milestone_id = data.get("milestone_id", None)
        if milestone_id is not None:
            milestone = get_object_or_404(Milestone, pk=milestone_id)

        ret = services.update_tasks_order_in_bulk(data["bulk_tasks"],
                                                  order_field,
                                                  project,
                                                  user_story=user_story,
                                                  status=status,
                                                  milestone=milestone)
        return response.Ok(ret)
Exemple #2
0
    def bulk_update_milestone(self, request, **kwargs):
        validator = validators.UpdateMilestoneBulkValidator(data=request.DATA)
        if not validator.is_valid():
            return response.BadRequest(validator.errors)

        data = validator.data
        project = get_object_or_404(Project, pk=data["project_id"])
        milestone = get_object_or_404(Milestone, pk=data["milestone_id"])

        self.check_permissions(request, "bulk_update_milestone", project)

        ret = services.update_issues_milestone_in_bulk(data["bulk_issues"],
                                                       milestone)

        return response.Ok(ret)
Exemple #3
0
    def bulk_create(self, request, **kwargs):
        validator = validators.CreateRelatedUserStoriesBulkValidator(
            data=request.DATA)
        if not validator.is_valid():
            return response.BadRequest(validator.errors)

        data = validator.data

        epic = get_object_or_404(models.Epic, id=kwargs["epic"])
        project = Project.objects.get(pk=data.get('project_id'))

        self.check_permissions(request, 'bulk_create', project)
        if project.blocked_code is not None:
            raise exc.Blocked(_("Blocked element"))

        related_userstories = services.create_related_userstories_in_bulk(
            data["bulk_userstories"],
            epic,
            project=project,
            owner=request.user)

        for related_userstory in related_userstories:
            self.persist_history_snapshot(obj=related_userstory)
            self.persist_history_snapshot(obj=related_userstory.user_story)

        related_uss_serialized = self.get_serializer_class()(
            epic.relateduserstory_set.all(), many=True)
        return response.Ok(related_uss_serialized.data)
Exemple #4
0
    def voted(self, request, *args, **kwargs):
        for_user = get_object_or_404(models.User, **kwargs)
        from_user = request.user
        self.check_permissions(request, 'liked', for_user)
        filters = {
            "type": request.GET.get("type", None),
            "q": request.GET.get("q", None),
        }

        self.object_list = services.get_voted_list(for_user, from_user,
                                                   **filters)
        page = self.paginate_queryset(self.object_list)
        elements = page.object_list if page is not None else self.object_list

        extra_args = {
            "user_watching":
            services.get_watched_content_for_user(request.user),
            "user_votes": services.get_voted_content_for_user(request.user),
        }

        response_data = [
            serializers.VotedObjectSerializer(into_namedtuple(elem),
                                              **extra_args).data
            for elem in elements
        ]

        return response.Ok(response_data)
Exemple #5
0
    def filters_data(self, request, *args, **kwargs):
        project_id = request.QUERY_PARAMS.get("project", None)
        project = get_object_or_404(Project, id=project_id)

        filter_backends = self.get_filter_backends()
        statuses_filter_backends = (f for f in filter_backends
                                    if f != filters.StatusesFilter)
        assigned_to_filter_backends = (f for f in filter_backends
                                       if f != filters.AssignedToFilter)
        owners_filter_backends = (f for f in filter_backends
                                  if f != filters.OwnersFilter)

        queryset = self.get_queryset()
        querysets = {
            "statuses":
            self.filter_queryset(queryset,
                                 filter_backends=statuses_filter_backends),
            "assigned_to":
            self.filter_queryset(queryset,
                                 filter_backends=assigned_to_filter_backends),
            "owners":
            self.filter_queryset(queryset,
                                 filter_backends=owners_filter_backends),
            "tags":
            self.filter_queryset(queryset)
        }
        return response.Ok(services.get_epics_filters_data(project, querysets))
Exemple #6
0
    def duplicate(self, request, pk=None):
        project = self.get_object()
        self.check_permissions(request, "duplicate", project)
        if project.blocked_code is not None:
            raise exc.Blocked(_("Blocked element"))

        validator = validators.DuplicateProjectValidator(data=request.DATA)
        if not validator.is_valid():
            return response.BadRequest(validator.errors)

        data = validator.data

        # Validate if the project can be imported
        is_private = data.get('is_private', False)
        total_memberships = len(data.get("users", [])) + 1
        (enough_slots,
         error_message) = users_services.has_available_slot_for_new_project(
             self.request.user, is_private, total_memberships)
        if not enough_slots:
            raise exc.NotEnoughSlotsForProject(is_private, total_memberships,
                                               error_message)

        new_project = services.duplicate_project(
            project=project,
            owner=request.user,
            name=data["name"],
            description=data["description"],
            is_private=data["is_private"],
            users=data["users"])
        new_project = get_object_or_404(self.get_queryset(), id=new_project.id)
        serializer = self.get_serializer(new_project)
        return response.Created(serializer.data)
Exemple #7
0
    def list(self, request, *args, **kwargs):
        resource_id = kwargs.get("resource_id", None)
        resource = get_object_or_404(self.resource_model, pk=resource_id)

        self.check_permissions(request, 'list', resource)

        return super().list(request, *args, **kwargs)
Exemple #8
0
    def retrieve(self, request, pk, *args, **kwargs):
        throttle = throttling.ImportDumpModeRateThrottle()

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

        project = get_object_or_404(self.get_queryset(), pk=pk)
        self.check_permissions(request, 'export_project', project)

        dump_format = request.QUERY_PARAMS.get("dump_format", "plain")

        if settings.CELERY_ENABLED:
            task = tasks.dump_project.delay(request.user, project, dump_format)
            tasks.delete_project_dump.apply_async((project.pk, project.slug, task.id, dump_format),
                                                  countdown=settings.EXPORTS_TTL)
            return response.Accepted({"export_id": task.id})

        if dump_format == "gzip":
            path = "exports/{}/{}-{}.json.gz".format(project.pk, project.slug, uuid.uuid4().hex)
            with default_storage.open(path, mode="wb") as outfile:
                services.render_project(project, gzip.GzipFile(fileobj=outfile))
        else:
            path = "exports/{}/{}-{}.json".format(project.pk, project.slug, uuid.uuid4().hex)
            with default_storage.open(path, mode="wb") as outfile:
                services.render_project(project, outfile)

        response_data = {
            "url": default_storage.url(path)
        }
        return response.Ok(response_data)
Exemple #9
0
 def by_slug(self, request):
     slug = request.QUERY_PARAMS.get("slug", None)
     project_id = request.QUERY_PARAMS.get("project", None)
     wiki_page = get_object_or_404(models.WikiPage,
                                   slug=slug,
                                   project_id=project_id)
     return self.retrieve(request, pk=wiki_page.pk)
Exemple #10
0
    def filter_queryset(self, request, queryset, view):
        project_id = None
        project = None
        qs = queryset.filter(is_active=True)
        if "project" in request.QUERY_PARAMS:
            try:
                project_id = int(request.QUERY_PARAMS["project"])
            except:
                logger.error(
                    "Filtering project diferent value than an integer: {}".
                    format(request.QUERY_PARAMS["project"]))
                raise exc.BadRequest(_("'project' must be an integer value."))

        if project_id:
            Project = apps.get_model('projects', 'Project')
            project = get_object_or_404(Project, pk=project_id)

        if request.user.is_authenticated() and request.user.is_superuser:
            qs = qs
        elif request.user.is_authenticated():
            Membership = apps.get_model('projects', 'Membership')
            memberships_qs = Membership.objects.filter(user=request.user)
            if project_id:
                memberships_qs = memberships_qs.filter(project_id=project_id)
            memberships_qs = memberships_qs.filter(
                Q(role__permissions__contains=[self.permission])
                | Q(is_admin=True))

            projects_list = [
                membership.project_id for membership in memberships_qs
            ]

            if project:
                is_member = project.id in projects_list
                has_project_public_view_permission = "view_project" in project.public_permissions
                if not is_member and not has_project_public_view_permission:
                    qs = qs.none()

            q = Q(memberships__project_id__in=projects_list) | Q(
                id=request.user.id)

            # If there is no selected project we want access to users from public projects
            if not project:
                q = q | Q(memberships__project__public_permissions__contains=[
                    self.permission
                ])

            qs = qs.filter(q)

        else:
            if project and "view_project" not in project.anon_permissions:
                qs = qs.none()

            qs = qs.filter(memberships__project__anon_permissions__contains=[
                self.permission
            ])

        return qs.distinct()
Exemple #11
0
def authorize_token(application_id:int, user:object, state:str) -> object:
    ApplicationToken = apps.get_model("external_apps", "ApplicationToken")
    Application = apps.get_model("external_apps", "Application")
    application = get_object_or_404(Application, id=application_id)
    token, _ = ApplicationToken.objects.get_or_create(user=user, application=application)
    token.update_auth_code()
    token.state = state
    token.save()
    return token
Exemple #12
0
    def patch(self, request, *args, **kwargs):
        self.check_permissions(request)

        resource_id = kwargs.get("resource_id", None)
        resource = get_object_or_404(self.resource_model, pk=resource_id)
        resource.read = timezone.now()
        resource.save()

        return response.Ok({})
Exemple #13
0
    def move_issues_to_sprint(self, request, pk=None, **kwargs):
        milestone = get_object_or_404(models.Milestone, pk=pk)

        self.check_permissions(request, "move_related_items", milestone)

        validator = IssuesUpdateMilestoneValidator(data=request.DATA)
        if not validator.is_valid():
            return response.BadRequest(validator.errors)

        data = validator.data
        project = get_object_or_404(Project, pk=data["project_id"])
        milestone_result = get_object_or_404(models.Milestone, pk=data["milestone_id"])

        if data["bulk_issues"]:
            self.check_permissions(request, "move_issues_to_sprint", project)
            services.update_issues_milestone_in_bulk(data["bulk_issues"], milestone_result)
            services.snapshot_issues_in_bulk(data["bulk_issues"], request.user)

        return response.NoContent()
Exemple #14
0
    def pre_delete(self, obj):
        move_to = self.request.QUERY_PARAMS.get('moveTo', None)
        if move_to:
            membership_model = apps.get_model("projects", "Membership")
            role_dest = get_object_or_404(self.model,
                                          project=obj.project,
                                          id=move_to)
            qs = membership_model.objects.filter(project_id=obj.project.pk,
                                                 role=obj)
            qs.update(role=role_dest)

        super().pre_delete(obj)
Exemple #15
0
    def remove_logo(self, request, *args, **kwargs):
        """
        Remove the logo of a project.
        """
        self.object = get_object_or_404(self.get_queryset(), **kwargs)
        self.check_permissions(request, "remove_logo", self.object)
        self.pre_conditions_on_save(self.object)
        self.object.logo = None
        self.object.save(update_fields=["logo"])

        serializer = self.get_serializer(self.object)
        return response.Ok(serializer.data)
Exemple #16
0
    def csv(self, request):
        uuid = request.QUERY_PARAMS.get("uuid", None)
        if uuid is None:
            return response.NotFound()

        project = get_object_or_404(Project, epics_csv_uuid=uuid)
        queryset = project.epics.all().order_by('ref')
        data = services.epics_to_csv(project, queryset)
        csv_response = HttpResponse(
            data.getvalue(), content_type='application/csv; charset=utf-8')
        csv_response[
            'Content-Disposition'] = 'attachment; filename="epics.csv"'
        return csv_response
Exemple #17
0
    def filters_data(self, request, *args, **kwargs):
        project_id = request.QUERY_PARAMS.get("project", None)
        project = get_object_or_404(Project, id=project_id)

        filter_backends = self.get_filter_backends()
        types_filter_backends = (f for f in filter_backends
                                 if f != filters.IssueTypesFilter)
        statuses_filter_backends = (f for f in filter_backends
                                    if f != filters.StatusesFilter)
        assigned_to_filter_backends = (f for f in filter_backends
                                       if f != filters.AssignedToFilter)
        owners_filter_backends = (f for f in filter_backends
                                  if f != filters.OwnersFilter)
        priorities_filter_backends = (f for f in filter_backends
                                      if f != filters.PrioritiesFilter)
        severities_filter_backends = (f for f in filter_backends
                                      if f != filters.SeveritiesFilter)
        roles_filter_backends = (f for f in filter_backends
                                 if f != filters.RoleFilter)
        tags_filter_backends = (f for f in filter_backends
                                if f != filters.TagsFilter)

        queryset = self.get_queryset()
        querysets = {
            "types":
            self.filter_queryset(queryset,
                                 filter_backends=types_filter_backends),
            "statuses":
            self.filter_queryset(queryset,
                                 filter_backends=statuses_filter_backends),
            "assigned_to":
            self.filter_queryset(queryset,
                                 filter_backends=assigned_to_filter_backends),
            "owners":
            self.filter_queryset(queryset,
                                 filter_backends=owners_filter_backends),
            "priorities":
            self.filter_queryset(queryset,
                                 filter_backends=priorities_filter_backends),
            "severities":
            self.filter_queryset(queryset,
                                 filter_backends=severities_filter_backends),
            "tags":
            self.filter_queryset(queryset,
                                 filter_backends=tags_filter_backends),
            "roles":
            self.filter_queryset(queryset,
                                 filter_backends=roles_filter_backends),
        }
        return response.Ok(services.get_issues_filters_data(
            project, querysets))
Exemple #18
0
    def retrieve(self, request, *args, **kwargs):
        pk = kwargs.get("pk", None)
        resource_id = kwargs.get("resource_id", None)
        resource = get_object_or_404(self.resource_model, pk=resource_id)

        self.check_permissions(request, 'retrieve', resource)

        try:
            self.object = services.get_voters(resource).get(pk=pk)
        except ObjectDoesNotExist:  # or User.DoesNotExist
            return response.NotFound()

        serializer = self.get_serializer(self.object)
        return response.Ok(serializer.data)
Exemple #19
0
    def validate(self, request, pk=None):
        application_id = request.DATA.get("application", None)
        auth_code = request.DATA.get("auth_code", None)
        state = request.DATA.get("state", None)
        application_token = get_object_or_404(models.ApplicationToken,
                                              application__id=application_id,
                                              auth_code=auth_code,
                                              state=state)

        application_token.generate_token()
        application_token.save()

        access_token_data = serializers.AccessTokenSerializer(application_token).data
        return response.Ok(access_token_data)
Exemple #20
0
    def render(self, request, **kwargs):
        content = request.DATA.get("content", None)
        project_id = request.DATA.get("project_id", None)

        if not content:
            raise exc.WrongArguments(
                {"content": _("'content' parameter is mandatory")})

        if not project_id:
            raise exc.WrongArguments(
                {"project_id": _("'project_id' parameter is mandatory")})

        project = get_object_or_404(Project, pk=project_id)

        self.check_permissions(request, "render", project)

        data = mdrender(project, content)
        return response.Ok({"data": data})
Exemple #21
0
    def contacts(self, request, *args, **kwargs):
        user = get_object_or_404(models.User, **kwargs)
        self.check_permissions(request, 'contacts', user)

        self.object_list = user_filters.ContactsFilterBackend(
        ).filter_queryset(
            user, request, self.get_queryset(),
            self).extra(select={
                "complete_user_name": "concat(full_name, username)"
            }).order_by("complete_user_name")

        page = self.paginate_queryset(self.object_list)
        if page is not None:
            serializer = self.serializer_class(page.object_list, many=True)
        else:
            serializer = self.serializer_class(self.object_list, many=True)

        return response.Ok(serializer.data)
Exemple #22
0
    def bulk_update_order(self, request, **kwargs):
        bulk_data = request.DATA.get(self.bulk_update_param, None)

        if bulk_data is None:
            raise exc.BadRequest(_("'{param}' parameter is mandatory".format(param=self.bulk_update_param)))

        project_id = request.DATA.get('project', None)
        if project_id is None:
            raise exc.BadRequest(_("'project' parameter is mandatory"))

        project = get_object_or_404(Project, id=project_id)

        self.check_permissions(request, 'bulk_update_order', project)
        if project.blocked_code is not None:
            raise exc.Blocked(_("Blocked element"))
            
        self.__class__.bulk_update_order_action(project, request.user, bulk_data)
        return response.NoContent(data=None)
Exemple #23
0
    def token(self, request, *args, **kwargs):
        if self.request.user.is_anonymous():
            raise exc.NotAuthenticated(_("Authentication required"))

        application = get_object_or_404(models.Application, **kwargs)
        self.check_permissions(request, 'token', request.user)
        try:
            application_token = models.ApplicationToken.objects.get(user=request.user, application=application)
            application_token.update_auth_code()
            application_token.state = request.GET.get("state", None)
            application_token.save()

        except models.ApplicationToken.DoesNotExist:
            application_token = models.ApplicationToken(
                user=request.user,
                application=application
            )

        auth_code_data = serializers.ApplicationTokenSerializer(application_token).data
        return response.Ok(auth_code_data)
Exemple #24
0
    def retrieve(self, request, *args, **kwargs):
        qs = self.get_queryset()
        if self.action == "by_slug":
            self.lookup_field = "slug"
            # If we retrieve the project by slug we want to filter by user the
            # permissions and return 404 in case the user don't have access
            flt = filters.get_filter_expression_can_view_projects(
                self.request.user)

            qs = qs.filter(flt)

        self.object = get_object_or_404(qs, **kwargs)

        self.check_permissions(request, 'retrieve', self.object)

        if self.object is None:
            raise Http404

        serializer = self.get_serializer(self.object)
        return response.Ok(serializer.data)
Exemple #25
0
    def destroy(self, request, *args, **kwargs):
        move_to = self.request.QUERY_PARAMS.get('moveTo', None)
        if move_to is None:
            return super().destroy(request, *args, **kwargs)

        obj = self.get_object_or_none()
        move_item = get_object_or_404(self.model, id=move_to)

        self.check_permissions(request, 'destroy', obj)

        qs = self.move_on_destroy_related_class.objects.filter(
            **{self.move_on_destroy_related_field: obj})
        qs.update(**{self.move_on_destroy_related_field: move_item})

        if getattr(obj.project,
                   self.move_on_destroy_project_default_field) == obj:
            setattr(obj.project, self.move_on_destroy_project_default_field,
                    move_item)
            obj.project.save()

        return super().destroy(request, *args, **kwargs)
Exemple #26
0
    def get_serializer_class(self):
        use_admin_serializer = False

        if self.action == "create":
            use_admin_serializer = True

        if self.action == "retrieve":
            use_admin_serializer = permissions_services.is_project_admin(
                self.request.user, self.object.project)

        project_id = self.request.QUERY_PARAMS.get("project", None)
        if self.action == "list" and project_id is not None:
            project = get_object_or_404(models.Project, pk=project_id)
            use_admin_serializer = permissions_services.is_project_admin(
                self.request.user, project)

        if use_admin_serializer:
            return self.admin_serializer_class

        else:
            return self.serializer_class
Exemple #27
0
def duplicate_project(project, **new_project_extra_args):
    owner = new_project_extra_args.get("owner")
    users = new_project_extra_args.pop("users")

    disconnect_projects_signals()
    Project = apps.get_model("projects", "Project")
    new_project = Project.objects.create(**new_project_extra_args)
    connect_projects_signals()

    permissions_services.set_base_permissions_for_project(new_project)

    # Cloning the structure from the old project using templates
    Template = apps.get_model("projects", "ProjectTemplate")
    template = Template()
    template.load_data_from_project(project)
    template.apply_to_project(new_project)
    new_project.creation_template = project.creation_template
    new_project.save()

    # Creating the membership for the new owner
    Membership = apps.get_model("projects", "Membership")
    Membership.objects.create(
        user=owner,
        is_admin=True,
        role=new_project.roles.get(slug=template.default_owner_role),
        project=new_project)

    # Creating the extra memberships
    for user in users:
        project_memberships = project.memberships.exclude(user_id=owner.id)
        membership = get_object_or_404(project_memberships, user_id=user["id"])
        Membership.objects.create(
            user=membership.user,
            is_admin=membership.is_admin,
            role=new_project.roles.get(slug=membership.role.slug),
            project=new_project)

    # Take initial snapshot for the project
    take_snapshot(new_project, user=owner)
    return new_project
Exemple #28
0
    def watched(self, request, *args, **kwargs):
        for_user = get_object_or_404(models.User, **kwargs)
        from_user = request.user
        self.check_permissions(request, 'watched', for_user)
        filters = {
            "type": request.GET.get("type", None),
            "q": request.GET.get("q", None),
        }

        self.object_list = services.get_watched_list(for_user, from_user,
                                                     **filters)
        page = self.paginate_queryset(self.object_list)
        elements = page.object_list if page is not None else self.object_list

        extra_args_liked = {
            "user_watching":
            services.get_watched_content_for_user(request.user),
            "user_likes": services.get_liked_content_for_user(request.user),
        }

        extra_args_voted = {
            "user_watching":
            services.get_watched_content_for_user(request.user),
            "user_votes": services.get_voted_content_for_user(request.user),
        }

        response_data = []
        for elem in elements:
            if elem["type"] == "project":
                # projects are liked objects
                response_data.append(
                    serializers.LikedObjectSerializer(into_namedtuple(elem),
                                                      **extra_args_liked).data)
            else:
                # stories, tasks and issues are voted objects
                response_data.append(
                    serializers.VotedObjectSerializer(into_namedtuple(elem),
                                                      **extra_args_voted).data)

        return response.Ok(response_data)
Exemple #29
0
    def change_logo(self, request, *args, **kwargs):
        """
        Change logo to this project.
        """
        self.object = get_object_or_404(self.get_queryset(), **kwargs)
        self.check_permissions(request, "change_logo", self.object)

        logo = request.FILES.get('logo', None)
        if not logo:
            raise exc.WrongArguments(_("Incomplete arguments"))
        try:
            pil_image(logo)
        except Exception:
            raise exc.WrongArguments(_("Invalid image format"))

        self.pre_conditions_on_save(self.object)

        self.object.logo = logo
        self.object.save(update_fields=["logo"])

        serializer = self.get_serializer(self.object)
        return response.Ok(serializer.data)
Exemple #30
0
    def stats(self, request, pk=None):
        milestone = get_object_or_404(models.Milestone, pk=pk)

        self.check_permissions(request, "stats", milestone)

        total_points = milestone.total_points
        milestone_stats = {
            'name': milestone.name,
            'estimated_start': milestone.estimated_start,
            'estimated_finish': milestone.estimated_finish,
            'total_points': total_points,
            'completed_points': milestone.closed_points.values(),
            'total_userstories': milestone.cached_user_stories.count(),
            'completed_userstories': milestone.cached_user_stories.filter(is_closed=True).count(),
            'total_tasks': milestone.tasks.count(),
            'completed_tasks': milestone.tasks.filter(status__is_closed=True).count(),
            'iocaine_doses': milestone.tasks.filter(is_iocaine=True).count(),
            'days': []
        }
        current_date = milestone.estimated_start
        sumTotalPoints = sum(total_points.values())
        optimal_points = sumTotalPoints
        milestone_days = (milestone.estimated_finish - milestone.estimated_start).days
        optimal_points_per_day = sumTotalPoints / milestone_days if milestone_days else 0

        while current_date <= milestone.estimated_finish:
            milestone_stats['days'].append({
                'day': current_date,
                'name': current_date.day,
                'open_points':  sumTotalPoints - milestone.total_closed_points_by_date(current_date),
                'optimal_points': optimal_points,
            })
            current_date = current_date + datetime.timedelta(days=1)
            optimal_points -= optimal_points_per_day

        return response.Ok(milestone_stats)