diff --git a/backend/api/v1/feed/serializers.py b/backend/api/v1/feed/serializers.py index 797c3051..68e93495 100644 --- a/backend/api/v1/feed/serializers.py +++ b/backend/api/v1/feed/serializers.py @@ -161,6 +161,7 @@ class CommentSerializer(serializers.ModelSerializer): 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 @@ -175,12 +176,19 @@ class CommentSerializer(serializers.ModelSerializer): "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")): diff --git a/backend/static/js/components/postDetailModal.js b/backend/static/js/components/postDetailModal.js index b884e8eb..f6cdd2f7 100644 --- a/backend/static/js/components/postDetailModal.js +++ b/backend/static/js/components/postDetailModal.js @@ -1,16 +1,23 @@ /** * postDetailModal.js * Модуль для открытия деталей поста в модальном окне + * Полностью переработанная версия */ (function() { 'use strict'; + // Константы + const INITIAL_COMMENTS_COUNT = 10; + const DEBUG = true; + + // Состояние let modal = null; let modalElement = null; + let currentPost = null; /** - * Инициализация модального окна + * Инициализация */ function initPostDetailModal() { modalElement = document.getElementById('postDetailModal'); @@ -21,7 +28,6 @@ modal = new bootstrap.Modal(modalElement); - // Очистка при закрытии modalElement.addEventListener('hidden.bs.modal', function() { const contentDiv = document.getElementById('postDetailContent'); if (contentDiv) { @@ -33,14 +39,14 @@ `; } + currentPost = null; }); - // Добавляем обработчики на ссылки постов attachPostLinkHandlers(); } /** - * Получение CSRF токена из cookie + * Утилиты для работы с cookies */ function getCsrfToken() { const cookies = document.cookie.split(';'); @@ -53,9 +59,6 @@ return null; } - /** - * Получение JWT токена из cookie (для загрузки данных) - */ function getAccessToken() { const cookies = document.cookie.split(';'); for (let cookie of cookies) { @@ -68,197 +71,20 @@ } /** - * Загрузка деталей поста через API + * Утилиты */ - async function loadPostDetail(postId) { - const accessToken = getAccessToken(); - const headers = { - 'Accept': 'application/json' - }; - - if (accessToken) { - headers['Authorization'] = `Bearer ${accessToken}`; - } - - try { - const response = await fetch(`/api/v1/posts/${postId}/`, { - method: 'GET', - headers: headers - }); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const post = await response.json(); - renderPostDetail(post); - } catch (error) { - console.error('Ошибка загрузки поста:', error); - showError('Не удалось загрузить пост'); - } + function escapeHtml(text) { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; } - /** - * Отображение деталей поста в модальном окне - */ - function renderPostDetail(post) { - const contentDiv = document.getElementById('postDetailContent'); - - // Сохраняем ID автора для определения его комментариев - const postAuthorId = post.author?.id; - - // Формируем HTML с кнопкой закрытия - let html = ''; - html += '
'; - - // Заголовок с автором - html += '
'; - html += '
'; - if (post.author && post.author.avatar) { - html += ``; - } else { - html += ''; - } - html += '
'; - html += '
'; - html += `
${post.author?.full_name || 'Аноним'}
`; - html += ``; - html += '
'; - - // Закрепленный пост - if (post.pinned) { - html += ''; - } - html += '
'; - - // Изображение - if (post.image) { - html += `
${post.title || 'Публикация'}
`; - } - - // Тело - html += '
'; - html += `

${post.title || 'Без названия'}

`; - if (post.body) { - html += `
${formatBody(post.body)}
`; - } - html += '
'; - - // Футер с лайками и комментариями - html += ''; - - // Секция комментариев внутри карточки - html += '
'; - - if (post.comments && post.comments.length > 0) { - html += '
'; - html += '
'; - html += '
'; - html += ''; - html += '
Комментарии
'; - html += `(${post.comments.length})`; - html += '
'; - html += '
'; - post.comments.forEach(comment => { - html += renderComment(comment, postAuthorId); - }); - html += '
'; - html += '
'; - } - - // Форма добавления комментария (sticky) - html += '
'; - html += '
'; - html += '
'; - html += '
'; - - // Кнопка выбора эмодзи - html += '