def move_userstories_to_sprint(self, request, pk=None, **kwargs): milestone = get_object_or_error(models.Milestone, request.user, pk=pk) self.check_permissions(request, "move_related_items", milestone) validator = validators.UpdateMilestoneBulkValidator(data=request.DATA) if not validator.is_valid(): return response.BadRequest(validator.errors) data = validator.data project = get_object_or_error(Project, request.user, pk=data["project_id"]) milestone_result = get_object_or_error(models.Milestone, request.user, pk=data["milestone_id"]) if data["bulk_stories"]: self.check_permissions(request, "move_uss_to_sprint", project) services.update_userstories_milestone_in_bulk( data["bulk_stories"], milestone_result) services.snapshot_userstories_in_bulk(data["bulk_stories"], request.user) return response.NoContent()
def bulk_update_kanban_order(self, request, **kwargs): # Validate data validator = validators.UpdateUserStoriesKanbanOrderBulkValidator( data=request.DATA) if not validator.is_valid(): return response.BadRequest(validator.errors) data = validator.data # Get and validate project permissions project = get_object_or_error(Project, request.user, pk=data["project_id"]) self.check_permissions(request, "bulk_update_order", project) if project.blocked_code is not None: raise exc.Blocked(_("Blocked element")) # Get status status = get_object_or_error(UserStoryStatus, request.user, pk=data["status_id"], project=project) # Get swimlane swimlane = None swimlane_id = data.get("swimlane_id", None) if swimlane_id is not None: swimlane = get_object_or_error(Swimlane, request.user, pk=swimlane_id, project=project) # Get after_userstory after_userstory = None after_userstory_id = data.get("after_userstory_id", None) if after_userstory_id is not None: after_userstory = get_object_or_error(models.UserStory, request.user, pk=after_userstory_id, project=project) # Get before_userstory before_userstory = None before_userstory_id = data.get("before_userstory_id", None) if before_userstory_id is not None: before_userstory = get_object_or_error(models.UserStory, request.user, pk=before_userstory_id, project=project) ret = services.update_userstories_kanban_order_in_bulk( user=request.user, project=project, status=status, swimlane=swimlane, after_userstory=after_userstory, before_userstory=before_userstory, bulk_userstories=data["bulk_userstories"]) return response.Ok(ret)
def bulk_update_backlog_order(self, request, **kwargs): # Validate data validator = validators.UpdateUserStoriesBacklogOrderBulkValidator( data=request.DATA) if not validator.is_valid(): return response.BadRequest(validator.errors) data = validator.data # Get and validate project permissions project = get_object_or_error(Project, request.user, pk=data["project_id"]) self.check_permissions(request, "bulk_update_order", project) if project.blocked_code is not None: raise exc.Blocked(_("Blocked element")) # Get milestone milestone = None milestone_id = data.get("milestone_id", None) if milestone_id is not None: milestone = get_object_or_error(Milestone, request.user, pk=milestone_id, project=project) # Get after_userstory after_userstory = None after_userstory_id = data.get("after_userstory_id", None) if after_userstory_id is not None: after_userstory = get_object_or_error(models.UserStory, request.user, pk=after_userstory_id, project=project) # Get before_userstory before_userstory = None before_userstory_id = data.get("before_userstory_id", None) if before_userstory_id is not None: before_userstory = get_object_or_error(models.UserStory, request.user, pk=before_userstory_id, project=project) ret = services.update_userstories_backlog_or_sprint_order_in_bulk( user=request.user, project=project, milestone=milestone, after_userstory=after_userstory, before_userstory=before_userstory, bulk_userstories=data["bulk_userstories"]) return response.Ok(ret)
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_error(self.get_queryset(), request.user, id=new_project.id) serializer = self.get_serializer(new_project) return response.Created(serializer.data)
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_error(models.Epic, request.user, 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)
def filters_data(self, request, *args, **kwargs): project_id = request.QUERY_PARAMS.get("project", None) project = get_object_or_error(Project, request.user, 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) 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 = { "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, filter_backends=tags_filter_backends), "roles": self.filter_queryset(queryset, filter_backends=roles_filter_backends), } return response.Ok(services.get_tasks_filters_data(project, querysets))
def bulk_update_order(self, request, **kwargs): contenttype = self.get_content_type() # Validate data data = request.DATA.copy() data["content_type_id"] = contenttype.id validator = validators.UpdateAttachmentsOrderBulkValidator(data=data) if not validator.is_valid(): return response.BadRequest(validator.errors) # Get and validate permissions item = contenttype.get_object_for_this_type(pk=data["object_id"]) self.check_permissions(request, "bulk_update_order", item.project) if item.project.blocked_code is not None: raise exc.Blocked(_("Blocked element")) # Get after_attachment after_attachment = None after_attachment_id = data.get("after_attachment_id", None) if after_attachment_id is not None: after_attachment = get_object_or_error(item.attachments, request.user, pk=after_attachment_id) ret = services.update_order_in_bulk(item=item, after_attachment=after_attachment, bulk_attachments=data["bulk_attachments"]) return response.Ok(ret)
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_error(self.get_queryset(), request.user, 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)
def list(self, request, *args, **kwargs): resource_id = kwargs.get("resource_id", None) resource = get_object_or_error(self.resource_model, request.user, pk=resource_id) self.check_permissions(request, 'list', resource) return super().list(request, *args, **kwargs)
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_error(Project, request.user, 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()
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_error(Project, request.user, pk=data["project_id"]) milestone = get_object_or_error(Milestone, request.user, 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)
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_error(Project, request.user, 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_error(UserStory, request.user, pk=user_story_id) status = None status_id = data.get("status_id", None) if status_id is not None: status = get_object_or_error(TaskStatus, request.user, pk=status_id) milestone = None milestone_id = data.get("milestone_id", None) if milestone_id is not None: milestone = get_object_or_error(Milestone, request.user, 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)
def patch(self, request, *args, **kwargs): self.check_permissions(request) resource_id = kwargs.get("resource_id", None) resource = get_object_or_error(self.resource_model, request.user, pk=resource_id) resource.read = timezone.now() resource.save() return response.Ok({})
def csv(self, request): uuid = request.QUERY_PARAMS.get("uuid", None) if uuid is None: return response.NotFound() project = get_object_or_error(Project, request.user, 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
def stats(self, request, pk=None): milestone = get_object_or_error(models.Milestone, request.user, 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)
def remove_logo(self, request, *args, **kwargs): """ Remove the logo of a project. """ self.object = get_object_or_error(self.get_queryset(), request.user, **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)
def retrieve(self, request, *args, **kwargs): pk = kwargs.get("pk", None) resource_id = kwargs.get("resource_id", None) resource = get_object_or_error(self.resource_model, request.user, pk=resource_id) self.check_permissions(request, 'retrieve', resource) try: self.object = services.get_fans(resource).get(pk=pk) except ObjectDoesNotExist: # or User.DoesNotExist return response.NotFound() serializer = self.get_serializer(self.object) return response.Ok(serializer.data)
def filters_data(self, request, *args, **kwargs): project_id = request.QUERY_PARAMS.get("project", None) project = get_object_or_error(Project, request.user, id=project_id) filter_backends = self.get_filter_backends() statuses_filter_backends = (f for f in filter_backends if f != filters.UserStoryStatusesFilter) assigned_to_filter_backends = (f for f in filter_backends if f != base_filters.AssignedToFilter) assigned_users_filter_backends = (f for f in filter_backends if f != filters.AssignedUsersFilter) owners_filter_backends = (f for f in filter_backends if f != base_filters.OwnersFilter) epics_filter_backends = (f for f in filter_backends if f != filters.EpicFilter) roles_filter_backends = (f for f in filter_backends if f != base_filters.RoleFilter) tags_filter_backends = (f for f in filter_backends if f != base_filters.TagsFilter) queryset = self.get_queryset() # assigned_to is kept for retro-compatibility reasons; but currently filters # are using assigned_users querysets = { "statuses": self.filter_queryset(queryset, filter_backends=statuses_filter_backends), "assigned_to": self.filter_queryset(queryset, filter_backends=assigned_to_filter_backends), "assigned_users": self.filter_queryset( queryset, filter_backends=assigned_users_filter_backends), "owners": self.filter_queryset(queryset, filter_backends=owners_filter_backends), "tags": self.filter_queryset(queryset, filter_backends=tags_filter_backends), "epics": self.filter_queryset(queryset, filter_backends=epics_filter_backends), "roles": self.filter_queryset(queryset, filter_backends=roles_filter_backends) } return response.Ok( services.get_userstories_filters_data(project, querysets))
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(request.user) qs = qs.filter(flt) self.object = get_object_or_error(qs, request.user, **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)
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 new_name = data.get("name", "") new_description = data.get("description", "") new_owner = self.request.user new_is_private = data.get('is_private', False) new_members = data.get("users", []) # Validate if the project can be imported (enough_slots, error_message, total_members) = services.check_if_project_can_be_duplicate( project=project, new_owner=new_owner, new_is_private=new_is_private, new_user_id_members=[m["id"] for m in new_members]) if not enough_slots: raise exc.NotEnoughSlotsForProject(new_is_private, total_members, error_message) new_project = services.duplicate_project(project=project, name=new_name, description=new_description, owner=new_owner, is_private=new_is_private, users=new_members) new_project = get_object_or_error(self.get_queryset(), request.user, id=new_project.id) serializer = self.get_serializer(new_project) return response.Created(serializer.data)
def change_logo(self, request, *args, **kwargs): """ Change logo to this project. """ self.object = get_object_or_error(self.get_queryset(), request.user, **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)
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_error(models.Project, self.request.user, 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
def _get_project(self, project_id): project_model = apps.get_model("projects", "Project") return get_object_or_error(project_model, self.request.user, pk=project_id)
def list(self, request, **kwargs): validator = ResolverValidator(data=request.QUERY_PARAMS) if not validator.is_valid(): raise exc.BadRequest(validator.errors) data = validator.data project_model = apps.get_model("projects", "Project") project = get_object_or_error(project_model, request.user, slug=data["project"]) self.check_permissions(request, "list", project) result = {"project": project.pk} if data["epic"] and user_has_perm(request.user, "view_epics", project): result["epic"] = get_object_or_error(project.epics.all(), request.user, ref=data["epic"]).pk if data["us"] and user_has_perm(request.user, "view_us", project): result["us"] = get_object_or_error(project.user_stories.all(), request.user, ref=data["us"]).pk if data["task"] and user_has_perm(request.user, "view_tasks", project): result["task"] = get_object_or_error(project.tasks.all(), request.user, ref=data["task"]).pk if data["issue"] and user_has_perm(request.user, "view_issues", project): result["issue"] = get_object_or_error(project.issues.all(), request.user, ref=data["issue"]).pk if data["milestone"] and user_has_perm(request.user, "view_milestones", project): result["milestone"] = get_object_or_error(project.milestones.all(), request.user, slug=data["milestone"]).pk if data["wikipage"] and user_has_perm(request.user, "view_wiki_pages", project): result["wikipage"] = get_object_or_error(project.wiki_pages.all(), request.user, slug=data["wikipage"]).pk if data["ref"]: ref_found = False # No need to continue once one ref is found try: value = int(data["ref"]) if user_has_perm(request.user, "view_epics", project): epic = project.epics.filter(ref=value).first() if epic: result["epic"] = epic.pk ref_found = True if ref_found is False and user_has_perm(request.user, "view_us", project): us = project.user_stories.filter(ref=value).first() if us: result["us"] = us.pk ref_found = True if ref_found is False and user_has_perm(request.user, "view_tasks", project): task = project.tasks.filter(ref=value).first() if task: result["task"] = task.pk ref_found = True if ref_found is False and user_has_perm(request.user, "view_issues", project): issue = project.issues.filter(ref=value).first() if issue: result["issue"] = issue.pk except: value = data["ref"] if user_has_perm(request.user, "view_wiki_pages", project): wiki_page = project.wiki_pages.filter(slug=value).first() if wiki_page: result["wikipage"] = wiki_page.pk return response.Ok(result)