This commit is contained in:
parent
6d9513f1b2
commit
b66e347c91
|
@ -13,7 +13,7 @@ from cache.cache import (
|
||||||
invalidate_shouts_cache,
|
invalidate_shouts_cache,
|
||||||
)
|
)
|
||||||
from orm.author import Author
|
from orm.author import Author
|
||||||
from orm.draft import Draft
|
from orm.draft import Draft, DraftAuthor, DraftTopic
|
||||||
from orm.shout import Shout, ShoutAuthor, ShoutTopic
|
from orm.shout import Shout, ShoutAuthor, ShoutTopic
|
||||||
from orm.topic import Topic
|
from orm.topic import Topic
|
||||||
from services.auth import login_required
|
from services.auth import login_required
|
||||||
|
@ -168,7 +168,21 @@ async def update_draft(_, info, draft_id: int, draft_input):
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
draft_id: ID черновика для обновления
|
draft_id: ID черновика для обновления
|
||||||
draft_input: Данные для обновления черновика
|
draft_input: Данные для обновления черновика согласно схеме DraftInput:
|
||||||
|
- layout: String
|
||||||
|
- author_ids: [Int!]
|
||||||
|
- topic_ids: [Int!]
|
||||||
|
- main_topic_id: Int
|
||||||
|
- media: [MediaItemInput]
|
||||||
|
- lead: String
|
||||||
|
- subtitle: String
|
||||||
|
- lang: String
|
||||||
|
- seo: String
|
||||||
|
- body: String
|
||||||
|
- title: String
|
||||||
|
- slug: String
|
||||||
|
- cover: String
|
||||||
|
- cover_caption: String
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Обновленный черновик или сообщение об ошибке
|
dict: Обновленный черновик или сообщение об ошибке
|
||||||
|
@ -180,66 +194,85 @@ async def update_draft(_, info, draft_id: int, draft_input):
|
||||||
if not user_id or not author_id:
|
if not user_id or not author_id:
|
||||||
return {"error": "Author ID are required"}
|
return {"error": "Author ID are required"}
|
||||||
|
|
||||||
# Проверяем slug - он должен быть или не пустым, или не передаваться вообще
|
try:
|
||||||
if "slug" in draft_input and (draft_input["slug"] is None or draft_input["slug"] == ""):
|
|
||||||
# Если slug пустой, либо удаляем его из входных данных, либо генерируем временный уникальный
|
|
||||||
# Вариант 1: просто удаляем ключ из входных данных, чтобы оставить старое значение
|
|
||||||
del draft_input["slug"]
|
|
||||||
# Вариант 2 (если нужно обновить): генерируем временный уникальный slug
|
|
||||||
# import uuid
|
|
||||||
# draft_input["slug"] = f"draft-{uuid.uuid4().hex[:8]}"
|
|
||||||
|
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
draft = session.query(Draft).filter(Draft.id == draft_id).first()
|
draft = session.query(Draft).filter(Draft.id == draft_id).first()
|
||||||
if not draft:
|
if not draft:
|
||||||
return {"error": "Draft not found"}
|
return {"error": "Draft not found"}
|
||||||
|
|
||||||
# Generate SEO description if not provided and not already set
|
# Фильтруем входные данные, оставляя только разрешенные поля
|
||||||
if "seo" not in draft_input and not draft.seo:
|
allowed_fields = {
|
||||||
body_src = draft_input.get("body") if "body" in draft_input else draft.body
|
"layout", "author_ids", "topic_ids", "main_topic_id",
|
||||||
lead_src = draft_input.get("lead") if "lead" in draft_input else draft.lead
|
"media", "lead", "subtitle", "lang", "seo", "body",
|
||||||
|
"title", "slug", "cover", "cover_caption"
|
||||||
|
}
|
||||||
|
filtered_input = {k: v for k, v in draft_input.items() if k in allowed_fields}
|
||||||
|
|
||||||
|
# Проверяем slug
|
||||||
|
if "slug" in filtered_input and not filtered_input["slug"]:
|
||||||
|
del filtered_input["slug"]
|
||||||
|
|
||||||
|
# Обновляем связи с авторами если переданы
|
||||||
|
if "author_ids" in filtered_input:
|
||||||
|
author_ids = filtered_input.pop("author_ids")
|
||||||
|
if author_ids:
|
||||||
|
# Очищаем текущие связи
|
||||||
|
session.query(DraftAuthor).filter(DraftAuthor.shout == draft_id).delete()
|
||||||
|
# Добавляем новые связи
|
||||||
|
for aid in author_ids:
|
||||||
|
da = DraftAuthor(shout=draft_id, author=aid)
|
||||||
|
session.add(da)
|
||||||
|
|
||||||
|
# Обновляем связи с темами если переданы
|
||||||
|
if "topic_ids" in filtered_input:
|
||||||
|
topic_ids = filtered_input.pop("topic_ids")
|
||||||
|
main_topic_id = filtered_input.pop("main_topic_id", None)
|
||||||
|
if topic_ids:
|
||||||
|
# Очищаем текущие связи
|
||||||
|
session.query(DraftTopic).filter(DraftTopic.shout == draft_id).delete()
|
||||||
|
# Добавляем новые связи
|
||||||
|
for tid in topic_ids:
|
||||||
|
dt = DraftTopic(
|
||||||
|
shout=draft_id,
|
||||||
|
topic=tid,
|
||||||
|
main=(tid == main_topic_id) if main_topic_id else False
|
||||||
|
)
|
||||||
|
session.add(dt)
|
||||||
|
|
||||||
|
# Генерируем SEO если не предоставлено
|
||||||
|
if "seo" not in filtered_input and not draft.seo:
|
||||||
|
body_src = filtered_input.get("body", draft.body)
|
||||||
|
lead_src = filtered_input.get("lead", draft.lead)
|
||||||
|
|
||||||
body_text = None
|
|
||||||
if body_src:
|
|
||||||
try:
|
try:
|
||||||
# Extract text, excluding comments and tables
|
body_text = trafilatura.extract(body_src, include_comments=False, include_tables=False) if body_src else None
|
||||||
body_text = trafilatura.extract(body_src, include_comments=False, include_tables=False)
|
lead_text = trafilatura.extract(lead_src, include_comments=False, include_tables=False) if lead_src else None
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"Trafilatura failed to extract body text for draft {draft_id}: {e}")
|
|
||||||
|
|
||||||
lead_text = None
|
|
||||||
if lead_src:
|
|
||||||
try:
|
|
||||||
# Extract text from lead
|
|
||||||
lead_text = trafilatura.extract(lead_src, include_comments=False, include_tables=False)
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"Trafilatura failed to extract lead text for draft {draft_id}: {e}")
|
|
||||||
|
|
||||||
# Generate body teaser only if body_text was successfully extracted
|
|
||||||
body_teaser = generate_teaser(body_text, 300) if body_text else ""
|
body_teaser = generate_teaser(body_text, 300) if body_text else ""
|
||||||
|
filtered_input["seo"] = lead_text if lead_text else body_teaser
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Failed to generate SEO for draft {draft_id}: {e}")
|
||||||
|
|
||||||
# Prioritize lead_text for SEO, fallback to body_teaser. Ensure it's a string.
|
# Обновляем основные поля черновика
|
||||||
generated_seo = lead_text if lead_text else body_teaser
|
for key, value in filtered_input.items():
|
||||||
draft_input["seo"] = generated_seo if generated_seo else ""
|
setattr(draft, key, value)
|
||||||
|
|
||||||
# Update the draft object with new data from draft_input
|
# Обновляем метаданные
|
||||||
# Assuming Draft.update is a helper that iterates keys or similar.
|
draft.updated_at = int(time.time())
|
||||||
# A more standard SQLAlchemy approach would be:
|
draft.updated_by = author_id
|
||||||
# for key, value in draft_input.items():
|
|
||||||
# if hasattr(draft, key):
|
|
||||||
# setattr(draft, key, value)
|
|
||||||
# But we stick to the existing pattern for now.
|
|
||||||
Draft.update(draft, draft_input)
|
|
||||||
|
|
||||||
# Set updated timestamp and author
|
|
||||||
current_time = int(time.time())
|
|
||||||
draft.updated_at = current_time
|
|
||||||
draft.updated_by = author_id # Используем ID напрямую
|
|
||||||
|
|
||||||
session.commit()
|
session.commit()
|
||||||
# Invalidate cache related to this draft if necessary (consider adding)
|
|
||||||
# await invalidate_draft_cache(draft_id)
|
# Преобразуем объект в словарь для ответа
|
||||||
return {"draft": draft}
|
draft_dict = draft.dict()
|
||||||
|
draft_dict["topics"] = [topic.dict() for topic in draft.topics]
|
||||||
|
draft_dict["authors"] = [author.dict() for author in draft.authors]
|
||||||
|
|
||||||
|
return {"draft": draft_dict}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to update draft: {e}", exc_info=True)
|
||||||
|
return {"error": f"Failed to update draft: {str(e)}"}
|
||||||
|
|
||||||
|
|
||||||
@mutation.field("delete_draft")
|
@mutation.field("delete_draft")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user