Skip to content

Commit 2d0981c

Browse files
pablohashescobarlifeiscontent
authored andcommitted
fix: assignee validation when updating issues (#6720)
* fix: assignee validation * chore: remove prints * fix: remove all assignees
1 parent ae5de0a commit 2d0981c

File tree

4 files changed

+45
-41
lines changed

4 files changed

+45
-41
lines changed

apiserver/plane/app/serializers/issue.py

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -111,25 +111,23 @@ def to_representation(self, instance):
111111
data["label_ids"] = label_ids if label_ids else []
112112
return data
113113

114-
def validate(self, data):
114+
def validate(self, attrs):
115115
if (
116-
data.get("start_date", None) is not None
117-
and data.get("target_date", None) is not None
118-
and data.get("start_date", None) > data.get("target_date", None)
116+
attrs.get("start_date", None) is not None
117+
and attrs.get("target_date", None) is not None
118+
and attrs.get("start_date", None) > attrs.get("target_date", None)
119119
):
120120
raise serializers.ValidationError("Start date cannot exceed target date")
121-
return data
122121

123-
def get_valid_assignees(self, assignees, project_id):
124-
if not assignees:
125-
return []
122+
if attrs.get("assignee_ids", []):
123+
attrs["assignee_ids"] = ProjectMember.objects.filter(
124+
project_id=self.context["project_id"],
125+
role__gte=15,
126+
is_active=True,
127+
member_id__in=attrs["assignee_ids"],
128+
).values_list("member_id", flat=True)
126129

127-
return ProjectMember.objects.filter(
128-
project_id=project_id,
129-
role__gte=15,
130-
is_active=True,
131-
member_id__in=assignees
132-
).values_list('member_id', flat=True)
130+
return attrs
133131

134132
def create(self, validated_data):
135133
assignees = validated_data.pop("assignee_ids", None)
@@ -146,33 +144,35 @@ def create(self, validated_data):
146144
created_by_id = issue.created_by_id
147145
updated_by_id = issue.updated_by_id
148146

149-
valid_assignee_ids = self.get_valid_assignees(assignees, project_id)
150-
if valid_assignee_ids is not None and len(valid_assignee_ids):
147+
if assignees is not None and len(assignees):
151148
try:
152149
IssueAssignee.objects.bulk_create(
153150
[
154151
IssueAssignee(
155-
assignee_id=user_id,
152+
assignee_id=assignee_id,
156153
issue=issue,
157154
project_id=project_id,
158155
workspace_id=workspace_id,
159156
created_by_id=created_by_id,
160157
updated_by_id=updated_by_id,
161158
)
162-
for user_id in valid_assignee_ids
159+
for assignee_id in assignees
163160
],
164161
batch_size=10,
165162
)
166163
except IntegrityError:
167164
pass
168165
else:
169166
# Then assign it to default assignee, if it is a valid assignee
170-
if default_assignee_id is not None and ProjectMember.objects.filter(
171-
member_id=default_assignee_id,
172-
project_id=project_id,
173-
role__gte=15,
174-
is_active=True
175-
).exists():
167+
if (
168+
default_assignee_id is not None
169+
and ProjectMember.objects.filter(
170+
member_id=default_assignee_id,
171+
project_id=project_id,
172+
role__gte=15,
173+
is_active=True,
174+
).exists()
175+
):
176176
try:
177177
IssueAssignee.objects.create(
178178
assignee_id=default_assignee_id,
@@ -216,21 +216,20 @@ def update(self, instance, validated_data):
216216
created_by_id = instance.created_by_id
217217
updated_by_id = instance.updated_by_id
218218

219-
valid_assignee_ids = self.get_valid_assignees(assignees, project_id)
220-
if valid_assignee_ids is not None:
219+
if assignees is not None:
221220
IssueAssignee.objects.filter(issue=instance).delete()
222221
try:
223222
IssueAssignee.objects.bulk_create(
224223
[
225224
IssueAssignee(
226-
assignee_id=user_id,
225+
assignee_id=assignee_id,
227226
issue=instance,
228227
project_id=project_id,
229228
workspace_id=workspace_id,
230229
created_by_id=created_by_id,
231230
updated_by_id=updated_by_id,
232231
)
233-
for user_id in valid_assignee_ids
232+
for assignee_id in assignees
234233
],
235234
batch_size=10,
236235
ignore_conflicts=True,

apiserver/plane/app/views/intake/base.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,9 @@ def list(self, request, slug, project_id):
178178
workspace__slug=slug, project_id=project_id
179179
).first()
180180
if not intake:
181-
return Response({"error": "Intake not found"}, status=status.HTTP_404_NOT_FOUND)
181+
return Response(
182+
{"error": "Intake not found"}, status=status.HTTP_404_NOT_FOUND
183+
)
182184

183185
project = Project.objects.get(pk=project_id)
184186
filters = issue_filters(request.GET, "GET", "issue__")
@@ -385,7 +387,7 @@ def partial_update(self, request, slug, project_id, pk):
385387
}
386388

387389
issue_serializer = IssueCreateSerializer(
388-
issue, data=issue_data, partial=True
390+
issue, data=issue_data, partial=True, context={"project_id": project_id}
389391
)
390392

391393
if issue_serializer.is_valid():

apiserver/plane/app/views/issue/base.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,9 @@ def partial_update(self, request, slug, project_id, pk=None):
635635
)
636636

