185 lines
7.3 KiB
Python

"""Read representation for documents."""
from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers
from documents.models import (
Document,
DocumentAcknowledgement,
DocumentDisplayState,
)
from ...employees.serializers import EmployeeBriefSerializer
from ..fields import FilerFileField as FilerFileSerializerField
from .common import DepartmentBriefSerializer, FolderBriefSerializer
from .tags import DocumentTagSerializer
class DocumentReadSerializer(serializers.ModelSerializer):
"""Сериализатор для чтения документа.
Включает список получателей и флаг, ознакомился ли текущий пользователь.
"""
created_by = EmployeeBriefSerializer(read_only=True)
uploaded_by = EmployeeBriefSerializer(read_only=True)
modified_by = EmployeeBriefSerializer(read_only=True)
recipients = EmployeeBriefSerializer(many=True, read_only=True)
departments = DepartmentBriefSerializer(many=True, read_only=True)
acknowledgement_recipients = EmployeeBriefSerializer(many=True, read_only=True)
acknowledgement_departments = DepartmentBriefSerializer(many=True, read_only=True)
folder = FolderBriefSerializer(read_only=True)
folder_path = serializers.CharField(read_only=True)
tags = DocumentTagSerializer(many=True, read_only=True)
created_at = serializers.DateTimeField(read_only=True)
file_url = FilerFileSerializerField(source="file", read_only=True)
file_name = serializers.CharField(
source="file.name", read_only=True, allow_null=True
)
file_size = serializers.IntegerField(
source="file.size", read_only=True, allow_null=True
)
is_acknowledged = serializers.SerializerMethodField()
is_maximally_hidden = serializers.SerializerMethodField()
acknowledgement_required_for_user = serializers.SerializerMethodField()
acknowledged_count = serializers.SerializerMethodField()
acknowledgement_total = serializers.SerializerMethodField()
comments_count = serializers.SerializerMethodField()
linked_tasks = serializers.SerializerMethodField()
class Meta:
model = Document
fields = (
"id",
"title",
"description",
"extracted_text", # Для полнотекстового поиска
"folder", # Папка документа
"folder_path", # Полный путь папки
"tags", # Теги
"created_by", # Создатель документа
"created_at", # Дата создания
"uploaded_by",
"uploaded_at",
"modified_by",
"modified_at",
"sent_to_all",
"is_regulation",
"acknowledgement_required", # Требуется ли ознакомление
"acknowledgement_for_all",
"acknowledgement_required_for_user",
"acknowledged_count",
"acknowledgement_total",
"comments_count",
"departments",
"recipients",
"acknowledgement_departments",
"acknowledgement_recipients",
"file_url",
"file_name",
"file_size",
"is_acknowledged",
"is_maximally_hidden",
"linked_tasks",
)
def get_is_acknowledged(self, obj: Document) -> bool:
"""Возвращает флаг ознакомления текущего пользователя.
Args:
obj (Document): Документ.
Returns:
bool: True, если текущий пользователь уже ознакомился.
"""
annotated = getattr(obj, "_is_acknowledged", None)
if annotated is not None:
return bool(annotated)
request = self.context.get("request")
if not request or not request.user.is_authenticated:
return False
return DocumentAcknowledgement.objects.filter(
document=obj, user=request.user
).exists()
def get_is_maximally_hidden(self, obj: Document) -> bool:
"""Максимально ли скрыта карточка для текущего пользователя."""
annotated = getattr(obj, "_is_maximally_hidden", None)
if annotated is not None:
return bool(annotated)
request = self.context.get("request")
if not request or not request.user.is_authenticated:
return False
return DocumentDisplayState.objects.filter(
document=obj,
user=request.user,
is_maximally_hidden=True,
).exists()
def get_acknowledgement_required_for_user(self, obj: Document) -> bool:
"""Нужно ли текущему сотруднику подтверждать ознакомление."""
request = self.context.get("request")
if not request or not request.user.is_authenticated:
return False
audience_ids = getattr(obj, "_acknowledgement_user_ids", None)
if audience_ids is not None:
return request.user.pk in audience_ids
from documents.audience import user_requires_document_acknowledgement
return user_requires_document_acknowledgement(obj, request.user)
def get_acknowledged_count(self, obj: Document) -> int:
"""Количество сотрудников из аудитории, уже ознакомившихся."""
attached = getattr(obj, "_acknowledged_count", None)
if attached is not None:
return int(attached)
from documents.audience import document_acknowledgement_audience
audience = document_acknowledgement_audience(obj)
return obj.acknowledgements.filter(user__in=audience).count()
def get_acknowledgement_total(self, obj: Document) -> int:
"""Размер аудитории обязательного ознакомления."""
attached = getattr(obj, "_acknowledgement_total", None)
if attached is not None:
return int(attached)
from documents.audience import document_acknowledgement_audience
return document_acknowledgement_audience(obj).count()
def get_comments_count(self, obj: Document) -> int:
"""Количество неудалённых комментариев документа."""
attached = getattr(obj, "_comments_count", None)
if attached is not None:
return int(attached)
from communications.comments_helpers import get_comment_count
return get_comment_count(obj)
@extend_schema_field(serializers.ListField(child=serializers.DictField()))
def get_linked_tasks(self, obj: Document) -> list[dict]:
prefetched = getattr(obj, "_linked_task_payloads", None)
if prefetched is not None:
return prefetched
request = self.context.get("request")
user = getattr(request, "user", None)
if not user or not getattr(user, "is_authenticated", False):
return []
from tasks.models import TaskLinkedObjectKind
from tasks.presentation import linked_task_badges_for_object
return linked_task_badges_for_object(
obj=obj,
kind=TaskLinkedObjectKind.DOCUMENT,
user=user,
)