Skip to content

Commit cfe3a19

Browse files
committed
fix(core): resolve Pylance type errors and fix draft persistence
Details: - Replaced string status literals with DraftStatus Enum to fix Pylance warnings. - Added user and draft creation to DB on initial generation request so drafts appear on the App Home dashboard. - Updated generate_draft_task to persist generated and failed content to the database.
1 parent 03b0366 commit cfe3a19

3 files changed

Lines changed: 68 additions & 18 deletions

File tree

backend/api/routes/feedback.py

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import json
2-
import uuid
32

43
import httpx
54
import structlog
65
from fastapi import APIRouter, Depends, HTTPException, Request, Response
6+
from sqlalchemy import select
77
from sqlalchemy.ext.asyncio import AsyncSession
88

99
from backend.config.lexicon import SLACK_UI
1010
from backend.config.settings import settings
11-
from backend.models.enums import Platform
12-
from backend.models.schemas import DraftUpdate
11+
from backend.models.db_models import User
12+
from backend.models.enums import DraftStatus, Platform
13+
from backend.models.schemas import DraftCreate, DraftUpdate
1314
from backend.repositories.draft_repository import DraftRepository
1415
from backend.workers.dependencies import get_db_session
1516
from backend.workers.tasks.generate_draft import generate_draft_task
@@ -148,6 +149,13 @@ async def slack_interactions(
148149

149150
async with httpx.AsyncClient() as client:
150151
if action_id == "action_publish_draft":
152+
# ДОДАНО: Змінюємо статус на Опубліковано
153+
if draft_id.isdigit():
154+
repo = DraftRepository(session)
155+
await repo.update(
156+
int(draft_id), DraftUpdate(status=DraftStatus.PUBLISHED)
157+
)
158+
151159
await publish_post_task.kiq(
152160
post_id=draft_id, platform=platform, content=draft_text
153161
)
@@ -210,20 +218,25 @@ async def slack_interactions(
210218
callback_id = view.get("callback_id")
211219
state_values = view.get("state", {}).get("values", {})
212220

221+
# --- СЦЕНАРІЙ 1: Генерація нового драфту ---
213222
# --- СЦЕНАРІЙ 1: Генерація нового драфту ---
214223
if callback_id == "modal_generate_draft":
215-
channel_id = view.get("private_metadata") # Дістаємо збережений канал
224+
channel_id = view.get("private_metadata")
216225
topic = (
217226
state_values.get("block_topic_input", {})
218227
.get("input_topic", {})
219228
.get("value", "")
220229
.strip()
221230
)
222-
platform = (
223-
state_values.get("block_platform_select", {})
224-
.get("input_platform_select", {})
225-
.get("selected_option", {})
226-
.get("value", "telegram")
231+
232+
block_state = state_values.get("block_platform_select", {}).get(
233+
"input_platform_select", {}
234+
)
235+
selected_option = block_state.get("selected_option")
236+
platform = Platform(
237+
selected_option.get("value", "telegram")
238+
if selected_option
239+
else "telegram"
227240
)
228241

229242
logger.info(
@@ -233,16 +246,34 @@ async def slack_interactions(
233246
platform=platform,
234247
)
235248

236-
new_draft_id = str(uuid.uuid4()) # ГЕНЕРУЄМО УНІКАЛЬНИЙ ID
249+
# --- ДОДАНО: СТВОРЕННЯ КОРИСТУВАЧА ТА ДРАФТУ В БД ---
250+
# 1. Знаходимо або створюємо користувача (Slack ID)
251+
user_query = await session.execute(
252+
select(User).where(User.username == user_id)
253+
)
254+
db_user = user_query.scalar_one_or_none()
255+
if not db_user:
256+
db_user = User(username=user_id)
257+
session.add(db_user)
258+
await session.flush()
259+
260+
# 2. Створюємо драфт (статус pending)
261+
repo = DraftRepository(session)
262+
new_draft = await repo.create(
263+
DraftCreate(topic=topic, platform=platform, user_id=db_user.id)
264+
)
265+
real_draft_id = str(new_draft.id)
266+
# ---------------------------------------------------
267+
268+
# Передаємо РЕАЛЬНИЙ ID з бази замість UUID
237269
await generate_draft_task.kiq( # type: ignore[call-overload]
238270
topic=topic,
239-
platform=platform,
271+
platform=platform.value,
240272
user_id=user_id,
241273
channel_id=channel_id,
242-
draft_id=new_draft_id,
274+
draft_id=real_draft_id,
243275
)
244276

245-
# Відправляємо підтвердження в канал
246277
async with httpx.AsyncClient() as client:
247278
await client.post(
248279
"https://slack.com/api/chat.postMessage",

backend/tests/unit/test_tasks.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ async def test_generate_draft_task_success():
2121
source_url = "https://pubmed.org/123"
2222

2323
# Act: Прямий виклик функції (в обхід брокера) з ін'єкцією мока
24-
result = await generate_draft_task(
25-
topic=topic, platform=platform, source_url=source_url, generator=mock_generator
24+
result: str = await generate_draft_task(
25+
topic=topic, platform=platform, source_url=source_url, generator=mock_generator, session=AsyncMock()
2626
)
2727

2828
# Assert: Перевіряємо результат та аргументи виклику
@@ -47,7 +47,7 @@ async def test_generate_draft_task_judge_failure():
4747
# Act & Assert
4848
with pytest.raises(JudgeFailedError) as exc_info:
4949
await generate_draft_task(
50-
topic="Стрес", platform="twitter", source_url=None, generator=mock_generator
50+
topic="Стрес", platform="twitter", source_url=None, generator=mock_generator, session=AsyncMock()
5151
)
5252

5353
assert exc_info.value.topic == "Стрес"
@@ -73,4 +73,5 @@ async def test_generate_draft_task_unexpected_error():
7373
platform="threads",
7474
source_url=None,
7575
generator=mock_generator,
76+
session=AsyncMock(),
7677
)

backend/workers/tasks/generate_draft.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
from typing import Annotated
22

33
import structlog
4+
from sqlalchemy.ext.asyncio import AsyncSession
45
from taskiq import TaskiqDepends
56

7+
from backend.models.enums import DraftStatus
8+
from backend.models.schemas import DraftUpdate
9+
from backend.repositories.draft_repository import DraftRepository
610
from backend.services.content_generator import ContentGenerator, JudgeFailedError
711
from backend.workers.broker import broker
812
from backend.workers.callbacks import notify_slack_on_complete, notify_slack_on_failure
9-
from backend.workers.dependencies import get_content_generator
13+
from backend.workers.dependencies import get_content_generator, get_db_session
1014

1115
logger = structlog.get_logger()
1216

@@ -17,6 +21,7 @@ async def generate_draft_task(
1721
topic: str,
1822
platform: str,
1923
generator: Annotated[ContentGenerator, TaskiqDepends(get_content_generator)],
24+
session: Annotated[AsyncSession, TaskiqDepends(get_db_session)],
2025
source_url: str | None = None,
2126
user_id: str | None = None,
2227
channel_id: str | None = None,
@@ -42,7 +47,12 @@ async def generate_draft_task(
4247
logger.info(
4348
"background_task_success", task="generate_medical_draft", topic=topic
4449
)
45-
50+
# --- ДОДАНО: ЗБЕРЕЖЕННЯ ТЕКСТУ ТА СТАТУСУ В БД ---
51+
if draft_id.isdigit():
52+
repo = DraftRepository(session)
53+
await repo.update(
54+
int(draft_id), DraftUpdate(content=result, status=DraftStatus.GENERATED)
55+
)
4656
# ДОДАНО: Відправка готового результату у Slack
4757
if user_id and channel_id:
4858
await notify_slack_on_complete(
@@ -63,6 +73,14 @@ async def generate_draft_task(
6373
topic=e.topic,
6474
attempts=e.attempts,
6575
)
76+
# --- ДОДАНО: ЗБЕРЕЖЕННЯ "БРУДНОГО" ТЕКСТУ ---
77+
if draft_id.isdigit():
78+
repo = DraftRepository(session)
79+
await repo.update(
80+
int(draft_id), DraftUpdate(content=e.draft, status=DraftStatus.FAILED)
81+
)
82+
83+
# ---------------------------------------------
6684
# ВІДДАЄМО ДРАФТ З КНОПКАМИ, АЛЕ З АЛЕРТОМ (is_valid=False)
6785
if user_id and channel_id:
6886
await notify_slack_on_complete(

0 commit comments

Comments
 (0)