This commit is contained in:
@@ -1,22 +1,25 @@
|
||||
import time
|
||||
from orm.topic import Topic
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.sql import and_
|
||||
|
||||
from cache.cache import (
|
||||
cache_author, cache_by_id, cache_topic,
|
||||
invalidate_shout_related_cache, invalidate_shouts_cache
|
||||
cache_author,
|
||||
cache_by_id,
|
||||
cache_topic,
|
||||
invalidate_shout_related_cache,
|
||||
invalidate_shouts_cache,
|
||||
)
|
||||
from orm.author import Author
|
||||
from orm.draft import Draft
|
||||
from orm.shout import Shout, ShoutAuthor, ShoutTopic
|
||||
from orm.topic import Topic
|
||||
from services.auth import login_required
|
||||
from services.db import local_session
|
||||
from services.schema import mutation, query
|
||||
from utils.logger import root_logger as logger
|
||||
from services.notify import notify_shout
|
||||
from services.schema import mutation, query
|
||||
from services.search import search_service
|
||||
|
||||
from utils.logger import root_logger as logger
|
||||
|
||||
|
||||
def create_shout_from_draft(session, draft, author_id):
|
||||
@@ -59,16 +62,19 @@ async def load_drafts(_, info):
|
||||
|
||||
@mutation.field("create_draft")
|
||||
@login_required
|
||||
async def create_draft(_, info, shout_id: int = 0):
|
||||
async def create_draft(_, info, draft_input):
|
||||
user_id = info.context.get("user_id")
|
||||
author_dict = info.context.get("author", {})
|
||||
author_id = author_dict.get("id")
|
||||
draft_id = draft_input.get("id")
|
||||
|
||||
if not draft_id:
|
||||
return {"error": "Draft ID is required"}
|
||||
if not user_id or not author_id:
|
||||
return {"error": "User ID and author ID are required"}
|
||||
return {"error": "Author ID are required"}
|
||||
|
||||
with local_session() as session:
|
||||
draft = Draft(created_by=author_id)
|
||||
draft = Draft(created_by=author_id, **draft_input)
|
||||
session.add(draft)
|
||||
session.commit()
|
||||
return {"draft": draft}
|
||||
@@ -81,11 +87,14 @@ async def update_draft(_, info, draft_input):
|
||||
author_dict = info.context.get("author", {})
|
||||
author_id = author_dict.get("id")
|
||||
draft_id = draft_input.get("id")
|
||||
if not draft_id:
|
||||
return {"error": "Draft ID is required"}
|
||||
if not user_id or not author_id:
|
||||
return {"error": "User ID and author ID are required"}
|
||||
return {"error": "Author ID are required"}
|
||||
|
||||
with local_session() as session:
|
||||
draft = session.query(Draft).filter(Draft.id == draft_id).first()
|
||||
del draft_input["id"]
|
||||
Draft.update(draft, {**draft_input})
|
||||
if not draft:
|
||||
return {"error": "Draft not found"}
|
||||
@@ -129,7 +138,7 @@ async def publish_draft(_, info, draft_id: int):
|
||||
shout = create_shout_from_draft(session, draft, author_id)
|
||||
session.add(shout)
|
||||
session.commit()
|
||||
return {"shout": shout}
|
||||
return {"shout": shout, "draft": draft}
|
||||
|
||||
|
||||
@mutation.field("unpublish_draft")
|
||||
@@ -149,15 +158,15 @@ async def unpublish_draft(_, info, draft_id: int):
|
||||
if shout:
|
||||
shout.published_at = None
|
||||
session.commit()
|
||||
return {"shout": shout}
|
||||
return {"shout": shout, "draft": draft}
|
||||
return {"error": "Failed to unpublish draft"}
|
||||
|
||||
|
||||
@mutation.field("publish_shout")
|
||||
@login_required
|
||||
async def publish_shout(_, info, shout_id: int, draft=None):
|
||||
async def publish_shout(_, info, shout_id: int):
|
||||
"""Publish draft as a shout or update existing shout.
|
||||
|
||||
|
||||
Args:
|
||||
shout_id: ID существующей публикации или 0 для новой
|
||||
draft: Объект черновика (опционально)
|
||||
@@ -205,11 +214,13 @@ async def publish_shout(_, info, shout_id: int, draft=None):
|
||||
# или публикация была ранее снята с публикации
|
||||
if not was_published:
|
||||
shout.published_at = now
|
||||
|
||||
|
||||
# Обрабатываем связи с авторами
|
||||
if not session.query(ShoutAuthor).filter(
|
||||
and_(ShoutAuthor.shout == shout.id, ShoutAuthor.author == author_id)
|
||||
).first():
|
||||
if (
|
||||
not session.query(ShoutAuthor)
|
||||
.filter(and_(ShoutAuthor.shout == shout.id, ShoutAuthor.author == author_id))
|
||||
.first()
|
||||
):
|
||||
sa = ShoutAuthor(shout=shout.id, author=author_id)
|
||||
session.add(sa)
|
||||
|
||||
@@ -217,9 +228,7 @@ async def publish_shout(_, info, shout_id: int, draft=None):
|
||||
if draft.topics:
|
||||
for topic in draft.topics:
|
||||
st = ShoutTopic(
|
||||
topic=topic.id,
|
||||
shout=shout.id,
|
||||
main=topic.main if hasattr(topic, 'main') else False
|
||||
topic=topic.id, shout=shout.id, main=topic.main if hasattr(topic, "main") else False
|
||||
)
|
||||
session.add(st)
|
||||
|
||||
@@ -229,13 +238,8 @@ async def publish_shout(_, info, shout_id: int, draft=None):
|
||||
|
||||
# Инвалидируем кэш только если это новая публикация или была снята с публикации
|
||||
if not was_published:
|
||||
cache_keys = [
|
||||
"feed",
|
||||
f"author_{author_id}",
|
||||
"random_top",
|
||||
"unrated"
|
||||
]
|
||||
|
||||
cache_keys = ["feed", f"author_{author_id}", "random_top", "unrated"]
|
||||
|
||||
# Добавляем ключи для тем
|
||||
for topic in shout.topics:
|
||||
cache_keys.append(f"topic_{topic.id}")
|
||||
@@ -264,7 +268,7 @@ async def publish_shout(_, info, shout_id: int, draft=None):
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to publish shout: {e}", exc_info=True)
|
||||
if 'session' in locals():
|
||||
if "session" in locals():
|
||||
session.rollback()
|
||||
return {"error": f"Failed to publish shout: {str(e)}"}
|
||||
|
||||
@@ -299,5 +303,3 @@ async def unpublish_shout(_, info, shout_id: int):
|
||||
return {"error": "Failed to unpublish shout"}
|
||||
|
||||
return {"shout": shout}
|
||||
|
||||
|
||||
|
@@ -5,7 +5,12 @@ from sqlalchemy import and_, desc, select
|
||||
from sqlalchemy.orm import joinedload
|
||||
from sqlalchemy.sql.functions import coalesce
|
||||
|
||||
from cache.cache import cache_author, cache_topic, invalidate_shout_related_cache, invalidate_shouts_cache
|
||||
from cache.cache import (
|
||||
cache_author,
|
||||
cache_topic,
|
||||
invalidate_shout_related_cache,
|
||||
invalidate_shouts_cache,
|
||||
)
|
||||
from orm.author import Author
|
||||
from orm.draft import Draft
|
||||
from orm.shout import Shout, ShoutAuthor, ShoutTopic
|
||||
@@ -114,11 +119,11 @@ async def get_my_shout(_, info, shout_id: int):
|
||||
|
||||
logger.debug(f"got {len(shout.authors)} shout authors, created by {shout.created_by}")
|
||||
is_editor = "editor" in roles
|
||||
logger.debug(f'viewer is{'' if is_editor else ' not'} editor')
|
||||
logger.debug(f"viewer is{'' if is_editor else ' not'} editor")
|
||||
is_creator = author_id == shout.created_by
|
||||
logger.debug(f'viewer is{'' if is_creator else ' not'} creator')
|
||||
logger.debug(f"viewer is{'' if is_creator else ' not'} creator")
|
||||
is_author = bool(list(filter(lambda x: x.id == int(author_id), [x for x in shout.authors])))
|
||||
logger.debug(f'viewer is{'' if is_creator else ' not'} author')
|
||||
logger.debug(f"viewer is{'' if is_creator else ' not'} author")
|
||||
can_edit = is_editor or is_author or is_creator
|
||||
|
||||
if not can_edit:
|
||||
|
@@ -5,7 +5,12 @@ from sqlalchemy import and_, select
|
||||
from orm.author import Author, AuthorFollower
|
||||
from orm.shout import Shout, ShoutAuthor, ShoutReactionsFollower, ShoutTopic
|
||||
from orm.topic import Topic, TopicFollower
|
||||
from resolvers.reader import apply_options, get_shouts_with_links, has_field, query_with_stat
|
||||
from resolvers.reader import (
|
||||
apply_options,
|
||||
get_shouts_with_links,
|
||||
has_field,
|
||||
query_with_stat,
|
||||
)
|
||||
from services.auth import login_required
|
||||
from services.db import local_session
|
||||
from services.schema import query
|
||||
|
@@ -67,10 +67,7 @@ def add_author_stat_columns(q):
|
||||
shouts_subq = (
|
||||
select(func.count(distinct(Shout.id)))
|
||||
.select_from(ShoutAuthor)
|
||||
.join(Shout, and_(
|
||||
Shout.id == ShoutAuthor.shout,
|
||||
Shout.deleted_at.is_(None)
|
||||
))
|
||||
.join(Shout, and_(Shout.id == ShoutAuthor.shout, Shout.deleted_at.is_(None)))
|
||||
.where(ShoutAuthor.author == Author.id)
|
||||
.scalar_subquery()
|
||||
)
|
||||
@@ -85,10 +82,7 @@ def add_author_stat_columns(q):
|
||||
# Основной запрос
|
||||
q = (
|
||||
q.select_from(Author)
|
||||
.add_columns(
|
||||
shouts_subq.label("shouts_stat"),
|
||||
followers_subq.label("followers_stat")
|
||||
)
|
||||
.add_columns(shouts_subq.label("shouts_stat"), followers_subq.label("followers_stat"))
|
||||
.group_by(Author.id)
|
||||
)
|
||||
|
||||
|
@@ -66,11 +66,11 @@ async def get_topic(_, _info, slug: str):
|
||||
# Мутация для создания новой темы
|
||||
@mutation.field("create_topic")
|
||||
@login_required
|
||||
async def create_topic(_, _info, inp):
|
||||
async def create_topic(_, _info, topic_input):
|
||||
with local_session() as session:
|
||||
# TODO: проверить права пользователя на создание темы для конкретного сообщества
|
||||
# и разрешение на создание
|
||||
new_topic = Topic(**inp)
|
||||
new_topic = Topic(**topic_input)
|
||||
session.add(new_topic)
|
||||
session.commit()
|
||||
|
||||
@@ -80,14 +80,14 @@ async def create_topic(_, _info, inp):
|
||||
# Мутация для обновления темы
|
||||
@mutation.field("update_topic")
|
||||
@login_required
|
||||
async def update_topic(_, _info, inp):
|
||||
slug = inp["slug"]
|
||||
async def update_topic(_, _info, topic_input):
|
||||
slug = topic_input["slug"]
|
||||
with local_session() as session:
|
||||
topic = session.query(Topic).filter(Topic.slug == slug).first()
|
||||
if not topic:
|
||||
return {"error": "topic not found"}
|
||||
else:
|
||||
Topic.update(topic, inp)
|
||||
Topic.update(topic, topic_input)
|
||||
session.add(topic)
|
||||
session.commit()
|
||||
|
||||
|
Reference in New Issue
Block a user