ФУНКЦИИ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: ручное назначение Voice Tasker

This commit is contained in:
DCCONSTRUCTIONS
2026-04-28 11:04:38 +03:00
parent 9243924f78
commit 02d79da6f9
8 changed files with 488 additions and 45 deletions
@@ -4,7 +4,7 @@
from rest_framework import serializers
from plane.db.models import Project, WorkspaceAICredential, WorkspaceAISettings
from plane.db.models import Project, WorkspaceAICredential, WorkspaceAISettings, WorkspaceMember
from plane.license.utils.encryption import encrypt_data
from .base import BaseSerializer
@@ -12,6 +12,8 @@ from .base import BaseSerializer
class WorkspaceAISettingsSerializer(BaseSerializer):
default_project_id = serializers.UUIDField(required=False, allow_null=True)
enabled_project_ids = serializers.ListField(child=serializers.UUIDField(), required=False, write_only=True)
enabled_member_ids = serializers.ListField(child=serializers.UUIDField(), required=False, write_only=True)
openai_api_key = serializers.CharField(required=False, allow_blank=True, write_only=True, trim_whitespace=False)
credential = serializers.SerializerMethodField(read_only=True)
@@ -26,6 +28,8 @@ class WorkspaceAISettingsSerializer(BaseSerializer):
"structuring_model",
"default_project_id",
"access_mode",
"enabled_project_ids",
"enabled_member_ids",
"max_audio_duration_seconds",
"per_user_hourly_limit",
"workspace_hourly_limit",
@@ -45,6 +49,12 @@ class WorkspaceAISettingsSerializer(BaseSerializer):
"updated_at": credential.updated_at if credential else None,
}
def to_representation(self, instance):
data = super().to_representation(instance)
data["enabled_project_ids"] = [str(project_id) for project_id in instance.enabled_projects.values_list("id", flat=True)]
data["enabled_member_ids"] = [str(member_id) for member_id in instance.enabled_members.values_list("id", flat=True)]
return data
def validate_default_project_id(self, value):
if value is None:
return None
@@ -54,6 +64,32 @@ class WorkspaceAISettingsSerializer(BaseSerializer):
raise serializers.ValidationError("Default project must belong to this workspace.")
return value
def validate_enabled_project_ids(self, value):
workspace = self.context["workspace"]
project_ids = list(dict.fromkeys(value))
existing_ids = set(
Project.objects.filter(workspace=workspace, id__in=project_ids, archived_at__isnull=True).values_list(
"id", flat=True
)
)
if len(existing_ids) != len(project_ids):
raise serializers.ValidationError("All selected projects must belong to this workspace.")
return project_ids
def validate_enabled_member_ids(self, value):
workspace = self.context["workspace"]
member_ids = list(dict.fromkeys(value))
existing_ids = set(
WorkspaceMember.objects.filter(
workspace=workspace,
member_id__in=member_ids,
is_active=True,
).values_list("member_id", flat=True)
)
if len(existing_ids) != len(member_ids):
raise serializers.ValidationError("All selected members must be active workspace members.")
return member_ids
def validate_max_audio_duration_seconds(self, value):
if value < 10 or value > 600:
raise serializers.ValidationError("Max audio duration must be between 10 and 600 seconds.")
@@ -72,6 +108,8 @@ class WorkspaceAISettingsSerializer(BaseSerializer):
def update(self, instance, validated_data):
api_key = validated_data.pop("openai_api_key", None)
default_project_id = validated_data.pop("default_project_id", serializers.empty)
enabled_project_ids = validated_data.pop("enabled_project_ids", serializers.empty)
enabled_member_ids = validated_data.pop("enabled_member_ids", serializers.empty)
if default_project_id is not serializers.empty:
instance.default_project_id = default_project_id
@@ -81,6 +119,12 @@ class WorkspaceAISettingsSerializer(BaseSerializer):
instance.save()
if enabled_project_ids is not serializers.empty:
instance.enabled_projects.set(enabled_project_ids)
if enabled_member_ids is not serializers.empty:
instance.enabled_members.set(enabled_member_ids)
if api_key:
cleaned_api_key = api_key.strip()
credential, _ = WorkspaceAICredential.objects.get_or_create(