This commit is contained in:
21
CHANGELOG.md
21
CHANGELOG.md
@@ -1,5 +1,26 @@
|
||||
# Changelog
|
||||
|
||||
## [0.9.10] - 2025-01-23
|
||||
|
||||
### 🐛 Fixed
|
||||
- **Исправлена критическая ошибка с уведомлениями**: Устранена ошибка `null value in column "kind" of relation "notification" violates not-null constraint`
|
||||
- **Исправлен возвращаемый формат publish_draft**: Теперь возвращается `{"draft": draft_dict}` вместо `{"shout": shout}` для соответствия GraphQL схеме
|
||||
- **Фронтенд получает корректные данные**: При публикации черновика фронтенд теперь получает ожидаемое поле `draft` вместо `null`
|
||||
|
||||
### 🏗️ Changed
|
||||
- **Обновлена функция save_notification**: Добавлено обязательное поле `kind` для создания уведомлений
|
||||
- **Исправлена типизация**: Поле `kind` теперь корректно преобразуется из `action` в `NotificationAction` enum
|
||||
- **Убрано неиспользуемое значение PUBLISHED**: Из enum `NotificationAction` убрано значение, которое не использовалось
|
||||
|
||||
### 📦 Added
|
||||
- **Добавлен fallback для нестандартных действий**: Если `action` не соответствует enum, используется `NotificationAction.CREATE`
|
||||
- **Созданы тесты для уведомлений**: Добавлены тесты проверки корректного создания уведомлений
|
||||
- **Созданы тесты для publish_draft**: Добавлены тесты проверки правильного возвращаемого формата
|
||||
|
||||
### 🧪 Tests
|
||||
- **test_notification_fix.py**: Тесты для проверки создания уведомлений с валидными действиями
|
||||
- **test_draft_publish_fix.py**: Тесты для проверки возвращаемого формата в `publish_draft`
|
||||
|
||||
## [0.9.9] - 2025-08-21
|
||||
|
||||
### 🐛 Fixed
|
||||
|
||||
@@ -502,7 +502,11 @@ async def publish_draft(_: None, info: GraphQLResolveInfo, draft_id: int) -> dic
|
||||
logger.info(f"Successfully published shout #{shout.id} from draft #{draft_id}")
|
||||
logger.debug(f"Shout data: {shout.dict()}")
|
||||
|
||||
return {"shout": shout}
|
||||
# Возвращаем обновленный черновик с информацией о shout
|
||||
draft_dict = draft.dict()
|
||||
draft_dict["shout"] = {"id": shout.id, "slug": shout.slug, "published_at": shout.published_at}
|
||||
|
||||
return {"draft": draft_dict}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to publish draft {draft_id}: {e}", exc_info=True)
|
||||
|
||||
@@ -74,3 +74,75 @@ class TestDraftPublishFix:
|
||||
|
||||
# Assert
|
||||
assert not hasattr(shout, 'draft')
|
||||
|
||||
"""
|
||||
Тест для проверки исправления возвращаемого значения в publish_draft.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import patch, MagicMock, AsyncMock
|
||||
|
||||
from resolvers.draft import publish_draft
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_publish_draft_returns_draft():
|
||||
"""Тест что publish_draft возвращает draft в правильном формате"""
|
||||
# Мокаем контекст
|
||||
mock_info = MagicMock()
|
||||
mock_info.context = {"author": {"id": 1}}
|
||||
|
||||
# Мокаем session
|
||||
mock_session = MagicMock()
|
||||
mock_session_instance = MagicMock()
|
||||
mock_session.return_value.__enter__.return_value = mock_session_instance
|
||||
|
||||
# Мокаем draft
|
||||
mock_draft = MagicMock()
|
||||
mock_draft.id = 1
|
||||
mock_draft.body = "<p>Test content</p>"
|
||||
mock_draft.shout = None
|
||||
mock_draft.authors = []
|
||||
mock_draft.topics = []
|
||||
mock_draft.dict.return_value = {"id": 1, "title": "Test Draft"}
|
||||
|
||||
# Мокаем shout
|
||||
mock_shout = MagicMock()
|
||||
mock_shout.id = 100
|
||||
mock_shout.slug = "test-shout"
|
||||
mock_shout.published_at = 1234567890
|
||||
mock_shout.dict.return_value = {"id": 100, "slug": "test-shout"}
|
||||
|
||||
# Настраиваем моки
|
||||
mock_session_instance.query.return_value.options.return_value.where.return_value.first.side_effect = [
|
||||
mock_draft, # Первый вызов для draft
|
||||
None, # Второй вызов для существующего shout
|
||||
]
|
||||
|
||||
# Мокаем create_shout_from_draft
|
||||
with patch('resolvers.draft.create_shout_from_draft', return_value=mock_shout):
|
||||
with patch('resolvers.draft.validate_html_content', return_value=(True, None)):
|
||||
with patch('resolvers.draft.invalidate_shouts_cache', new_callable=AsyncMock):
|
||||
with patch('resolvers.draft.invalidate_shout_related_cache', new_callable=AsyncMock):
|
||||
with patch('resolvers.draft.notify_shout', new_callable=AsyncMock):
|
||||
with patch('resolvers.draft.search_service.index'):
|
||||
with patch('resolvers.draft.local_session', mock_session):
|
||||
# Вызываем функцию
|
||||
result = await publish_draft(None, mock_info, 1)
|
||||
|
||||
# Проверяем результат
|
||||
assert "draft" in result
|
||||
assert "error" not in result
|
||||
|
||||
draft_data = result["draft"]
|
||||
assert draft_data["id"] == 1
|
||||
assert "shout" in draft_data
|
||||
|
||||
shout_data = draft_data["shout"]
|
||||
assert shout_data["id"] == 100
|
||||
assert shout_data["slug"] == "test-shout"
|
||||
assert shout_data["published_at"] == 1234567890
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__])
|
||||
|
||||
Reference in New Issue
Block a user