forked from github/plane
feat: bulk issue operations
This commit is contained in:
parent
60ae940d40
commit
374e52e75a
@ -186,6 +186,9 @@ from plane.api.views import (
|
||||
## Exporter
|
||||
ExportIssuesEndpoint,
|
||||
## End Exporter
|
||||
# Bulk Issue Operations
|
||||
BulkIssueOperationsEndpoint,
|
||||
## End Bulk Issue Operations
|
||||
)
|
||||
|
||||
|
||||
@ -1728,4 +1731,9 @@ urlpatterns = [
|
||||
name="workspace-project-boards",
|
||||
),
|
||||
## End Public Boards
|
||||
path(
|
||||
"workspaces/<str:slug>/projects/<uuid:project_id>/bulk-operation-issues/",
|
||||
BulkIssueOperationsEndpoint.as_view(),
|
||||
name="bulk-issue-operation",
|
||||
),
|
||||
]
|
||||
|
@ -90,6 +90,7 @@ from .issue import (
|
||||
IssueRetrievePublicEndpoint,
|
||||
ProjectIssuesPublicEndpoint,
|
||||
IssueDraftViewSet,
|
||||
BulkIssueOperationsEndpoint,
|
||||
)
|
||||
|
||||
from .auth_extended import (
|
||||
|
@ -82,6 +82,8 @@ from plane.db.models import (
|
||||
IssueVote,
|
||||
IssueRelation,
|
||||
ProjectPublicMember,
|
||||
IssueLabel,
|
||||
IssueAssignee,
|
||||
)
|
||||
from plane.bgtasks.issue_activites_task import issue_activity
|
||||
from plane.utils.grouper import group_results
|
||||
@ -130,7 +132,7 @@ class IssueViewSet(BaseViewSet):
|
||||
current_instance=json.dumps(
|
||||
IssueSerializer(current_instance).data, cls=DjangoJSONEncoder
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
|
||||
return super().perform_update(serializer)
|
||||
@ -151,7 +153,7 @@ class IssueViewSet(BaseViewSet):
|
||||
current_instance=json.dumps(
|
||||
IssueSerializer(current_instance).data, cls=DjangoJSONEncoder
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
return super().perform_destroy(instance)
|
||||
|
||||
@ -282,7 +284,8 @@ class IssueViewSet(BaseViewSet):
|
||||
|
||||
if group_by:
|
||||
return Response(
|
||||
group_results(issues, group_by, sub_group_by), status=status.HTTP_200_OK
|
||||
group_results(issues, group_by, sub_group_by),
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
return Response(issues, status=status.HTTP_200_OK)
|
||||
@ -318,7 +321,7 @@ class IssueViewSet(BaseViewSet):
|
||||
issue_id=str(serializer.data.get("id", None)),
|
||||
project_id=str(project_id),
|
||||
current_instance=None,
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
@ -335,9 +338,7 @@ class IssueViewSet(BaseViewSet):
|
||||
.order_by()
|
||||
.annotate(count=Func(F("id"), function="Count"))
|
||||
.values("count")
|
||||
).get(
|
||||
workspace__slug=slug, project_id=project_id, pk=pk
|
||||
)
|
||||
).get(workspace__slug=slug, project_id=project_id, pk=pk)
|
||||
return Response(IssueSerializer(issue).data, status=status.HTTP_200_OK)
|
||||
except Issue.DoesNotExist:
|
||||
return Response(
|
||||
@ -472,7 +473,8 @@ class UserWorkSpaceIssues(BaseAPIView):
|
||||
|
||||
if group_by:
|
||||
return Response(
|
||||
group_results(issues, group_by, sub_group_by), status=status.HTTP_200_OK
|
||||
group_results(issues, group_by, sub_group_by),
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
return Response(issues, status=status.HTTP_200_OK)
|
||||
@ -577,7 +579,7 @@ class IssueCommentViewSet(BaseViewSet):
|
||||
issue_id=str(self.kwargs.get("issue_id")),
|
||||
project_id=str(self.kwargs.get("project_id")),
|
||||
current_instance=None,
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
|
||||
def perform_update(self, serializer):
|
||||
@ -596,7 +598,7 @@ class IssueCommentViewSet(BaseViewSet):
|
||||
IssueCommentSerializer(current_instance).data,
|
||||
cls=DjangoJSONEncoder,
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
|
||||
return super().perform_update(serializer)
|
||||
@ -618,7 +620,7 @@ class IssueCommentViewSet(BaseViewSet):
|
||||
IssueCommentSerializer(current_instance).data,
|
||||
cls=DjangoJSONEncoder,
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
return super().perform_destroy(instance)
|
||||
|
||||
@ -902,7 +904,7 @@ class IssueLinkViewSet(BaseViewSet):
|
||||
issue_id=str(self.kwargs.get("issue_id")),
|
||||
project_id=str(self.kwargs.get("project_id")),
|
||||
current_instance=None,
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
|
||||
def perform_update(self, serializer):
|
||||
@ -921,7 +923,7 @@ class IssueLinkViewSet(BaseViewSet):
|
||||
IssueLinkSerializer(current_instance).data,
|
||||
cls=DjangoJSONEncoder,
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
|
||||
return super().perform_update(serializer)
|
||||
@ -943,7 +945,7 @@ class IssueLinkViewSet(BaseViewSet):
|
||||
IssueLinkSerializer(current_instance).data,
|
||||
cls=DjangoJSONEncoder,
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
return super().perform_destroy(instance)
|
||||
|
||||
@ -1022,7 +1024,7 @@ class IssueAttachmentEndpoint(BaseAPIView):
|
||||
serializer.data,
|
||||
cls=DjangoJSONEncoder,
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
@ -1045,7 +1047,7 @@ class IssueAttachmentEndpoint(BaseAPIView):
|
||||
issue_id=str(self.kwargs.get("issue_id", None)),
|
||||
project_id=str(self.kwargs.get("project_id", None)),
|
||||
current_instance=None,
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
@ -1248,7 +1250,7 @@ class IssueArchiveViewSet(BaseViewSet):
|
||||
issue_id=str(issue.id),
|
||||
project_id=str(project_id),
|
||||
current_instance=None,
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
|
||||
return Response(IssueSerializer(issue).data, status=status.HTTP_200_OK)
|
||||
@ -1453,7 +1455,7 @@ class IssueReactionViewSet(BaseViewSet):
|
||||
issue_id=str(self.kwargs.get("issue_id", None)),
|
||||
project_id=str(self.kwargs.get("project_id", None)),
|
||||
current_instance=None,
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
|
||||
def destroy(self, request, slug, project_id, issue_id, reaction_code):
|
||||
@ -1477,7 +1479,7 @@ class IssueReactionViewSet(BaseViewSet):
|
||||
"identifier": str(issue_reaction.id),
|
||||
}
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
issue_reaction.delete()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
@ -1526,7 +1528,7 @@ class CommentReactionViewSet(BaseViewSet):
|
||||
issue_id=None,
|
||||
project_id=str(self.kwargs.get("project_id", None)),
|
||||
current_instance=None,
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
|
||||
def destroy(self, request, slug, project_id, comment_id, reaction_code):
|
||||
@ -1551,7 +1553,7 @@ class CommentReactionViewSet(BaseViewSet):
|
||||
"comment_id": str(comment_id),
|
||||
}
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
comment_reaction.delete()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
@ -1648,7 +1650,7 @@ class IssueCommentPublicViewSet(BaseViewSet):
|
||||
issue_id=str(issue_id),
|
||||
project_id=str(project_id),
|
||||
current_instance=None,
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
if not ProjectMember.objects.filter(
|
||||
project_id=project_id,
|
||||
@ -1698,7 +1700,7 @@ class IssueCommentPublicViewSet(BaseViewSet):
|
||||
IssueCommentSerializer(comment).data,
|
||||
cls=DjangoJSONEncoder,
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
@ -1732,7 +1734,7 @@ class IssueCommentPublicViewSet(BaseViewSet):
|
||||
IssueCommentSerializer(comment).data,
|
||||
cls=DjangoJSONEncoder,
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
comment.delete()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
@ -1807,7 +1809,7 @@ class IssueReactionPublicViewSet(BaseViewSet):
|
||||
issue_id=str(self.kwargs.get("issue_id", None)),
|
||||
project_id=str(self.kwargs.get("project_id", None)),
|
||||
current_instance=None,
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
@ -1852,7 +1854,7 @@ class IssueReactionPublicViewSet(BaseViewSet):
|
||||
"identifier": str(issue_reaction.id),
|
||||
}
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
issue_reaction.delete()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
@ -1926,7 +1928,7 @@ class CommentReactionPublicViewSet(BaseViewSet):
|
||||
issue_id=None,
|
||||
project_id=str(self.kwargs.get("project_id", None)),
|
||||
current_instance=None,
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
@ -1978,7 +1980,7 @@ class CommentReactionPublicViewSet(BaseViewSet):
|
||||
"comment_id": str(comment_id),
|
||||
}
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
comment_reaction.delete()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
@ -2042,7 +2044,7 @@ class IssueVotePublicViewSet(BaseViewSet):
|
||||
issue_id=str(self.kwargs.get("issue_id", None)),
|
||||
project_id=str(self.kwargs.get("project_id", None)),
|
||||
current_instance=None,
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
serializer = IssueVoteSerializer(issue_vote)
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
@ -2077,7 +2079,7 @@ class IssueVotePublicViewSet(BaseViewSet):
|
||||
"identifier": str(issue_vote.id),
|
||||
}
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
issue_vote.delete()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
@ -2111,7 +2113,7 @@ class IssueRelationViewSet(BaseViewSet):
|
||||
IssueRelationSerializer(current_instance).data,
|
||||
cls=DjangoJSONEncoder,
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
return super().perform_destroy(instance)
|
||||
|
||||
@ -2145,7 +2147,7 @@ class IssueRelationViewSet(BaseViewSet):
|
||||
issue_id=str(issue_id),
|
||||
project_id=str(project_id),
|
||||
current_instance=None,
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
|
||||
if relation == "blocking":
|
||||
@ -2401,7 +2403,6 @@ class IssueDraftViewSet(BaseViewSet):
|
||||
serializer_class = IssueFlatSerializer
|
||||
model = Issue
|
||||
|
||||
|
||||
def perform_update(self, serializer):
|
||||
requested_data = json.dumps(self.request.data, cls=DjangoJSONEncoder)
|
||||
current_instance = (
|
||||
@ -2417,12 +2418,11 @@ class IssueDraftViewSet(BaseViewSet):
|
||||
current_instance=json.dumps(
|
||||
IssueSerializer(current_instance).data, cls=DjangoJSONEncoder
|
||||
),
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
|
||||
return super().perform_update(serializer)
|
||||
|
||||
|
||||
def perform_destroy(self, instance):
|
||||
current_instance = (
|
||||
self.get_queryset().filter(pk=self.kwargs.get("pk", None)).first()
|
||||
@ -2442,7 +2442,6 @@ class IssueDraftViewSet(BaseViewSet):
|
||||
)
|
||||
return super().perform_destroy(instance)
|
||||
|
||||
|
||||
def get_queryset(self):
|
||||
return (
|
||||
Issue.objects.annotate(
|
||||
@ -2468,7 +2467,6 @@ class IssueDraftViewSet(BaseViewSet):
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@method_decorator(gzip_page)
|
||||
def list(self, request, slug, project_id):
|
||||
try:
|
||||
@ -2577,7 +2575,6 @@ class IssueDraftViewSet(BaseViewSet):
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
|
||||
def create(self, request, slug, project_id):
|
||||
try:
|
||||
project = Project.objects.get(pk=project_id)
|
||||
@ -2602,7 +2599,7 @@ class IssueDraftViewSet(BaseViewSet):
|
||||
issue_id=str(serializer.data.get("id", None)),
|
||||
project_id=str(project_id),
|
||||
current_instance=None,
|
||||
epoch = int(timezone.now().timestamp())
|
||||
epoch=int(timezone.now().timestamp()),
|
||||
)
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
@ -2612,7 +2609,6 @@ class IssueDraftViewSet(BaseViewSet):
|
||||
{"error": "Project was not found"}, status=status.HTTP_404_NOT_FOUND
|
||||
)
|
||||
|
||||
|
||||
def retrieve(self, request, slug, project_id, pk=None):
|
||||
try:
|
||||
issue = Issue.objects.get(
|
||||
@ -2624,3 +2620,224 @@ class IssueDraftViewSet(BaseViewSet):
|
||||
{"error": "Issue Does not exist"}, status=status.HTTP_404_NOT_FOUND
|
||||
)
|
||||
|
||||
|
||||
class BulkIssueOperationsEndpoint(BaseAPIView):
|
||||
permission_classes = [
|
||||
ProjectEntityPermission,
|
||||
]
|
||||
|
||||
def post(self, request, slug, project_id):
|
||||
try:
|
||||
issue_ids = request.data.get("issue_ids", [])
|
||||
# Get all the issues
|
||||
issues = (
|
||||
Issue.objects.filter(
|
||||
workspace__slug=slug, project_id=project_id, pk__in=issue_ids
|
||||
)
|
||||
.select_related("state")
|
||||
.prefetch_related("labels", "assignees")
|
||||
)
|
||||
# Current epoch
|
||||
epoch = int(timezone.now().timestamp())
|
||||
|
||||
# Project details
|
||||
project = Project.objects.get(workspace__slug=slug, pk=project_id)
|
||||
workspace_id = project.workspace_id
|
||||
|
||||
# Initialize arrays
|
||||
bulk_update_issues = []
|
||||
bulk_issue_activities = []
|
||||
bulk_update_issue_labels = []
|
||||
bulk_update_issue_assignees = []
|
||||
|
||||
properties = request.data.get("properties", {})
|
||||
|
||||
for issue in issues:
|
||||
# Priority
|
||||
if properties.get("priority", False):
|
||||
bulk_issue_activities.append(
|
||||
{
|
||||
"type": "issue.activity.updated",
|
||||
"requested_data": json.dumps(
|
||||
{"priority": properties.get("priority")}
|
||||
),
|
||||
"current_instance": json.dumps(
|
||||
{"priority": (issue.priority)}
|
||||
),
|
||||
"issue_id": str(issue.id),
|
||||
"actor_id": str(request.user.id),
|
||||
"project_id": str(project_id),
|
||||
"epoch": epoch,
|
||||
}
|
||||
)
|
||||
issue.priority = properties.get("priority")
|
||||
# State
|
||||
if properties.get("state", False):
|
||||
bulk_issue_activities.append(
|
||||
{
|
||||
"type": "issue.activity.updated",
|
||||
"requested_data": json.dumps(
|
||||
{"state": properties.get("state_id")}
|
||||
),
|
||||
"current_instance": json.dumps({"state": (issue.state_id)}),
|
||||
"issue_id": str(issue.id),
|
||||
"actor_id": str(request.user.id),
|
||||
"project_id": str(project_id),
|
||||
"epoch": epoch,
|
||||
}
|
||||
)
|
||||
issue.state_id = properties.get("state")
|
||||
# Start date
|
||||
if properties.get("start_date", False):
|
||||
bulk_issue_activities.append(
|
||||
{
|
||||
"type": "issue.activity.updated",
|
||||
"requested_data": json.dumps(
|
||||
{"start_date": properties.get("start_date")}
|
||||
),
|
||||
"current_instance": json.dumps(
|
||||
{"start_date": (issue.start_date)}
|
||||
),
|
||||
"issue_id": str(issue.id),
|
||||
"actor_id": str(request.user.id),
|
||||
"project_id": str(project_id),
|
||||
"epoch": epoch,
|
||||
}
|
||||
)
|
||||
issue.start_date = properties.get("start_date")
|
||||
# Target date
|
||||
if properties.get("target_date", False):
|
||||
bulk_issue_activities.append(
|
||||
{
|
||||
"type": "issue.activity.updated",
|
||||
"requested_data": json.dumps(
|
||||
{"target_date": properties.get("requested_data")}
|
||||
),
|
||||
"current_instance": json.dumps(
|
||||
{"target_date": (issue.target_date)}
|
||||
),
|
||||
"issue_id": str(issue.id),
|
||||
"actor_id": str(request.user.id),
|
||||
"project_id": str(project_id),
|
||||
"epoch": epoch,
|
||||
}
|
||||
)
|
||||
issue.target_date = properties.get("target_date")
|
||||
# Estimate point
|
||||
if properties.get("estimate_point", False):
|
||||
bulk_issue_activities.append(
|
||||
{
|
||||
"type": "issue.activity.updated",
|
||||
"requested_data": json.dumps(
|
||||
{"estimate_point": properties.get("estimate_point")}
|
||||
),
|
||||
"current_instance": json.dumps(
|
||||
{"estimate_point": (issue.estimate_point)}
|
||||
),
|
||||
"issue_id": str(issue.id),
|
||||
"actor_id": str(request.user.id),
|
||||
"project_id": str(project_id),
|
||||
"epoch": epoch,
|
||||
}
|
||||
)
|
||||
issue.estimate_point = properties.get("estimate_point")
|
||||
|
||||
bulk_update_issues.append(issue)
|
||||
|
||||
# Labels
|
||||
if properties.get("labels_list", []):
|
||||
for label_id in properties.get("labels_list", []):
|
||||
bulk_update_issue_labels.append(
|
||||
IssueLabel(
|
||||
issue=issue,
|
||||
label_id=label_id,
|
||||
created_by=request.user,
|
||||
project_id=project_id,
|
||||
workspace_id=workspace_id,
|
||||
)
|
||||
)
|
||||
bulk_issue_activities.append(
|
||||
{
|
||||
"type": "issue.activity.updated",
|
||||
"requested_data": json.dumps(
|
||||
{"labels_list": properties.get("labels_list", [])}
|
||||
),
|
||||
"current_instance": json.dumps(
|
||||
{"labels": [str(label.id) for label in issue.labels.all()]}
|
||||
),
|
||||
"issue_id": str(issue.id),
|
||||
"actor_id": str(request.user.id),
|
||||
"project_id": str(project_id),
|
||||
"epoch": epoch,
|
||||
}
|
||||
)
|
||||
|
||||
# Assignees
|
||||
if properties.get("assignees_list", []):
|
||||
for assignee_id in properties.get(
|
||||
"assignees_list", issue.assignees
|
||||
):
|
||||
bulk_update_issue_assignees.append(
|
||||
IssueAssignee(
|
||||
issue=issue,
|
||||
assignee_id=assignee_id,
|
||||
created_by=request.user,
|
||||
project_id=project_id,
|
||||
workspace_id=workspace_id,
|
||||
)
|
||||
)
|
||||
bulk_issue_activities.append(
|
||||
{
|
||||
"type": "issue.activity.updated",
|
||||
"requested_data": json.dumps(
|
||||
{"assignees_list": properties.get("assignees_list", [])}
|
||||
),
|
||||
"current_instance": json.dumps(
|
||||
{
|
||||
"assignees": [
|
||||
str(assignee.id)
|
||||
for assignee in issue.assignees.all()
|
||||
]
|
||||
}
|
||||
),
|
||||
"issue_id": str(issue.id),
|
||||
"actor_id": str(request.user.id),
|
||||
"project_id": str(project_id),
|
||||
"epoch": epoch,
|
||||
}
|
||||
)
|
||||
|
||||
# Bulk update all the objects
|
||||
Issue.objects.bulk_update(
|
||||
bulk_update_issues,
|
||||
["priority", "estimate_point", "start_date", "target_date", "state"],
|
||||
batch_size=100,
|
||||
)
|
||||
|
||||
# Create new labels
|
||||
IssueLabel.objects.bulk_create(
|
||||
bulk_update_issue_labels,
|
||||
ignore_conflicts=True,
|
||||
batch_size=100,
|
||||
)
|
||||
|
||||
# Create new assignees
|
||||
IssueAssignee.objects.bulk_create(
|
||||
bulk_update_issue_assignees,
|
||||
ignore_conflicts=True,
|
||||
batch_size=100,
|
||||
)
|
||||
|
||||
[issue_activity.delay(**activity) for activity in bulk_issue_activities]
|
||||
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
except Project.DoesNotExist:
|
||||
return Response(
|
||||
{"error": "Project does not exists"}, status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
except Exception as e:
|
||||
capture_exception(e)
|
||||
return Response(
|
||||
{"error": "Something went wrong please try again later"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.3 on 2023-09-21 08:05
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('db', '0046_auto_20230919_1421'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='issuelabel',
|
||||
unique_together={('issue', 'label')},
|
||||
),
|
||||
]
|
@ -413,6 +413,7 @@ class IssueLabel(ProjectBaseModel):
|
||||
)
|
||||
|
||||
class Meta:
|
||||
unique_together = ["issue", "label"]
|
||||
verbose_name = "Issue Label"
|
||||
verbose_name_plural = "Issue Labels"
|
||||
db_table = "issue_labels"
|
||||
|
Loading…
Reference in New Issue
Block a user