637637
requested_data = json.dumps(self.request.data, cls=DjangoJSONEncoder)
638-
serializer = IssueCreateSerializer(issue, data=request.data, partial=True)
638+
serializer = IssueCreateSerializer(
639+
issue, data=request.data, partial=True, context={"project_id": project_id}
640+
)
639641
if serializer.is_valid():
640642
serializer.save()
641643
issue_activity.delay(
@@ -1099,7 +1101,6 @@ def post(self, request, slug, project_id):
10991101

11001102

11011103
class IssueMetaEndpoint(BaseAPIView):
1102-
11031104
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST], level="PROJECT")
11041105
def get(self, request, slug, project_id, issue_id):
11051106
issue = Issue.issue_objects.only("sequence_id", "project__identifier").get(
@@ -1115,14 +1116,12 @@ def get(self, request, slug, project_id, issue_id):
11151116

11161117

11171118
class IssueDetailIdentifierEndpoint(BaseAPIView):
1118-
11191119
def strict_str_to_int(self, s):
1120-
if not s.isdigit() and not (s.startswith('-') and s[1:].isdigit()):
1120+
if not s.isdigit() and not (s.startswith("-") and s[1:].isdigit()):
11211121
raise ValueError("Invalid integer string")
11221122
return int(s)
11231123

11241124
def get(self, request, slug, project_identifier, issue_identifier):
1125-
11261125
# Check if the issue identifier is a valid integer
11271126
try:
11281127
issue_identifier = self.strict_str_to_int(issue_identifier)
@@ -1134,8 +1133,7 @@ def get(self, request, slug, project_identifier, issue_identifier):
11341133

11351134
# Fetch the project
11361135
project = Project.objects.get(
1137-
identifier__iexact=project_identifier,
1138-
workspace__slug=slug,
1136+
identifier__iexact=project_identifier, workspace__slug=slug
11391137
)
11401138

11411139
# Check if the user is a member of the project
@@ -1237,8 +1235,8 @@ def get(self, request, slug, project_identifier, issue_identifier):
12371235
.annotate(
12381236
is_subscribed=Exists(
12391237
IssueSubscriber.objects.filter(
1240-
workspace__slug=slug,
1241-
project_id=project.id,
1238+
workspace__slug=slug,
1239+
project_id=project.id,
12421240
issue__sequence_id=issue_identifier,
12431241
subscriber=request.user,
12441242
)

apiserver/plane/space/views/intake.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
# Module imports
1414
from .base import BaseViewSet
15-
from plane.db.models import IntakeIssue, Issue, State, IssueLink, FileAsset, DeployBoard
15+
from plane.db.models import IntakeIssue, Issue, IssueLink, FileAsset, DeployBoard
1616
from plane.app.serializers import (
1717
IssueSerializer,
1818
IntakeIssueSerializer,
@@ -202,7 +202,12 @@ def partial_update(self, request, anchor, intake_id, pk):
202202
"description": issue_data.get("description", issue.description),
203203
}
204204

205-
issue_serializer = IssueCreateSerializer(issue, data=issue_data, partial=True)
205+
issue_serializer = IssueCreateSerializer(
206+
issue,
207+
data=issue_data,
208+
partial=True,
209+
context={"project_id": project_deploy_board.project_id},
210+
)
206211

207212
if issue_serializer.is_valid():
208213
current_instance = issue

0 commit comments

Comments
 (0)