ФУНКЦИИ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: source-side редактирование открытого внешнего запроса и перестройка маршрутизации
This commit is contained in:
@@ -57,6 +57,7 @@ from .external_contours import (
|
||||
ExternalContourRequestCreateSerializer,
|
||||
ExternalContourRequestDecisionSerializer,
|
||||
ExternalContourRequestReplySerializer,
|
||||
ExternalContourRequestUpdateSerializer,
|
||||
ExternalContourRequestSerializer,
|
||||
ExternalContourTargetOptionsSerializer,
|
||||
ExternalContourTargetProjectSerializer,
|
||||
|
||||
@@ -41,6 +41,22 @@ class ExternalContourRequestReplySerializer(serializers.Serializer):
|
||||
comment = serializers.CharField()
|
||||
|
||||
|
||||
class ExternalContourRequestUpdateSerializer(serializers.Serializer):
|
||||
name = serializers.CharField(max_length=255, required=False)
|
||||
description_html = serializers.CharField(required=False, allow_blank=True, allow_null=True)
|
||||
|
||||
def validate(self, data):
|
||||
if not data:
|
||||
raise serializers.ValidationError("At least one field must be provided")
|
||||
|
||||
if "name" in data:
|
||||
data["name"] = data["name"].strip()
|
||||
if not data["name"]:
|
||||
raise serializers.ValidationError({"name": "Title is required"})
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class ExternalContourTargetProjectSerializer(BaseSerializer):
|
||||
inbox_view = serializers.BooleanField(read_only=True, source="intake_view")
|
||||
|
||||
@@ -257,6 +273,11 @@ class ExternalContourRequestSerializer(BaseSerializer):
|
||||
return ExternalContourMirroredCommentSerializer(comments, many=True).data
|
||||
|
||||
def get_source_project_name(self, obj):
|
||||
source_project_id = obj.extra.get("source_project_id")
|
||||
if source_project_id:
|
||||
live_name = Project.objects.filter(pk=source_project_id).values_list("name", flat=True).first()
|
||||
if live_name:
|
||||
return live_name
|
||||
return obj.extra.get("source_project_name")
|
||||
|
||||
def get_source_decision(self, obj):
|
||||
|
||||
@@ -33,7 +33,7 @@ urlpatterns = [
|
||||
),
|
||||
path(
|
||||
"workspaces/<str:slug>/projects/<uuid:project_id>/external-contours/<uuid:request_id>/",
|
||||
ExternalContourDetailEndpoint.as_view(http_method_names=["get"]),
|
||||
ExternalContourDetailEndpoint.as_view(http_method_names=["get", "patch"]),
|
||||
name="external-contour-detail",
|
||||
),
|
||||
path(
|
||||
|
||||
@@ -14,6 +14,7 @@ from plane.api.serializers import (
|
||||
ExternalContourRequestCreateSerializer,
|
||||
ExternalContourRequestDecisionSerializer,
|
||||
ExternalContourRequestReplySerializer,
|
||||
ExternalContourRequestUpdateSerializer,
|
||||
ExternalContourRequestSerializer,
|
||||
ExternalContourTargetOptionsSerializer,
|
||||
ExternalContourTargetProjectSerializer,
|
||||
@@ -304,6 +305,55 @@ class ExternalContourDetailEndpoint(BaseAPIView):
|
||||
)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
def patch(self, request, slug, project_id, request_id):
|
||||
contour_request = get_object_or_404(self.get_queryset())
|
||||
issue = contour_request.issue
|
||||
|
||||
if not issue:
|
||||
return Response({"error": "Target issue was not found"}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
requested_by_id = contour_request.extra.get("requested_by_id") or (
|
||||
str(issue.created_by_id) if issue.created_by_id else None
|
||||
)
|
||||
if str(request.user.id) != str(requested_by_id):
|
||||
return Response({"error": "Only the sender can edit this request"}, status=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
if issue.state and issue.state.group in [StateGroup.COMPLETED.value, StateGroup.CANCELLED.value]:
|
||||
return Response(
|
||||
{"error": "Only open external contour requests can be edited"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
serializer = ExternalContourRequestUpdateSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
issue_serializer = IssueCreateSerializer(
|
||||
issue,
|
||||
data=serializer.validated_data,
|
||||
partial=True,
|
||||
context={
|
||||
"project_id": str(issue.project_id),
|
||||
"workspace_id": str(issue.workspace_id),
|
||||
},
|
||||
)
|
||||
issue_serializer.is_valid(raise_exception=True)
|
||||
issue_serializer.save()
|
||||
|
||||
contour_request.updated_at = timezone.now()
|
||||
contour_request.save(update_fields=["updated_at"])
|
||||
contour_request.refresh_from_db()
|
||||
|
||||
response_serializer = ExternalContourRequestSerializer(
|
||||
contour_request,
|
||||
context={
|
||||
"include_mirror_data": True,
|
||||
"workspace_slug": slug,
|
||||
"source_project_id": str(project_id),
|
||||
"request": request,
|
||||
},
|
||||
)
|
||||
return Response(response_serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class ExternalContourDecisionEndpoint(BaseAPIView):
|
||||
permission_classes = [ProjectLitePermission]
|
||||
|
||||
@@ -33,7 +33,7 @@ urlpatterns = [
|
||||
),
|
||||
path(
|
||||
"workspaces/<str:slug>/projects/<uuid:project_id>/external-contours/<uuid:request_id>/",
|
||||
ExternalContourDetailEndpoint.as_view(http_method_names=["get"]),
|
||||
ExternalContourDetailEndpoint.as_view(http_method_names=["get", "patch"]),
|
||||
name="external-contour-detail",
|
||||
),
|
||||
path(
|
||||
|
||||
@@ -14,6 +14,7 @@ from plane.api.serializers import (
|
||||
ExternalContourRequestCreateSerializer,
|
||||
ExternalContourRequestDecisionSerializer,
|
||||
ExternalContourRequestReplySerializer,
|
||||
ExternalContourRequestUpdateSerializer,
|
||||
ExternalContourRequestSerializer,
|
||||
ExternalContourTargetOptionsSerializer,
|
||||
ExternalContourTargetProjectSerializer,
|
||||
@@ -304,6 +305,55 @@ class ExternalContourDetailEndpoint(BaseAPIView):
|
||||
)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
def patch(self, request, slug, project_id, request_id):
|
||||
contour_request = get_object_or_404(self.get_queryset())
|
||||
issue = contour_request.issue
|
||||
|
||||
if not issue:
|
||||
return Response({"error": "Target issue was not found"}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
requested_by_id = contour_request.extra.get("requested_by_id") or (
|
||||
str(issue.created_by_id) if issue.created_by_id else None
|
||||
)
|
||||
if str(request.user.id) != str(requested_by_id):
|
||||
return Response({"error": "Only the sender can edit this request"}, status=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
if issue.state and issue.state.group in [StateGroup.COMPLETED.value, StateGroup.CANCELLED.value]:
|
||||
return Response(
|
||||
{"error": "Only open external contour requests can be edited"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
serializer = ExternalContourRequestUpdateSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
issue_serializer = IssueCreateSerializer(
|
||||
issue,
|
||||
data=serializer.validated_data,
|
||||
partial=True,
|
||||
context={
|
||||
"project_id": str(issue.project_id),
|
||||
"workspace_id": str(issue.workspace_id),
|
||||
},
|
||||
)
|
||||
issue_serializer.is_valid(raise_exception=True)
|
||||
issue_serializer.save()
|
||||
|
||||
contour_request.updated_at = timezone.now()
|
||||
contour_request.save(update_fields=["updated_at"])
|
||||
contour_request.refresh_from_db()
|
||||
|
||||
response_serializer = ExternalContourRequestSerializer(
|
||||
contour_request,
|
||||
context={
|
||||
"include_mirror_data": True,
|
||||
"workspace_slug": slug,
|
||||
"source_project_id": str(project_id),
|
||||
"request": request,
|
||||
},
|
||||
)
|
||||
return Response(response_serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class ExternalContourDecisionEndpoint(BaseAPIView):
|
||||
permission_classes = [ProjectLitePermission]
|
||||
|
||||
Reference in New Issue
Block a user