This commit is contained in:
parent
670a477f9a
commit
fd6b0ce5fd
|
@ -58,7 +58,8 @@ async def get_my_shout(_, info, shout_id: int):
|
||||||
if isinstance(shout.media, str):
|
if isinstance(shout.media, str):
|
||||||
try:
|
try:
|
||||||
shout.media = json.loads(shout.media)
|
shout.media = json.loads(shout.media)
|
||||||
except:
|
except Exception as e:
|
||||||
|
logger.error(f"Error parsing shout media: {e}")
|
||||||
shout.media = []
|
shout.media = []
|
||||||
if not isinstance(shout.media, list):
|
if not isinstance(shout.media, list):
|
||||||
shout.media = [shout.media] if shout.media else []
|
shout.media = [shout.media] if shout.media else []
|
||||||
|
@ -212,89 +213,136 @@ async def create_shout(_, info, inp):
|
||||||
return {"error": error_msg}
|
return {"error": error_msg}
|
||||||
|
|
||||||
|
|
||||||
def patch_main_topic(session, main_topic, shout):
|
def patch_main_topic(session, main_topic_slug, shout):
|
||||||
|
logger.info(f"Starting patch_main_topic for shout#{shout.id} with slug '{main_topic_slug}'")
|
||||||
|
|
||||||
with session.begin():
|
with session.begin():
|
||||||
shout = session.query(Shout).options(joinedload(Shout.topics)).filter(Shout.id == shout.id).first()
|
# Получаем текущий главный топик
|
||||||
if not shout:
|
old_main = (
|
||||||
return
|
|
||||||
old_main_topic = (
|
|
||||||
session.query(ShoutTopic).filter(and_(ShoutTopic.shout == shout.id, ShoutTopic.main.is_(True))).first()
|
session.query(ShoutTopic).filter(and_(ShoutTopic.shout == shout.id, ShoutTopic.main.is_(True))).first()
|
||||||
)
|
)
|
||||||
|
if old_main:
|
||||||
|
logger.info(f"Found current main topic: {old_main.topic}")
|
||||||
|
|
||||||
main_topic = session.query(Topic).filter(Topic.slug == main_topic).first()
|
# Находим новый главный топик
|
||||||
|
main_topic = session.query(Topic).filter(Topic.slug == main_topic_slug).first()
|
||||||
|
if not main_topic:
|
||||||
|
logger.error(f"Main topic with slug '{main_topic_slug}' not found")
|
||||||
|
return
|
||||||
|
|
||||||
if main_topic:
|
logger.info(f"Found new main topic: {main_topic.id}")
|
||||||
new_main_topic = (
|
|
||||||
session.query(ShoutTopic)
|
|
||||||
.filter(and_(ShoutTopic.shout == shout.id, ShoutTopic.topic == main_topic.id))
|
|
||||||
.first()
|
|
||||||
)
|
|
||||||
|
|
||||||
if old_main_topic and new_main_topic and old_main_topic is not new_main_topic:
|
# Находим связь с новым главным топиком
|
||||||
ShoutTopic.update(old_main_topic, {"main": False})
|
new_main = (
|
||||||
session.add(old_main_topic)
|
session.query(ShoutTopic)
|
||||||
|
.filter(and_(ShoutTopic.shout == shout.id, ShoutTopic.topic == main_topic.id))
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
ShoutTopic.update(new_main_topic, {"main": True})
|
if old_main and new_main and old_main is not new_main:
|
||||||
session.add(new_main_topic)
|
logger.info("Updating main topic flags")
|
||||||
|
old_main.main = False
|
||||||
|
session.add(old_main)
|
||||||
|
|
||||||
|
new_main.main = True
|
||||||
|
session.add(new_main)
|
||||||
|
|
||||||
|
session.flush()
|
||||||
|
logger.info(f"Main topic updated for shout#{shout.id}")
|
||||||
|
|
||||||
|
|
||||||
def patch_topics(session, shout, topics_input):
|
def patch_topics(session, shout, topics_input):
|
||||||
|
logger.info(f"Starting patch_topics for shout#{shout.id}")
|
||||||
|
logger.info(f"Received topics_input: {topics_input}")
|
||||||
|
|
||||||
|
# Создаем новые топики если есть
|
||||||
new_topics_to_link = [Topic(**new_topic) for new_topic in topics_input if new_topic["id"] < 0]
|
new_topics_to_link = [Topic(**new_topic) for new_topic in topics_input if new_topic["id"] < 0]
|
||||||
if new_topics_to_link:
|
if new_topics_to_link:
|
||||||
|
logger.info(f"Creating new topics: {[t.dict() for t in new_topics_to_link]}")
|
||||||
session.add_all(new_topics_to_link)
|
session.add_all(new_topics_to_link)
|
||||||
session.commit()
|
session.flush() # Получаем ID для новых топиков
|
||||||
|
|
||||||
for new_topic_to_link in new_topics_to_link:
|
# Получаем текущие связи
|
||||||
created_unlinked_topic = ShoutTopic(shout=shout.id, topic=new_topic_to_link.id)
|
current_links = session.query(ShoutTopic).filter(ShoutTopic.shout == shout.id).all()
|
||||||
session.add(created_unlinked_topic)
|
logger.info(f"Current topic links: {[{t.topic: t.main} for t in current_links]}")
|
||||||
|
|
||||||
existing_topics_input = [topic_input for topic_input in topics_input if topic_input.get("id", 0) > 0]
|
# Удаляем старые связи
|
||||||
existing_topic_to_link_ids = [
|
if current_links:
|
||||||
existing_topic_input["id"]
|
logger.info(f"Removing old topic links for shout#{shout.id}")
|
||||||
for existing_topic_input in existing_topics_input
|
for link in current_links:
|
||||||
if existing_topic_input["id"] not in [topic.id for topic in shout.topics]
|
session.delete(link)
|
||||||
]
|
session.flush()
|
||||||
|
|
||||||
for existing_topic_to_link_id in existing_topic_to_link_ids:
|
# Создаем новые связи
|
||||||
created_unlinked_topic = ShoutTopic(shout=shout.id, topic=existing_topic_to_link_id)
|
for topic_input in topics_input:
|
||||||
session.add(created_unlinked_topic)
|
topic_id = topic_input["id"]
|
||||||
|
if topic_id < 0:
|
||||||
|
# Для новых топиков берем ID из созданных
|
||||||
|
topic = next(t for t in new_topics_to_link if t.slug == topic_input["slug"])
|
||||||
|
topic_id = topic.id
|
||||||
|
|
||||||
topic_to_unlink_ids = [
|
logger.info(f"Creating new topic link: shout#{shout.id} -> topic#{topic_id}")
|
||||||
topic.id
|
new_link = ShoutTopic(
|
||||||
for topic in shout.topics
|
shout=shout.id,
|
||||||
if topic.id not in [topic_input["id"] for topic_input in existing_topics_input]
|
topic=topic_id,
|
||||||
]
|
main=False, # main topic устанавливается отдельно через patch_main_topic
|
||||||
|
)
|
||||||
|
session.add(new_link)
|
||||||
|
|
||||||
session.query(ShoutTopic).filter(
|
try:
|
||||||
and_(ShoutTopic.shout == shout.id, ShoutTopic.topic.in_(topic_to_unlink_ids))
|
session.flush()
|
||||||
).delete(synchronize_session=False)
|
logger.info(f"Successfully updated topics for shout#{shout.id}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error flushing topic changes: {e}", exc_info=True)
|
||||||
|
raise
|
||||||
|
|
||||||
|
# Проверяем результат
|
||||||
|
new_links = session.query(ShoutTopic).filter(ShoutTopic.shout == shout.id).all()
|
||||||
|
logger.info(f"New topic links: {[{t.topic: t.main} for t in new_links]}")
|
||||||
|
|
||||||
|
|
||||||
@mutation.field("update_shout")
|
@mutation.field("update_shout")
|
||||||
@login_required
|
@login_required
|
||||||
async def update_shout(_, info, shout_id: int, shout_input=None, publish=False):
|
async def update_shout(_, info, shout_id: int, shout_input=None, publish=False):
|
||||||
|
logger.info(f"Starting update_shout with id={shout_id}, publish={publish}")
|
||||||
|
logger.debug(f"Full shout_input: {shout_input}")
|
||||||
|
|
||||||
user_id = info.context.get("user_id")
|
user_id = info.context.get("user_id")
|
||||||
roles = info.context.get("roles", [])
|
roles = info.context.get("roles", [])
|
||||||
author_dict = info.context.get("author")
|
author_dict = info.context.get("author")
|
||||||
if not author_dict:
|
if not author_dict:
|
||||||
|
logger.error("Author profile not found")
|
||||||
return {"error": "author profile was not found"}
|
return {"error": "author profile was not found"}
|
||||||
|
|
||||||
author_id = author_dict.get("id")
|
author_id = author_dict.get("id")
|
||||||
shout_input = shout_input or {}
|
shout_input = shout_input or {}
|
||||||
current_time = int(time.time())
|
current_time = int(time.time())
|
||||||
shout_id = shout_id or shout_input.get("id", shout_id)
|
shout_id = shout_id or shout_input.get("id", shout_id)
|
||||||
slug = shout_input.get("slug")
|
slug = shout_input.get("slug")
|
||||||
|
|
||||||
if not user_id:
|
if not user_id:
|
||||||
|
logger.error("Unauthorized update attempt")
|
||||||
return {"error": "unauthorized"}
|
return {"error": "unauthorized"}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
if author_id:
|
if author_id:
|
||||||
logger.info(f"author for shout#{shout_id} detected author #{author_id}")
|
logger.info(f"Processing update for shout#{shout_id} by author #{author_id}")
|
||||||
shout_by_id = session.query(Shout).filter(Shout.id == shout_id).first()
|
shout_by_id = session.query(Shout).filter(Shout.id == shout_id).first()
|
||||||
|
|
||||||
if not shout_by_id:
|
if not shout_by_id:
|
||||||
logger.error(f"shout#{shout_id} not found")
|
logger.error(f"shout#{shout_id} not found")
|
||||||
return {"error": "shout not found"}
|
return {"error": "shout not found"}
|
||||||
logger.info(f"shout#{shout_id} found")
|
|
||||||
|
logger.info(f"Found shout#{shout_id}")
|
||||||
|
|
||||||
|
# Логируем текущие топики
|
||||||
|
current_topics = (
|
||||||
|
[{"id": t.id, "slug": t.slug, "title": t.title} for t in shout_by_id.topics]
|
||||||
|
if shout_by_id.topics
|
||||||
|
else []
|
||||||
|
)
|
||||||
|
logger.info(f"Current topics for shout#{shout_id}: {current_topics}")
|
||||||
|
|
||||||
if slug != shout_by_id.slug:
|
if slug != shout_by_id.slug:
|
||||||
same_slug_shout = session.query(Shout).filter(Shout.slug == slug).first()
|
same_slug_shout = session.query(Shout).filter(Shout.slug == slug).first()
|
||||||
|
@ -307,24 +355,34 @@ async def update_shout(_, info, shout_id: int, shout_input=None, publish=False):
|
||||||
logger.info(f"shout#{shout_id} slug patched")
|
logger.info(f"shout#{shout_id} slug patched")
|
||||||
|
|
||||||
if filter(lambda x: x.id == author_id, [x for x in shout_by_id.authors]) or "editor" in roles:
|
if filter(lambda x: x.id == author_id, [x for x in shout_by_id.authors]) or "editor" in roles:
|
||||||
logger.info(f"shout#{shout_id} is author or editor")
|
logger.info(f"Author #{author_id} has permission to edit shout#{shout_id}")
|
||||||
|
|
||||||
# topics patch
|
# topics patch
|
||||||
topics_input = shout_input.get("topics")
|
topics_input = shout_input.get("topics")
|
||||||
if topics_input:
|
if topics_input:
|
||||||
logger.info(f"topics_input: {topics_input}")
|
logger.info(f"Received topics_input for shout#{shout_id}: {topics_input}")
|
||||||
patch_topics(session, shout_by_id, topics_input)
|
try:
|
||||||
|
patch_topics(session, shout_by_id, topics_input)
|
||||||
|
logger.info(f"Successfully patched topics for shout#{shout_id}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error patching topics: {e}", exc_info=True)
|
||||||
|
return {"error": f"Failed to update topics: {str(e)}"}
|
||||||
|
|
||||||
del shout_input["topics"]
|
del shout_input["topics"]
|
||||||
for tpc in topics_input:
|
for tpc in topics_input:
|
||||||
await cache_by_id(Topic, tpc["id"], cache_topic)
|
await cache_by_id(Topic, tpc["id"], cache_topic)
|
||||||
|
else:
|
||||||
|
logger.warning(f"No topics_input received for shout#{shout_id}")
|
||||||
|
|
||||||
# main topic
|
# main topic
|
||||||
main_topic = shout_input.get("main_topic")
|
main_topic = shout_input.get("main_topic")
|
||||||
if main_topic:
|
if main_topic:
|
||||||
|
logger.info(f"Updating main topic for shout#{shout_id} to {main_topic}")
|
||||||
patch_main_topic(session, main_topic, shout_by_id)
|
patch_main_topic(session, main_topic, shout_by_id)
|
||||||
|
|
||||||
shout_input["updated_at"] = current_time
|
shout_input["updated_at"] = current_time
|
||||||
if publish:
|
if publish:
|
||||||
logger.info(f"publishing shout#{shout_id} with input: {shout_input}")
|
logger.info(f"Publishing shout#{shout_id}")
|
||||||
shout_input["published_at"] = current_time
|
shout_input["published_at"] = current_time
|
||||||
# Проверяем наличие связи с автором
|
# Проверяем наличие связи с автором
|
||||||
logger.info(f"Checking author link for shout#{shout_id} and author#{author_id}")
|
logger.info(f"Checking author link for shout#{shout_id} and author#{author_id}")
|
||||||
|
@ -343,11 +401,25 @@ async def update_shout(_, info, shout_id: int, shout_input=None, publish=False):
|
||||||
else:
|
else:
|
||||||
logger.info("Author link already exists")
|
logger.info("Author link already exists")
|
||||||
|
|
||||||
|
# Логируем финальное состояние перед сохранением
|
||||||
|
logger.info(f"Final shout_input for update: {shout_input}")
|
||||||
Shout.update(shout_by_id, shout_input)
|
Shout.update(shout_by_id, shout_input)
|
||||||
session.add(shout_by_id)
|
session.add(shout_by_id)
|
||||||
session.commit()
|
|
||||||
|
|
||||||
shout_dict = shout_by_id.dict()
|
try:
|
||||||
|
session.commit()
|
||||||
|
logger.info(f"Successfully committed updates for shout#{shout_id}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Commit failed: {e}", exc_info=True)
|
||||||
|
return {"error": f"Failed to save changes: {str(e)}"}
|
||||||
|
|
||||||
|
# После обновления проверяем топики
|
||||||
|
updated_topics = (
|
||||||
|
[{"id": t.id, "slug": t.slug, "title": t.title} for t in shout_by_id.topics]
|
||||||
|
if shout_by_id.topics
|
||||||
|
else []
|
||||||
|
)
|
||||||
|
logger.info(f"Updated topics for shout#{shout_id}: {updated_topics}")
|
||||||
|
|
||||||
# Инвалидация кэша после обновления
|
# Инвалидация кэша после обновления
|
||||||
try:
|
try:
|
||||||
|
@ -379,25 +451,23 @@ async def update_shout(_, info, shout_id: int, shout_input=None, publish=False):
|
||||||
logger.warning(f"Cache invalidation error: {cache_error}", exc_info=True)
|
logger.warning(f"Cache invalidation error: {cache_error}", exc_info=True)
|
||||||
|
|
||||||
if not publish:
|
if not publish:
|
||||||
await notify_shout(shout_dict, "update")
|
await notify_shout(shout_by_id.dict(), "update")
|
||||||
else:
|
else:
|
||||||
await notify_shout(shout_dict, "published")
|
await notify_shout(shout_by_id.dict(), "published")
|
||||||
# search service indexing
|
# search service indexing
|
||||||
search_service.index(shout_by_id)
|
search_service.index(shout_by_id)
|
||||||
for a in shout_by_id.authors:
|
for a in shout_by_id.authors:
|
||||||
await cache_by_id(Author, a.id, cache_author)
|
await cache_by_id(Author, a.id, cache_author)
|
||||||
logger.info(f"shout#{shout_id} updated")
|
logger.info(f"shout#{shout_id} updated")
|
||||||
return {"shout": shout_dict, "error": None}
|
return {"shout": shout_by_id.dict(), "error": None}
|
||||||
else:
|
else:
|
||||||
logger.warning(f"updater for shout#{shout_id} is not author or editor")
|
logger.warning(f"Access denied: author #{author_id} cannot edit shout#{shout_id}")
|
||||||
return {"error": "access denied", "shout": None}
|
return {"error": "access denied", "shout": None}
|
||||||
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
import traceback
|
logger.error(f"Unexpected error in update_shout: {exc}", exc_info=True)
|
||||||
|
logger.error(f"Failed input data: {shout_input}")
|
||||||
traceback.print_exc()
|
return {"error": "cant update shout"}
|
||||||
logger.error(exc)
|
|
||||||
logger.error(f" cannot update with data: {shout_input}")
|
|
||||||
|
|
||||||
return {"error": "cant update shout"}
|
return {"error": "cant update shout"}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user