From ddc2d69e5427ba824c2e07fc3df5dddfc0185397 Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 21 Jan 2025 17:50:02 +0300 Subject: [PATCH] published_at-revert --- resolvers/editor.py | 287 ++++++++++++++++++++------------------------ 1 file changed, 128 insertions(+), 159 deletions(-) diff --git a/resolvers/editor.py b/resolvers/editor.py index 44b4c308..1cb55322 100644 --- a/resolvers/editor.py +++ b/resolvers/editor.py @@ -100,147 +100,133 @@ async def create_shout(_, info, inp): logger.debug(f"Context user_id: {user_id}, author: {author_dict}") if not author_dict: + logger.error("Author profile not found in context") return {"error": "author profile was not found"} - try: - with local_session() as session: - current_time = int(time.time()) - is_draft = inp.get("is_draft", False) - if not is_draft: - inp["published_at"] = current_time + author_id = author_dict.get("id") + if user_id and author_id: + try: + with local_session() as session: + author_id = int(author_id) + current_time = int(time.time()) + slug = inp.get("slug") or f"draft-{current_time}" + + logger.info(f"Creating shout with slug: {slug}") + + # Создаем объект Shout напрямую, без промежуточного словаря + new_shout = Shout( + title=inp.get("title", ""), + subtitle=inp.get("subtitle", ""), + lead=inp.get("lead", ""), + description=inp.get("description", ""), + body=inp.get("body", ""), + layout=inp.get("layout", "article"), + created_by=author_id, + slug=slug, + published_at=None, + community=1, + created_at=current_time, + stat={ # Добавляем начальную статистику + "views": 0, + "comments": 0, + "reactions": 0, + "shares": 0, + "bookmarks": 0 + } + ) - # Устанавливаем обязательные поля - inp["created_at"] = current_time - inp["updated_at"] = current_time - inp["created_by"] = author_dict.get("id") - inp["community"] = inp.get("community", 1) + # Check for duplicate slug + logger.debug(f"Checking for existing slug: {slug}") + same_slug_shout = session.query(Shout).filter(Shout.slug == new_shout.slug).first() + c = 1 + while same_slug_shout is not None: + logger.debug(f"Found duplicate slug, trying iteration {c}") + new_shout.slug = f"{slug}-{c}" + same_slug_shout = session.query(Shout).filter(Shout.slug == new_shout.slug).first() + c += 1 - # Генерация уникального slug с ограничением длины - base_slug = inp.get("slug") or f"draft-{current_time}" - slug = base_slug[:50] # Сразу ограничиваем длину базового slug - counter = 1 - max_attempts = 10 - - while counter <= max_attempts: - existing_slug = session.query(Shout).filter(Shout.slug == slug).first() - if not existing_slug: - break - slug = f"{base_slug[:40]}-{counter}" # Оставляем место для счетчика - counter += 1 - - if counter > max_attempts: - # Если не удалось создать уникальный slug, используем короткий вариант - slug = f"d-{current_time}-{author_dict.get('id')}" - - inp["slug"] = slug - inp["lang"] = inp.get("lang", "ru") - - # Добавляем обязательные поля контента - inp["title"] = inp.get("title", "Без названия") - inp["body"] = inp.get("body", "") - - logger.info("Creating new shout object") - new_shout = Shout(**inp) - session.add(new_shout) - session.flush() - - try: - session.commit() - logger.info(f"Created shout with ID: {new_shout.id}") - except Exception as e: - logger.error(f"Error creating shout object: {e}", exc_info=True) - return {"error": f"Database error: {str(e)}"} - - # Get created shout - try: - logger.debug(f"Retrieving created shout with slug: {new_shout.slug}") - shout = session.query(Shout).where(Shout.slug == new_shout.slug).first() - if not shout: - logger.error("Created shout not found in database") - return {"error": "Shout creation failed - not found after commit"} - except Exception as e: - logger.error(f"Error retrieving created shout: {e}", exc_info=True) - return {"error": f"Error retrieving created shout: {str(e)}"} - - # Link author - try: - logger.debug(f"Linking author {author_dict.get('id')} to shout {shout.id}") - existing_sa = session.query(ShoutAuthor).filter_by(shout=shout.id, author=author_dict.get("id")).first() - if not existing_sa: - sa = ShoutAuthor(shout=shout.id, author=author_dict.get("id")) - session.add(sa) - logger.info(f"Added author {author_dict.get('id')} to shout {shout.id}") - except Exception as e: - logger.error(f"Error linking author: {e}", exc_info=True) - return {"error": f"Error linking author: {str(e)}"} - - # Link topics - try: - logger.debug(f"Linking topics: {inp.get('topics', [])}") - topics = session.query(Topic).filter(Topic.slug.in_(inp.get("topics", []))).all() - for topic in topics: - existing_st = session.query(ShoutTopic).filter_by(shout=shout.id, topic=topic.id).first() - if not existing_st: - t = ShoutTopic(topic=topic.id, shout=shout.id) - session.add(t) - logger.info(f"Added topic {topic.id} to shout {shout.id}") - except Exception as e: - logger.error(f"Error linking topics: {e}", exc_info=True) - return {"error": f"Error linking topics: {str(e)}"} - - try: - session.commit() - logger.info("Final commit successful") - except Exception as e: - logger.error(f"Error in final commit: {e}", exc_info=True) - return {"error": f"Error in final commit: {str(e)}"} - - try: - logger.debug("Following created shout") - await follow(None, info, "shout", shout.slug) - except Exception as e: - logger.warning(f"Error following shout: {e}", exc_info=True) - # Don't return error as this is not critical - - # После успешного создания обновляем статистику автора - try: - author = session.query(Author).filter(Author.id == author_dict.get("id")).first() - if author and author.stat: - author.stat["shouts"] = author.stat.get("shouts", 0) + 1 - session.add(author) + try: + logger.info("Creating new shout object") + session.add(new_shout) session.commit() - await cache_author(author.dict()) - except Exception as e: - logger.warning(f"Error updating author stats: {e}", exc_info=True) - # Не возвращаем ошибку, так как это некритично + logger.info(f"Created shout with ID: {new_shout.id}") + except Exception as e: + logger.error(f"Error creating shout object: {e}", exc_info=True) + return {"error": f"Database error: {str(e)}"} - # Преобразуем связанные сущности в словари - try: - shout_dict = shout.dict() - shout_dict["authors"] = [ - {"id": author.id, "name": author.name, "slug": author.slug, "pic": author.pic} - for author in shout.authors - ] - shout_dict["topics"] = [ - {"id": topic.id, "name": topic.name, "slug": topic.slug} for topic in shout.topics - ] - logger.info(f"Successfully created shout {shout.id} with authors and topics as dicts") + # Get created shout + try: + logger.debug(f"Retrieving created shout with slug: {slug}") + shout = session.query(Shout).where(Shout.slug == slug).first() + if not shout: + logger.error("Created shout not found in database") + return {"error": "Shout creation failed - not found after commit"} + except Exception as e: + logger.error(f"Error retrieving created shout: {e}", exc_info=True) + return {"error": f"Error retrieving created shout: {str(e)}"} - # Инвалидируем кэш - await invalidate_shouts_cache(["feed", f"author_{author_dict.get('id')}", "random_top", "unrated"]) + # Link author + try: + logger.debug(f"Linking author {author_id} to shout {shout.id}") + existing_sa = session.query(ShoutAuthor).filter_by(shout=shout.id, author=author_id).first() + if not existing_sa: + sa = ShoutAuthor(shout=shout.id, author=author_id) + session.add(sa) + logger.info(f"Added author {author_id} to shout {shout.id}") + except Exception as e: + logger.error(f"Error linking author: {e}", exc_info=True) + return {"error": f"Error linking author: {str(e)}"} - # Обновляем кэш связанных сущностей - # TODO: await cache_related_entities(shout) + # Link topics + try: + logger.debug(f"Linking topics: {inp.get('topics', [])}") + topics = session.query(Topic).filter(Topic.slug.in_(inp.get("topics", []))).all() + for topic in topics: + existing_st = session.query(ShoutTopic).filter_by(shout=shout.id, topic=topic.id).first() + if not existing_st: + t = ShoutTopic(topic=topic.id, shout=shout.id) + session.add(t) + logger.info(f"Added topic {topic.id} to shout {shout.id}") + except Exception as e: + logger.error(f"Error linking topics: {e}", exc_info=True) + return {"error": f"Error linking topics: {str(e)}"} - return {"shout": shout_dict, "error": None} - except Exception as e: - logger.warning(f"Error converting related entities to dicts: {e}", exc_info=True) - # Если преобразование не удалось, возвращаем исходный объект + try: + session.commit() + logger.info("Final commit successful") + except Exception as e: + logger.error(f"Error in final commit: {e}", exc_info=True) + return {"error": f"Error in final commit: {str(e)}"} + + try: + logger.debug("Following created shout") + await follow(None, info, "shout", shout.slug) + except Exception as e: + logger.warning(f"Error following shout: {e}", exc_info=True) + # Don't return error as this is not critical + + # После успешного создания обновляем статистику автора + try: + author = session.query(Author).filter(Author.id == author_id).first() + if author and author.stat: + author.stat["shouts"] = (author.stat.get("shouts", 0) + 1) + session.add(author) + session.commit() + await cache_author(author.dict()) + except Exception as e: + logger.warning(f"Error updating author stats: {e}", exc_info=True) + # Не возвращаем ошибку, так как это некритично + + logger.info(f"Successfully created shout {shout.id}") return {"shout": shout} - except Exception as exc: - logger.error(f"Error in create_shout: {exc}", exc_info=True) - return {"error": str(exc)} + except Exception as e: + logger.error(f"Unexpected error in create_shout: {e}", exc_info=True) + return {"error": f"Unexpected error: {str(e)}"} + + error_msg = "cant create shout" if user_id else "unauthorized" + logger.error(f"Create shout failed: {error_msg}") + return {"error": error_msg} def patch_main_topic(session, main_topic, shout): @@ -328,24 +314,13 @@ async def update_shout(_, info, shout_id: int, shout_input=None, publish=False): logger.info(f"shout#{shout_id} found") if slug != shout_by_id.slug: - base_slug = slug[:50] - new_slug = base_slug - counter = 1 - max_attempts = 10 - - while counter <= max_attempts: - same_slug_shout = ( - session.query(Shout).filter(and_(Shout.slug == new_slug, Shout.id != shout_id)).first() - ) - if not same_slug_shout: - break - new_slug = f"{base_slug[:40]}-{counter}" - counter += 1 - - if counter > max_attempts: - new_slug = f"d-{current_time}-{shout_id}" - - shout_input["slug"] = new_slug + same_slug_shout = session.query(Shout).filter(Shout.slug == slug).first() + c = 1 + while same_slug_shout is not None: + c += 1 + slug = f"{slug}-{c}" + same_slug_shout = session.query(Shout).filter(Shout.slug == slug).first() + shout_input["slug"] = slug 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: @@ -371,17 +346,11 @@ async def update_shout(_, info, shout_id: int, shout_input=None, publish=False): session.commit() shout_dict = shout_by_id.dict() - # Преобразуем связанные сущности в словари - try: - shout_dict["authors"] = [author.dict() for author in shout_by_id.authors] - shout_dict["topics"] = [topic.dict() for topic in shout_by_id.topics] - except Exception as e: - logger.warning(f"Error converting related entities to dicts: {e}", exc_info=True) # Инвалидация кэша после обновления try: logger.info("Invalidating cache after shout update") - + cache_keys = [ "feed", # лента f"author_{author_id}", # публикации автора @@ -393,7 +362,7 @@ async def update_shout(_, info, shout_id: int, shout_input=None, publish=False): for topic in shout_by_id.topics: cache_keys.append(f"topic_{topic.id}") cache_keys.append(f"topic_shouts_{topic.id}") - + # Добавляем ключи для новых тем (если есть в shout_input) if shout_input.get("topics"): for topic in shout_input["topics"]: @@ -402,13 +371,13 @@ async def update_shout(_, info, shout_id: int, shout_input=None, publish=False): cache_keys.append(f"topic_shouts_{topic.id}") await invalidate_shouts_cache(cache_keys) - + # Обновляем кэш тем и авторов for topic in shout_by_id.topics: await cache_by_id(Topic, topic.id, cache_topic) for author in shout_by_id.authors: await cache_author(author.dict()) - + logger.info("Cache invalidated successfully") except Exception as cache_error: logger.warning(f"Cache invalidation error: {cache_error}", exc_info=True) @@ -424,7 +393,7 @@ async def update_shout(_, info, shout_id: int, shout_input=None, publish=False): logger.info(f"shout#{shout_id} updated") return {"shout": shout_dict, "error": None} else: - logger.warning(f"shout#{shout_id} is not author or editor") + logger.warning(f"updater for shout#{shout_id} is not author or editor") return {"error": "access denied", "shout": None} except Exception as exc: