ФУНКЦИИ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: additive read-layer двусторонней доски внешних контуров
This commit is contained in:
@@ -54,6 +54,7 @@ from .intake import (
|
||||
IntakeIssueUpdateSerializer,
|
||||
)
|
||||
from .external_contours import (
|
||||
ExternalContourBoardItemSerializer,
|
||||
ExternalContourRequestCreateSerializer,
|
||||
ExternalContourRequestDecisionSerializer,
|
||||
ExternalContourRequestReplySerializer,
|
||||
|
||||
@@ -212,6 +212,10 @@ class ExternalContourRequestSerializer(BaseSerializer):
|
||||
return obj.extra.get("source_project_id")
|
||||
|
||||
def get_has_unread_updates(self, obj):
|
||||
annotated_value = getattr(obj, "has_unread_updates_annotated", None)
|
||||
if annotated_value is not None:
|
||||
return annotated_value
|
||||
|
||||
request = self.context.get("request")
|
||||
user = getattr(request, "user", None)
|
||||
user_id = getattr(user, "id", None)
|
||||
@@ -329,3 +333,96 @@ class ExternalContourRequestSerializer(BaseSerializer):
|
||||
if issue and issue.state and issue.state.group in ["completed", "cancelled"]:
|
||||
return "closed"
|
||||
return "open"
|
||||
|
||||
|
||||
class ExternalContourBoardItemSerializer(ExternalContourRequestSerializer):
|
||||
direction = serializers.SerializerMethodField()
|
||||
source_project = serializers.SerializerMethodField()
|
||||
target_project = serializers.SerializerMethodField()
|
||||
requested_by = serializers.SerializerMethodField()
|
||||
capabilities = serializers.SerializerMethodField()
|
||||
|
||||
class Meta(ExternalContourRequestSerializer.Meta):
|
||||
fields = ExternalContourRequestSerializer.Meta.fields + [
|
||||
"direction",
|
||||
"source_project",
|
||||
"target_project",
|
||||
"requested_by",
|
||||
"capabilities",
|
||||
]
|
||||
read_only_fields = fields
|
||||
|
||||
def _resolve_direction(self, obj):
|
||||
current_project_id = str(self.context.get("current_project_id") or "")
|
||||
source_project_id = str(obj.extra.get("source_project_id") or "")
|
||||
target_project_id = str(obj.extra.get("target_project_id") or obj.issue.project_id or "")
|
||||
|
||||
if current_project_id and current_project_id == source_project_id:
|
||||
return "outgoing"
|
||||
if current_project_id and current_project_id == target_project_id:
|
||||
return "incoming"
|
||||
return self.context.get("direction") or "outgoing"
|
||||
|
||||
def get_has_unread_updates(self, obj):
|
||||
unread_request_ids = self.context.get("unread_request_ids")
|
||||
if unread_request_ids is not None:
|
||||
return str(obj.id) in unread_request_ids
|
||||
return super().get_has_unread_updates(obj)
|
||||
|
||||
def _get_project_payload(self, project_id, fallback_name=None):
|
||||
if not project_id:
|
||||
return None
|
||||
|
||||
project = (self.context.get("project_map") or {}).get(str(project_id))
|
||||
return {
|
||||
"id": str(project_id),
|
||||
"identifier": getattr(project, "identifier", None),
|
||||
"name": getattr(project, "name", None) or fallback_name,
|
||||
"logo_props": getattr(project, "logo_props", None),
|
||||
}
|
||||
|
||||
def get_direction(self, obj):
|
||||
return self._resolve_direction(obj)
|
||||
|
||||
def get_source_project(self, obj):
|
||||
source_project_id = obj.extra.get("source_project_id")
|
||||
fallback_name = obj.extra.get("source_project_name")
|
||||
return self._get_project_payload(source_project_id, fallback_name=fallback_name)
|
||||
|
||||
def get_target_project(self, obj):
|
||||
target_project_id = obj.extra.get("target_project_id") or (str(obj.issue.project_id) if obj.issue_id else None)
|
||||
fallback_name = obj.extra.get("target_project_name") or (obj.issue.project.name if obj.issue and obj.issue.project else None)
|
||||
return self._get_project_payload(target_project_id, fallback_name=fallback_name)
|
||||
|
||||
def get_requested_by(self, obj):
|
||||
requested_by_id = obj.extra.get("requested_by_id") or (str(obj.created_by_id) if obj.created_by_id else None)
|
||||
requested_by_name = obj.extra.get("requested_by_name") or self.get_requested_by_name(obj)
|
||||
return {
|
||||
"id": requested_by_id,
|
||||
"display_name": requested_by_name,
|
||||
}
|
||||
|
||||
def get_capabilities(self, obj):
|
||||
request = self.context.get("request")
|
||||
user_id = str(getattr(getattr(request, "user", None), "id", "") or "")
|
||||
requested_by_id = str(obj.extra.get("requested_by_id") or obj.created_by_id or "")
|
||||
direction = self._resolve_direction(obj)
|
||||
issue_project_id = str(obj.issue.project_id) if obj.issue_id and obj.issue and obj.issue.project_id else ""
|
||||
member_project_ids = self.context.get("member_project_ids") or set()
|
||||
is_open_request = self.get_status(obj) == "open"
|
||||
|
||||
return {
|
||||
"can_open_detail": True,
|
||||
"can_open_target_issue": issue_project_id in member_project_ids,
|
||||
"can_edit_request": direction == "outgoing" and user_id == requested_by_id and is_open_request,
|
||||
"can_reply": direction == "outgoing" and bool(obj.issue_id),
|
||||
"can_source_decide": direction == "outgoing" and not is_open_request,
|
||||
}
|
||||
|
||||
def get_source_project_name(self, obj):
|
||||
source_project = self.get_source_project(obj)
|
||||
return source_project["name"] if source_project else None
|
||||
|
||||
def get_target_project_name(self, obj):
|
||||
target_project = self.get_target_project(obj)
|
||||
return target_project["name"] if target_project else None
|
||||
|
||||
@@ -6,6 +6,8 @@ from django.urls import path
|
||||
|
||||
from plane.app.views import (
|
||||
ExternalContourAttachmentDownloadEndpoint,
|
||||
ExternalContourBoardEndpoint,
|
||||
ExternalContourBoardItemDetailEndpoint,
|
||||
ExternalContourDetailEndpoint,
|
||||
ExternalContourDecisionEndpoint,
|
||||
ExternalContourListCreateEndpoint,
|
||||
@@ -16,6 +18,16 @@ from plane.app.views import (
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
"workspaces/<str:slug>/projects/<uuid:project_id>/external-contours/board/",
|
||||
ExternalContourBoardEndpoint.as_view(http_method_names=["get"]),
|
||||
name="external-contour-board",
|
||||
),
|
||||
path(
|
||||
"workspaces/<str:slug>/projects/<uuid:project_id>/external-contours/board-items/<uuid:request_id>/",
|
||||
ExternalContourBoardItemDetailEndpoint.as_view(http_method_names=["get"]),
|
||||
name="external-contour-board-item-detail",
|
||||
),
|
||||
path(
|
||||
"workspaces/<str:slug>/projects/<uuid:project_id>/external-contours/",
|
||||
ExternalContourListCreateEndpoint.as_view(http_method_names=["get", "post"]),
|
||||
|
||||
Reference in New Issue
Block a user