Corp/backend/api/v1/feed/serializers.py
Игорь Надеин 34ddc5588f feat(comments): добавлен флаг is_post_author в API
- Добавлено поле is_post_author в CommentSerializer
- Сервер теперь явно указывает, является ли автор комментария автором поста
- Фронтенд использует этот флаг (с fallback на ручное сравнение)
- Добавлена детальная отладка для диагностики проблемы
- Это устраняет проблему с неправильным определением автора
2025-11-29 16:15:39 +03:00

211 lines
7.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# backend/api/v1/feed/serializers.py
from __future__ import annotations
from typing import Any, Dict, Optional
from django.contrib.auth import get_user_model
from rest_framework import serializers
from feed.constants import TYPE_COMPANY, TYPE_DEPARTMENT, TYPE_EMPLOYEE
from feed.models import Comment, Post, PostLike
from ..serializers import Base64ImageField
Employee = get_user_model()
class AuthorMiniSerializer(serializers.ModelSerializer):
full_name = serializers.SerializerMethodField()
avatar = Base64ImageField(read_only=True)
class Meta:
model = Employee
fields = ["id", "first_name", "last_name", "full_name", "avatar"]
def get_full_name(self, obj):
fn = (obj.first_name or "").strip()
ln = (obj.last_name or "").strip()
nm = f"{fn} {ln}".strip()
return nm
class CommentMiniSerializer(serializers.ModelSerializer):
author = AuthorMiniSerializer(read_only=True)
created_at_display = serializers.DateTimeField(
source="created_at", format="%d.%m.%Y %H:%M", read_only=True
)
class Meta:
model = Comment
fields = ["id", "text", "created_at", "created_at_display", "author"]
class PostListSerializer(serializers.ModelSerializer):
author_id = serializers.IntegerField(read_only=True)
author = AuthorMiniSerializer(read_only=True)
# удoбные представления дат
created_at_display = serializers.DateTimeField(
source="created_at", format="%d.%m.%Y %H:%M", read_only=True
)
# ожидания фронта
is_liked = serializers.BooleanField(read_only=True, default=False)
comments_count = serializers.IntegerField(read_only=True, default=0)
# для ссылок на отдел
department_id = serializers.IntegerField(read_only=True)
last_comment = serializers.SerializerMethodField()
class Meta:
model = Post
fields = [
"id",
"type",
"department",
"department_id",
"title",
"body",
"image",
"attachment",
"created_at",
"created_at_display",
"pinned",
"likes_count",
"comments_count",
"author_id",
"author",
"is_liked",
"last_comment",
]
read_only_fields = (
"created_at",
"created_at_display",
"pinned",
"likes_count",
"comments_count",
"author_id",
"author",
"department_id",
"is_liked",
)
def get_last_comment(self, obj):
# Берём готовую мапу из контекста, собранную во viewset.list()
lc_map = self.context.get("last_comments_map") or {}
lc = None
lc_id = getattr(obj, "last_comment_id", None)
if lc_id:
lc = lc_map.get(lc_id)
if not lc:
return None
return CommentMiniSerializer(lc, context=self.context).data
class PostSerializer(PostListSerializer):
"""Сериализатор для деталей поста с комментариями"""
comments = serializers.SerializerMethodField()
user_has_liked = serializers.SerializerMethodField()
class Meta(PostListSerializer.Meta):
fields = PostListSerializer.Meta.fields + [
"comments",
"user_has_liked"
]
def get_comments(self, obj):
"""Возвращает список комментариев к посту"""
comments = obj.comments.select_related("author").order_by(
"created_at"
)
return CommentSerializer(
comments, many=True, context=self.context
).data
def get_user_has_liked(self, obj):
"""Проверяет, лайкнул ли текущий пользователь этот пост"""
request = self.context.get("request")
if request and request.user and request.user.is_authenticated:
return PostLike.objects.filter(
post=obj, user=request.user
).exists()
return False
def validate(self, attrs):
# значения с учётом partial
t = attrs.get("type", getattr(self.instance, "type", None))
dept = attrs.get("department", getattr(self.instance, "department", None))
# личные посты запрещены
if t == TYPE_EMPLOYEE:
raise serializers.ValidationError(
{"type": "Публикация на личной странице запрещена."}
)
# связка type/department
if t == TYPE_DEPARTMENT and not dept:
raise serializers.ValidationError(
{"department": "Нужно указать отдел для новостей отдела."}
)
if t != TYPE_DEPARTMENT and dept is not None:
raise serializers.ValidationError(
{"department": "Для этого типа публикаций отдел указывать нельзя."}
)
return attrs
class CommentSerializer(serializers.ModelSerializer):
post_id = serializers.IntegerField(read_only=True)
author_id = serializers.IntegerField(read_only=True)
author = AuthorMiniSerializer(read_only=True)
image = serializers.FileField(allow_null=True, required=False)
attachment = serializers.FileField(allow_null=True, required=False)
created_at_display = serializers.DateTimeField(
source="created_at", format="%d.%m.%Y %H:%M", read_only=True
)
is_post_author = serializers.SerializerMethodField()
class Meta:
model = Comment
fields = [
"id",
"post",
"post_id",
"author_id",
"author",
"text",
"image",
"attachment",
"created_at",
"created_at_display",
"is_post_author",
]
extra_kwargs = {
"post": {"write_only": True},
"text": {"required": False, "allow_blank": True},
}
def get_is_post_author(self, obj):
"""Проверяет, является ли автор комментария автором поста"""
if not obj.author or not obj.post or not obj.post.author:
return False
return obj.author.id == obj.post.author.id
def validate(self, attrs):
text = (attrs.get("text") or "").strip()
if not (text or attrs.get("image") or attrs.get("attachment")):
raise serializers.ValidationError(
{"text": "Нужно указать текст, изображение или файл."}
)
return attrs
def create(self, validated_data):
# author выставляется во view
instance = Comment(**validated_data)
instance.save(skip_validation=True)
return instance
def update(self, instance, validated_data):
for k, v in validated_data.items():
setattr(instance, k, v)
instance.save(skip_validation=True)
return instance