From 34aeb95ef366807d95c00c985692c37f6455cec6 Mon Sep 17 00:00:00 2001 From: knst-kotov Date: Wed, 29 Jun 2022 13:47:53 +0300 Subject: [PATCH 1/4] fix cooments subscription --- orm/shout.py | 2 ++ resolvers/comments.py | 52 +++++-------------------------------------- resolvers/profile.py | 1 + resolvers/zine.py | 25 ++++++++++++--------- schema.graphql | 1 + 5 files changed, 23 insertions(+), 58 deletions(-) diff --git a/orm/shout.py b/orm/shout.py index de6f1d6b..6b108bf3 100644 --- a/orm/shout.py +++ b/orm/shout.py @@ -18,6 +18,8 @@ class ShoutCommentsSubscription(Base): subscriber = Column(ForeignKey('user.slug'), primary_key = True) shout = Column(ForeignKey('shout.slug'), primary_key = True) createdAt: str = Column(DateTime, nullable=False, default = datetime.now, comment="Created at") + auto = Column(Boolean, nullable=False, default = False) + deletedAt: str = Column(DateTime, nullable=True) class ShoutAuthor(Base): __tablename__ = "shout_author" diff --git a/resolvers/comments.py b/resolvers/comments.py index 29a4163c..3e58c7d3 100644 --- a/resolvers/comments.py +++ b/resolvers/comments.py @@ -6,40 +6,7 @@ from auth.authenticate import login_required import asyncio from datetime import datetime -class CommentResult: - def __init__(self, status, comment): - self.status = status - self.comment = comment - -class ShoutCommentsSubscription: - queue = asyncio.Queue() - - def __init__(self, shout_slug): - self.shout_slug = shout_slug - -class ShoutCommentsStorage: - lock = asyncio.Lock() - subscriptions = [] - - @staticmethod - async def register_subscription(subs): - self = ShoutCommentsStorage - async with self.lock: - self.subscriptions.append(subs) - - @staticmethod - async def del_subscription(subs): - self = ShoutCommentsStorage - async with self.lock: - self.subscriptions.remove(subs) - - @staticmethod - async def put(comment_result): - self = ShoutCommentsStorage - async with self.lock: - for subs in self.subscriptions: - if comment_result.comment.shout == subs.shout_slug: - subs.queue.put_nowait(comment_result) +from sqlalchemy import and_ def comments_subscribe(user, slug): ShoutCommentsSubscription.create( @@ -53,7 +20,10 @@ def comments_unsubscribe(user, slug): first() if not sub: raise Exception("subscription not exist") - session.delete(sub) + if sub.auto: + sub.deletedAt = datetime.now() + else: + session.delete(sub) session.commit() @mutation.field("createComment") @@ -69,9 +39,6 @@ async def create_comment(_, info, body, shout, replyTo = None): replyTo = replyTo ) - result = CommentResult("NEW", comment) - await ShoutCommentsStorage.put(result) - return {"comment": comment} @mutation.field("updateComment") @@ -92,9 +59,6 @@ async def update_comment(_, info, id, body): session.commit() - result = CommentResult("UPDATED", comment) - await ShoutCommentsStorage.put(result) - return {"comment": comment} @mutation.field("deleteComment") @@ -113,9 +77,6 @@ async def delete_comment(_, info, id): comment.deletedAt = datetime.now() session.commit() - result = CommentResult("DELETED", comment) - await ShoutCommentsStorage.put(result) - return {} @mutation.field("rateComment") @@ -141,7 +102,4 @@ async def rate_comment(_, info, id, value): createdBy = user_id, value = value) - result = CommentResult("UPDATED_RATING", comment) - await ShoutCommentsStorage.put(result) - return {} diff --git a/resolvers/profile.py b/resolvers/profile.py index c22c3b1f..7e603495 100644 --- a/resolvers/profile.py +++ b/resolvers/profile.py @@ -4,6 +4,7 @@ from orm.comment import Comment from orm.base import local_session from orm.topic import Topic, TopicSubscription from resolvers.base import mutation, query, subscription +from resolvers.community import get_subscribed_communities from auth.authenticate import login_required from inbox_resolvers.inbox import get_total_unread_messages_for_user diff --git a/resolvers/zine.py b/resolvers/zine.py index 357e1910..838036f0 100644 --- a/resolvers/zine.py +++ b/resolvers/zine.py @@ -7,6 +7,9 @@ from orm.user import UserStorage, AuthorSubscription from orm.topic import TopicSubscription from resolvers.base import mutation, query +from resolvers.profile import author_subscribe, author_unsubscribe +from resolvers.topics import topic_subscribe, topic_unsubscribe +from resolvers.community import community_subscribe, community_unsubscribe from resolvers.comments import comments_subscribe, comments_unsubscribe from auth.authenticate import login_required from settings import SHOUTS_REPO @@ -315,17 +318,17 @@ async def shouts_by_communities(_, info, slugs, page, size): @mutation.field("subscribe") @login_required -async def subscribe(_, info, subscription, slug): +async def subscribe(_, info, what, slug): user = info.context["request"].user try: - if subscription == "AUTHOR": + if what == "AUTHOR": author_subscribe(user, slug) - elif subscription == "TOPIC": + elif what == "TOPIC": topic_subscribe(user, slug) - elif subscription == "COMMUNITY": + elif what == "COMMUNITY": community_subscribe(user, slug) - elif comments_subscription == "COMMENTS": + elif what == "COMMENTS": comments_subscribe(user, slug) except Exception as e: return {"error" : e} @@ -334,17 +337,17 @@ async def subscribe(_, info, subscription, slug): @mutation.field("unsubscribe") @login_required -async def unsubscribe(_, info, subscription, slug): +async def unsubscribe(_, info, what, slug): user = info.context["request"].user try: - if subscription == "AUTHOR": + if what == "AUTHOR": author_unsubscribe(user, slug) - elif subscription == "TOPIC": + elif what == "TOPIC": topic_unsubscribe(user, slug) - elif subscription == "COMMUNITY": + elif what == "COMMUNITY": community_unsubscribe(user, slug) - elif subscription == "COMMENTS": + elif what == "COMMENTS": comments_unsubscribe(user, slug) except Exception as e: return {"error" : e} @@ -374,4 +377,4 @@ async def rate_shout(_, info, slug, value): await ShoutRatingStorage.update_rating(rating) - return {"error" : ""} \ No newline at end of file + return {"error" : ""} diff --git a/schema.graphql b/schema.graphql index a5b77615..d1459826 100644 --- a/schema.graphql +++ b/schema.graphql @@ -98,6 +98,7 @@ enum SubscriptionType { TOPIC AUTHOR COMMUNITY + COMMENTS } ################################### Mutation From 3f7d9c527bee5516670707d09e982b272aef42f6 Mon Sep 17 00:00:00 2001 From: knst-kotov Date: Wed, 29 Jun 2022 14:32:56 +0300 Subject: [PATCH 2/4] return subscribed shout comments in CurrentUserInfo --- resolvers/__init__.py | 3 +-- resolvers/comments.py | 10 ++++++++-- resolvers/profile.py | 26 ++++++-------------------- schema.graphql | 10 +++++----- 4 files changed, 20 insertions(+), 29 deletions(-) diff --git a/resolvers/__init__.py b/resolvers/__init__.py index 7d164795..0941c76b 100644 --- a/resolvers/__init__.py +++ b/resolvers/__init__.py @@ -2,7 +2,7 @@ from resolvers.auth import login, sign_out, is_email_used, register, confirm, au from resolvers.zine import get_shout_by_slug, subscribe, unsubscribe, view_shout, rate_shout, \ top_month, top_overall, recent_published, recent_all, top_viewed, \ shouts_by_authors, shouts_by_topics, shouts_by_communities -from resolvers.profile import get_users_by_slugs, get_current_user, shouts_reviewed, shout_comments_subscribed +from resolvers.profile import get_users_by_slugs, get_current_user, shouts_reviewed from resolvers.topics import topic_subscribe, topic_unsubscribe, topics_by_author, \ topics_by_community, topics_by_slugs from resolvers.comments import create_comment, delete_comment, update_comment, rate_comment @@ -31,7 +31,6 @@ __all__ = [ "shouts_by_topics", "shouts_by_authors", "shouts_by_communities", - "shout_comments_subscribed", "shouts_reviewed", "top_month", "top_overall", diff --git a/resolvers/comments.py b/resolvers/comments.py index 3e58c7d3..0de99dcf 100644 --- a/resolvers/comments.py +++ b/resolvers/comments.py @@ -6,8 +6,6 @@ from auth.authenticate import login_required import asyncio from datetime import datetime -from sqlalchemy import and_ - def comments_subscribe(user, slug): ShoutCommentsSubscription.create( subscriber = user.slug, @@ -103,3 +101,11 @@ async def rate_comment(_, info, id, value): value = value) return {} + +def get_subscribed_shout_comments(slug): + with local_session() as session: + rows = session.query(ShoutCommentsSubscription.shout).\ + filter(ShoutCommentsSubscription.subscriber == slug and not ShoutCommentsSubscription.deletedAt is None).\ + all() + slugs = [row.shout for row in rows] + return slugs diff --git a/resolvers/profile.py b/resolvers/profile.py index 7e603495..930af9aa 100644 --- a/resolvers/profile.py +++ b/resolvers/profile.py @@ -5,6 +5,7 @@ from orm.base import local_session from orm.topic import Topic, TopicSubscription from resolvers.base import mutation, query, subscription from resolvers.community import get_subscribed_communities +from resolvers.comments import get_subscribed_shout_comments from auth.authenticate import login_required from inbox_resolvers.inbox import get_total_unread_messages_for_user @@ -31,10 +32,11 @@ def _get_user_subscribed_authors(slug): async def get_user_info(slug): return { - "totalUnreadMessages" : await get_total_unread_messages_for_user(slug), - "userSubscribedTopics" : _get_user_subscribed_topic_slugs(slug), - "userSubscribedAuthors" : _get_user_subscribed_authors(slug), - "userSubscribedCommunities": get_subscribed_communities(slug) + "totalUnreadMessages" : await get_total_unread_messages_for_user(slug), + "userSubscribedTopics" : _get_user_subscribed_topic_slugs(slug), + "userSubscribedAuthors" : _get_user_subscribed_authors(slug), + "userSubscribedCommunities" : get_subscribed_communities(slug), + "userSubscribedShoutComments": get_subscribed_shout_comments(slug) } @query.field("getCurrentUser") @@ -204,22 +206,6 @@ async def shouts_reviewed(_, info, page, size): return shouts -@query.field("shoutCommentsSubscribed") -@login_required -async def shout_comments_subscribed(_, info, slug, page, size): - user = info.context["request"].user - with local_session() as session: - comments_by_shout = session.query(Comment).\ - join(ShoutCommentsSubscription).\ - join(ShoutCommentsSubscription, ShoutCommentsSubscription.shout == slug).\ - where(ShoutCommentsSubscription.subscriber == user.slug) - comments = comments_by_shout.\ - order_by(desc(Shout.createdAt)).\ - limit(size).\ - offset( (page - 1) * size) - - return shouts - @query.field("shoutsCommentedByUser") async def shouts_commented_by_user(_, info, slug, page, size): user = await UserStorage.get_user_by_slug(slug) diff --git a/schema.graphql b/schema.graphql index d1459826..72f3baf5 100644 --- a/schema.graphql +++ b/schema.graphql @@ -7,10 +7,11 @@ type Result { } type CurrentUserInfo { - totalUnreadMessages: Int - userSubscribedTopics: [String]! - userSubscribedAuthors: [String]! - userSubscribedCommunities: [String]! + totalUnreadMessages: Int + userSubscribedTopics: [String]! + userSubscribedAuthors: [String]! + userSubscribedCommunities: [String]! + userSubscribedShoutComments: [String]! } type AuthResult { @@ -206,7 +207,6 @@ type Query { getCommunity(slug: String): Community! getCommunities: [Community]! - shoutCommentsSubscribed(slug: String!, page: Int!, size: Int!): [Shout]! shoutsReviewed(page: Int!, size: Int!): [Shout]! recentCommented(page: Int!, size: Int!): [Shout]! } From dc3f7fe6a55b52290b323a2920353963fee2ea37 Mon Sep 17 00:00:00 2001 From: knst-kotov Date: Wed, 29 Jun 2022 15:22:14 +0300 Subject: [PATCH 3/4] autosubscribe when comment created --- resolvers/comments.py | 35 +++++++++++++++++++++++++++-------- resolvers/zine.py | 4 ++-- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/resolvers/comments.py b/resolvers/comments.py index 0de99dcf..dc426a01 100644 --- a/resolvers/comments.py +++ b/resolvers/comments.py @@ -6,15 +6,30 @@ from auth.authenticate import login_required import asyncio from datetime import datetime -def comments_subscribe(user, slug): +def comments_subscribe(user, slug, auto = False): + with local_session() as session: + sub = session.query(ShoutCommentsSubscription).\ + filter(ShoutCommentsSubscription.subscriber == user.slug, ShoutCommentsSubscription.shout == slug).\ + first() + if auto and sub: + return + elif not auto and sub: + if not sub.deletedAt is None: + sub.deletedAt = None + sub.auto = False + session.commit() + return + raise Exception("subscription already exist") + ShoutCommentsSubscription.create( subscriber = user.slug, - shout = slug) + shout = slug, + auto = auto) def comments_unsubscribe(user, slug): with local_session() as session: sub = session.query(ShoutCommentsSubscription).\ - filter(and_(ShoutCommentsSubscription.subscriber == user.slug, ShoutCommentsSubscription.shout == slug)).\ + filter(ShoutCommentsSubscription.subscriber == user.slug, ShoutCommentsSubscription.shout == slug).\ first() if not sub: raise Exception("subscription not exist") @@ -27,16 +42,20 @@ def comments_unsubscribe(user, slug): @mutation.field("createComment") @login_required async def create_comment(_, info, body, shout, replyTo = None): - auth = info.context["request"].auth - user_id = auth.user_id + user = info.context["request"].user comment = Comment.create( - author = user_id, + author = user.id, body = body, shout = shout, replyTo = replyTo ) + try: + comments_subscribe(user, shout, True) + except Exception as e: + print(f"error on comment autosubscribe: {e}") + return {"comment": comment} @mutation.field("updateComment") @@ -89,7 +108,7 @@ async def rate_comment(_, info, id, value): return {"error": "invalid comment id"} rating = session.query(CommentRating).\ - filter(CommentRating.comment_id == id and CommentRating.createdBy == user_id).first() + filter(CommentRating.comment_id == id, CommentRating.createdBy == user_id).first() if rating: rating.value = value session.commit() @@ -105,7 +124,7 @@ async def rate_comment(_, info, id, value): def get_subscribed_shout_comments(slug): with local_session() as session: rows = session.query(ShoutCommentsSubscription.shout).\ - filter(ShoutCommentsSubscription.subscriber == slug and not ShoutCommentsSubscription.deletedAt is None).\ + filter(ShoutCommentsSubscription.subscriber == slug, ShoutCommentsSubscription.deletedAt == None).\ all() slugs = [row.shout for row in rows] return slugs diff --git a/resolvers/zine.py b/resolvers/zine.py index 838036f0..17180453 100644 --- a/resolvers/zine.py +++ b/resolvers/zine.py @@ -331,7 +331,7 @@ async def subscribe(_, info, what, slug): elif what == "COMMENTS": comments_subscribe(user, slug) except Exception as e: - return {"error" : e} + return {"error" : str(e)} return {} @@ -350,7 +350,7 @@ async def unsubscribe(_, info, what, slug): elif what == "COMMENTS": comments_unsubscribe(user, slug) except Exception as e: - return {"error" : e} + return {"error" : str(e)} return {} From 8b2bbfec7b8590a15873ada816e94ea55d31075f Mon Sep 17 00:00:00 2001 From: knst-kotov Date: Wed, 29 Jun 2022 16:05:04 +0300 Subject: [PATCH 4/4] autosubscribe when shout created --- resolvers/editor.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/resolvers/editor.py b/resolvers/editor.py index 86e7654c..27f9c494 100644 --- a/resolvers/editor.py +++ b/resolvers/editor.py @@ -1,6 +1,7 @@ from orm import Shout, ShoutRating, ShoutRatingStorage from orm.base import local_session from resolvers.base import mutation, query, subscription +from resolvers.comments import comments_subscribe from auth.authenticate import login_required import asyncio from datetime import datetime @@ -19,7 +20,9 @@ async def create_shout(_, info, input): ShoutAuthor.create( shout = new_shout.slug, user = user.slug) - + + comments_subscribe(user, new_shout.slug, True) + if "mainTopic" in input: topic_slugs.append(input["mainTopic"]) @@ -106,4 +109,4 @@ async def delete_shout(_, info, slug): shout.deletedAt = datetime.now() session.commit() - return {} \ No newline at end of file + return {}