diff --git a/resolvers/editor.py b/resolvers/editor.py index f640fa84..d1bca743 100644 --- a/resolvers/editor.py +++ b/resolvers/editor.py @@ -6,8 +6,6 @@ from sqlalchemy.sql.functions import coalesce from cache.cache import cache_author, cache_topic from orm.author import Author -from orm.rating import is_negative, is_positive -from orm.reaction import Reaction, ReactionKind from orm.shout import Shout, ShoutAuthor, ShoutTopic from orm.topic import Topic from resolvers.follower import follow, unfollow @@ -17,7 +15,6 @@ from services.db import local_session from services.notify import notify_shout from services.schema import mutation, query from services.search import search_service -from utils.diff import apply_diff, get_diff from utils.logger import root_logger as logger @@ -329,40 +326,3 @@ async def delete_shout(_, info, shout_id: int): return {"error": None} else: return {"error": "access denied"} - - -def handle_proposing(session, r, shout): - if is_positive(r.kind): - replied_reaction = session.query(Reaction).filter(Reaction.id == r.reply_to, Reaction.shout == r.shout).first() - - if replied_reaction and replied_reaction.kind is ReactionKind.PROPOSE.value and replied_reaction.quote: - # patch all the proposals' quotes - proposals = ( - session.query(Reaction) - .filter( - and_( - Reaction.shout == r.shout, - Reaction.kind == ReactionKind.PROPOSE.value, - ) - ) - .all() - ) - - for proposal in proposals: - if proposal.quote: - proposal_diff = get_diff(shout.body, proposal.quote) - proposal_dict = proposal.dict() - proposal_dict["quote"] = apply_diff(replied_reaction.quote, proposal_diff) - Reaction.update(proposal, proposal_dict) - session.add(proposal) - - # patch shout's body - shout_dict = shout.dict() - shout_dict["body"] = replied_reaction.quote - Shout.update(shout, shout_dict) - session.add(shout) - session.commit() - - if is_negative(r.kind): - # TODO: rejection logic - pass diff --git a/resolvers/proposals.py b/resolvers/proposals.py new file mode 100644 index 00000000..69266cd7 --- /dev/null +++ b/resolvers/proposals.py @@ -0,0 +1,48 @@ + + +from sqlalchemy import and_ +from orm.rating import is_negative, is_positive +from orm.reaction import Reaction, ReactionKind +from orm.shout import Shout +from services.db import local_session +from utils.diff import apply_diff, get_diff + + +def handle_proposing(kind: ReactionKind, reply_to: int, shout_id: int): + with local_session() as session: + if is_positive(kind): + replied_reaction = session.query(Reaction).filter(Reaction.id == reply_to, Reaction.shout == shout_id).first() + + if replied_reaction and replied_reaction.kind is ReactionKind.PROPOSE.value and replied_reaction.quote: + # patch all the proposals' quotes + proposals = ( + session.query(Reaction) + .filter( + and_( + Reaction.shout == shout_id, + Reaction.kind == ReactionKind.PROPOSE.value, + ) + ) + .all() + ) + + # patch shout's body + shout = session.query(Shout).filter(Shout.id == shout_id).first() + body = replied_reaction.quote + Shout.update(shout, { body }) + session.add(shout) + session.commit() + + # реакция содержит цитату -> обновляются все предложения + # (proposals) для соответствующего Shout. + for proposal in proposals: + if proposal.quote: + proposal_diff = get_diff(shout.body, proposal.quote) + proposal_dict = proposal.dict() + proposal_dict["quote"] = apply_diff(replied_reaction.quote, proposal_diff) + Reaction.update(proposal, proposal_dict) + session.add(proposal) + + if is_negative(kind): + # TODO: rejection logic + pass diff --git a/resolvers/reaction.py b/resolvers/reaction.py index a28595a3..7f7959d7 100644 --- a/resolvers/reaction.py +++ b/resolvers/reaction.py @@ -7,7 +7,7 @@ from orm.author import Author from orm.rating import PROPOSAL_REACTIONS, RATING_REACTIONS, is_negative, is_positive from orm.reaction import Reaction, ReactionKind from orm.shout import Shout -from resolvers.editor import handle_proposing +from resolvers.proposals import handle_proposing from resolvers.follower import follow from resolvers.stat import update_author_stat from services.auth import add_user_role, login_required @@ -82,8 +82,12 @@ def get_reactions_with_stat(q, limit, offset): with local_session() as session: result_rows = session.execute(q) for reaction, author, shout, commented_stat, rating_stat in result_rows: - reaction.created_by = author - reaction.shout = shout + if shout is None: + logger.error(f"пустое поле Shout: {reaction.dict()}") + continue # Или обработайте иначе + + reaction.created_by = author.dict() + reaction.shout = shout.dict() reaction.stat = {"rating": rating_stat, "comments": commented_stat} reactions.append(reaction) @@ -186,7 +190,7 @@ def set_unfeatured(session, shout_id): session.commit() -async def _create_reaction(session, info, shout, author_id: int, reaction) -> dict: +async def _create_reaction(session, info, shout_dict, author_id: int, reaction) -> dict: """ Create a new reaction and perform related actions such as updating counters and notification. @@ -207,20 +211,21 @@ async def _create_reaction(session, info, shout, author_id: int, reaction) -> di update_author_stat(author_id) # Handle proposal - if r.reply_to and r.kind in PROPOSAL_REACTIONS and author_id in shout.authors: - handle_proposing(session, r, shout) - + is_author = bool(list(filter(lambda x: x['id'] == int(author_id), [x for x in shout_dict['authors']]))) + if r.reply_to and r.kind in PROPOSAL_REACTIONS and is_author: + handle_proposing(r.kind, r.reply_to, shout_dict['id']) + # Handle rating if r.kind in RATING_REACTIONS: if check_to_unfeature(session, author_id, r): - set_unfeatured(session, shout.id) + set_unfeatured(session, shout_dict['id']) elif check_to_feature(session, author_id, r): - await set_featured(session, shout.id) + await set_featured(session, shout_dict['id']) # Follow if liked if r.kind == ReactionKind.LIKE.value: try: - follow(None, info, "shout", shout.slug) + follow(None, info, "shout", shout_dict['slug']) except Exception: pass @@ -292,6 +297,7 @@ async def create_reaction(_, info, reaction): logger.debug(f"Loaded shout: {shout and shout.id}") if shout: + shout_dict = shout.dict() reaction["created_by"] = author_id kind = reaction.get( "kind", ReactionKind.COMMENT.value if isinstance(reaction.get("body"), str) else None @@ -305,6 +311,7 @@ async def create_reaction(_, info, reaction): logger.error(f"Rating preparation error: {error_result}") return error_result + logger.debug(f"Creating reaction for shout: {shout_dict['id']}") rdict = await _create_reaction(session, info, shout, author_id, reaction) logger.debug(f"Created reaction result: {rdict}")