ФУНКЦИИ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: единый realtime слой Tasker

Добавлен NODE.DC realtime event stream для workspace/project/member/invite/profile событий. Обновлены frontend stores и live controller. Доработаны settings modal, member dropdown и confirm remove под NODE.DC UX.
This commit is contained in:
DCCONSTRUCTIONS
2026-05-12 17:28:40 +03:00
parent fc59481703
commit 480f85cce8
23 changed files with 993 additions and 72 deletions
@@ -10,6 +10,11 @@ from django.views import View
from django.views.decorators.csrf import csrf_exempt
from plane.authentication.views.nodedc_logout import is_internal_logout_request_authorized
from plane.app.realtime.issue_events import publish_assignee_cleanup_issue_events_on_commit
from plane.app.realtime.nodedc_events import (
publish_nodedc_user_profile_event_on_commit,
publish_nodedc_workspace_event_on_commit,
)
from plane.utils.host import base_host
from plane.db.models import (
ExternalIdentityLink,
@@ -361,6 +366,9 @@ class NodeDCInternalUserProfileSyncEndpoint(View):
with transaction.atomic():
updated_fields = sync_user_profile_from_payload(user, payload)
if updated_fields:
publish_nodedc_user_profile_event_on_commit(user, changed_fields=updated_fields)
return JsonResponse(
{
"ok": True,
@@ -434,6 +442,17 @@ class NodeDCInternalWorkspaceMembershipEnsureEndpoint(View):
profile.last_workspace_id = workspace.id
profile.save(update_fields=["last_workspace_id", "updated_at"])
publish_nodedc_workspace_event_on_commit(
workspace,
"workspace_member.created" if created else "workspace_member.updated",
payload={
"member_id": str(user.id),
"role": membership.role,
"source": "launcher",
},
extra_user_ids=[user.id],
)
return JsonResponse({"ok": True, "membership": serialize_membership(membership, created)})
@@ -475,7 +494,16 @@ class NodeDCInternalWorkspaceMembershipRemoveEndpoint(View):
}
)
project_ids = list(
ProjectMember.objects.filter(
project__workspace=workspace,
member=user,
is_active=True,
).values_list("project_id", flat=True)
)
with transaction.atomic():
publish_assignee_cleanup_issue_events_on_commit(workspace_id=workspace.id, assignee_id=user.id)
ProjectMember.objects.filter(
project__workspace=workspace,
member=user,
@@ -488,6 +516,17 @@ class NodeDCInternalWorkspaceMembershipRemoveEndpoint(View):
membership.is_active = False
membership.save(update_fields=["is_active", "updated_at"])
publish_nodedc_workspace_event_on_commit(
workspace,
"workspace_member.deleted",
payload={
"member_id": str(user.id),
"project_ids": [str(project_id) for project_id in project_ids],
"source": "launcher",
},
extra_user_ids=[user.id],
)
return JsonResponse(
{
"ok": True,
@@ -530,6 +569,19 @@ class NodeDCInternalWorkspaceInviteApproveEndpoint(View):
]
)
invited_user = User.objects.filter(email__iexact=invitation.email, is_bot=False).first()
publish_nodedc_workspace_event_on_commit(
invitation.workspace,
"workspace_invite.approved",
payload={
"invite_id": str(invitation.id),
"email": invitation.email,
"status": invitation.nodedc_approval_status,
"source": "launcher",
},
extra_user_ids=[invitation.created_by_id, getattr(invited_user, "id", None)],
)
return JsonResponse({"ok": True, "invite": serialize_workspace_invite(request, invitation)})
@@ -561,6 +613,19 @@ class NodeDCInternalWorkspaceInviteRejectEndpoint(View):
]
)
invited_user = User.objects.filter(email__iexact=invitation.email, is_bot=False).first()
publish_nodedc_workspace_event_on_commit(
invitation.workspace,
"workspace_invite.rejected",
payload={
"invite_id": str(invitation.id),
"email": invitation.email,
"status": invitation.nodedc_approval_status,
"source": "launcher",
},
extra_user_ids=[invitation.created_by_id, getattr(invited_user, "id", None)],
)
return JsonResponse({"ok": True, "invite": serialize_workspace_invite(request, invitation)})
@@ -648,6 +713,28 @@ class NodeDCInternalProjectMembershipEnsureEndpoint(View):
profile.last_workspace_id = workspace.id
profile.save(update_fields=["last_workspace_id", "updated_at"])
publish_nodedc_workspace_event_on_commit(
workspace,
"workspace_member.updated",
payload={
"member_id": str(user.id),
"role": workspace_membership.role,
"source": "launcher",
},
extra_user_ids=[user.id],
)
publish_nodedc_workspace_event_on_commit(
workspace,
"project_member.created" if created else "project_member.updated",
payload={
"project_id": str(project.id),
"member_id": str(user.id),
"role": project_member.role,
"source": "launcher",
},
extra_user_ids=[user.id],
)
return JsonResponse({"ok": True, "membership": serialize_project_membership(project_member, created)})
@@ -695,10 +782,22 @@ class NodeDCInternalProjectMembershipRemoveEndpoint(View):
}
)
publish_assignee_cleanup_issue_events_on_commit(project_id=project.id, assignee_id=user.id)
project_member.is_active = False
project_member.save(update_fields=["is_active", "updated_at"])
IssueAssignee.objects.filter(project=project, assignee=user).delete()
publish_nodedc_workspace_event_on_commit(
workspace,
"project_member.deleted",
payload={
"project_id": str(project.id),
"member_id": str(user.id),
"source": "launcher",
},
extra_user_ids=[user.id],
)
return JsonResponse(
{
"ok": True,