This commit is contained in:
parent
5024e963e3
commit
6b2ac09f74
|
@ -3,6 +3,7 @@ from operator import or_
|
||||||
|
|
||||||
import trafilatura
|
import trafilatura
|
||||||
from sqlalchemy.sql import and_
|
from sqlalchemy.sql import and_
|
||||||
|
from sqlalchemy.orm import joinedload
|
||||||
|
|
||||||
from cache.cache import (
|
from cache.cache import (
|
||||||
cache_author,
|
cache_author,
|
||||||
|
@ -17,7 +18,7 @@ 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
|
||||||
from services.db import local_session
|
from services.db import local_session
|
||||||
from services.notify import notify_shout
|
from services.notify import notify_shout, notify_draft
|
||||||
from services.schema import mutation, query
|
from services.schema import mutation, query
|
||||||
from services.search import search_service
|
from services.search import search_service
|
||||||
from utils.logger import root_logger as logger
|
from utils.logger import root_logger as logger
|
||||||
|
@ -234,6 +235,17 @@ async def delete_draft(_, info, draft_id: int):
|
||||||
@mutation.field("publish_draft")
|
@mutation.field("publish_draft")
|
||||||
@login_required
|
@login_required
|
||||||
async def publish_draft(_, info, draft_id: int):
|
async def publish_draft(_, info, draft_id: int):
|
||||||
|
"""Публикует черновик в виде публикации (shout).
|
||||||
|
|
||||||
|
Загружает связанные объекты (topics, authors) заранее, чтобы избежать ошибок
|
||||||
|
с отсоединенными объектами при сериализации.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
draft_id: ID черновика для публикации
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Опубликованная публикация и черновик или сообщение об ошибке
|
||||||
|
"""
|
||||||
user_id = info.context.get("user_id")
|
user_id = info.context.get("user_id")
|
||||||
author_dict = info.context.get("author", {})
|
author_dict = info.context.get("author", {})
|
||||||
author_id = author_dict.get("id")
|
author_id = author_dict.get("id")
|
||||||
|
@ -241,18 +253,78 @@ async def publish_draft(_, info, draft_id: int):
|
||||||
return {"error": "User ID and author ID are required"}
|
return {"error": "User ID and author ID are required"}
|
||||||
|
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
draft = session.query(Draft).filter(Draft.id == draft_id).first()
|
# Загружаем черновик со связанными объектами (topics, authors)
|
||||||
|
draft = (
|
||||||
|
session.query(Draft)
|
||||||
|
.options(
|
||||||
|
joinedload(Draft.topics),
|
||||||
|
joinedload(Draft.authors)
|
||||||
|
)
|
||||||
|
.filter(Draft.id == draft_id)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
if not draft:
|
if not draft:
|
||||||
return {"error": "Draft not found"}
|
return {"error": "Draft not found"}
|
||||||
|
|
||||||
|
# Создаем публикацию из черновика
|
||||||
shout = create_shout_from_draft(session, draft, author_id)
|
shout = create_shout_from_draft(session, draft, author_id)
|
||||||
session.add(shout)
|
session.add(shout)
|
||||||
|
|
||||||
|
# Добавляем авторов публикации
|
||||||
|
sa = ShoutAuthor(shout=shout.id, author=author_id)
|
||||||
|
session.add(sa)
|
||||||
|
|
||||||
|
# Добавляем темы публикации, если они есть
|
||||||
|
if draft.topics:
|
||||||
|
for topic in draft.topics:
|
||||||
|
st = ShoutTopic(
|
||||||
|
topic=topic.id,
|
||||||
|
shout=shout.id,
|
||||||
|
main=getattr(topic, "main", False)
|
||||||
|
)
|
||||||
|
session.add(st)
|
||||||
|
|
||||||
|
# Фиксируем изменения
|
||||||
|
session.flush()
|
||||||
|
|
||||||
|
# Отправляем уведомления
|
||||||
|
try:
|
||||||
|
# Преобразуем черновик в словарь для уведомления
|
||||||
|
draft_dict = draft.__dict__.copy()
|
||||||
|
# Удаляем служебные поля SQLAlchemy
|
||||||
|
draft_dict.pop('_sa_instance_state', None)
|
||||||
|
# Отправляем уведомление
|
||||||
|
await notify_draft(draft_dict, action="publish")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to send notification for draft {draft_id}: {e}")
|
||||||
|
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
|
# Инвалидируем кэш после публикации
|
||||||
|
try:
|
||||||
|
await invalidate_shouts_cache()
|
||||||
|
await invalidate_shout_related_cache(shout.slug)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to invalidate cache: {e}")
|
||||||
|
|
||||||
return {"shout": shout, "draft": draft}
|
return {"shout": shout, "draft": draft}
|
||||||
|
|
||||||
|
|
||||||
@mutation.field("unpublish_draft")
|
@mutation.field("unpublish_draft")
|
||||||
@login_required
|
@login_required
|
||||||
async def unpublish_draft(_, info, draft_id: int):
|
async def unpublish_draft(_, info, draft_id: int):
|
||||||
|
"""Снимает черновик с публикации.
|
||||||
|
|
||||||
|
Загружает связанные объекты заранее, чтобы избежать ошибок с отсоединенными
|
||||||
|
объектами при сериализации.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
draft_id: ID черновика
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Снятый с публикации черновик и публикация или сообщение об ошибке
|
||||||
|
"""
|
||||||
user_id = info.context.get("user_id")
|
user_id = info.context.get("user_id")
|
||||||
author_dict = info.context.get("author", {})
|
author_dict = info.context.get("author", {})
|
||||||
author_id = author_dict.get("id")
|
author_id = author_dict.get("id")
|
||||||
|
@ -260,14 +332,47 @@ async def unpublish_draft(_, info, draft_id: int):
|
||||||
return {"error": "User ID and author ID are required"}
|
return {"error": "User ID and author ID are required"}
|
||||||
|
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
draft = session.query(Draft).filter(Draft.id == draft_id).first()
|
# Загружаем черновик со связанными объектами
|
||||||
|
draft = (
|
||||||
|
session.query(Draft)
|
||||||
|
.options(
|
||||||
|
joinedload(Draft.topics),
|
||||||
|
joinedload(Draft.authors)
|
||||||
|
)
|
||||||
|
.filter(Draft.id == draft_id)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
if not draft:
|
if not draft:
|
||||||
return {"error": "Draft not found"}
|
return {"error": "Draft not found"}
|
||||||
|
|
||||||
shout = session.query(Shout).filter(Shout.draft == draft.id).first()
|
shout = session.query(Shout).filter(Shout.draft == draft.id).first()
|
||||||
if shout:
|
if shout:
|
||||||
shout.published_at = None
|
shout.published_at = None
|
||||||
|
|
||||||
|
# Отправляем уведомления
|
||||||
|
try:
|
||||||
|
# Преобразуем черновик в словарь для уведомления
|
||||||
|
draft_dict = draft.__dict__.copy()
|
||||||
|
# Удаляем служебные поля SQLAlchemy
|
||||||
|
draft_dict.pop('_sa_instance_state', None)
|
||||||
|
# Отправляем уведомление
|
||||||
|
await notify_draft(draft_dict, action="unpublish")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to send notification for draft {draft_id}: {e}")
|
||||||
|
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
|
# Инвалидируем кэш после снятия с публикации
|
||||||
|
try:
|
||||||
|
await invalidate_shouts_cache()
|
||||||
|
if shout.slug:
|
||||||
|
await invalidate_shout_related_cache(shout.slug)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to invalidate cache: {e}")
|
||||||
|
|
||||||
return {"shout": shout, "draft": draft}
|
return {"shout": shout, "draft": draft}
|
||||||
|
|
||||||
return {"error": "Failed to unpublish draft"}
|
return {"error": "Failed to unpublish draft"}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user