From 03c1b69bfb62689f4e79b44e781fa9fd1c18087f Mon Sep 17 00:00:00 2001 From: knst-kotov Date: Sun, 12 Jun 2022 09:10:00 +0300 Subject: [PATCH 1/6] fix recentAll --- resolvers/__init__.py | 4 ++-- resolvers/zine.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/resolvers/__init__.py b/resolvers/__init__.py index 658ae999..86b097a1 100644 --- a/resolvers/__init__.py +++ b/resolvers/__init__.py @@ -1,6 +1,6 @@ from resolvers.auth import login, sign_out, is_email_free, register, confirm from resolvers.zine import create_shout, get_shout_by_slug, \ - top_month, top_overall, recent_shouts, recent_all, top_viewed, shouts_by_authors, shouts_by_topics, shouts_by_communities, \ + top_month, top_overall, recent_published, recent_all, top_viewed, shouts_by_authors, shouts_by_topics, shouts_by_communities, \ shouts_candidates, shouts_reviewed, shouts_subscribed from resolvers.profile import get_users_by_slugs, get_current_user from resolvers.topics import topic_subscribe, topic_unsubscribe, topics_by_author, \ @@ -19,7 +19,7 @@ __all__ = [ "get_current_user", "get_users_by_slugs", "get_shout_by_slug", - "recent_shouts", + "recent_published", "recent_all", "shouts_by_topics", "shouts_by_authors", diff --git a/resolvers/zine.py b/resolvers/zine.py index f8e1dcf9..9f7c934a 100644 --- a/resolvers/zine.py +++ b/resolvers/zine.py @@ -83,7 +83,7 @@ class ShoutsCache: lock = asyncio.Lock() @staticmethod - async def prepare_recent_shouts(): + async def prepare_recent_published(): with local_session() as session: stmt = select(Shout).\ options(selectinload(Shout.authors), selectinload(Shout.topics)).\ @@ -96,14 +96,14 @@ class ShoutsCache: shout.ratings = await ShoutRatingStorage.get_ratings(shout.slug) shouts.append(shout) async with ShoutsCache.lock: - ShoutsCache.recent_shouts = shouts + ShoutsCache.recent_published = shouts @staticmethod async def prepare_recent_all(): with local_session() as session: stmt = select(Shout).\ options(selectinload(Shout.authors), selectinload(Shout.topics)).\ - where(Shout.publishedAt != None).\ + order_by(desc("createdAt")).\ limit(ShoutsCache.limit) shouts = [] for row in session.execute(stmt): @@ -198,7 +198,7 @@ class ShoutsCache: await ShoutsCache.prepare_top_month() await ShoutsCache.prepare_top_overall() await ShoutsCache.prepare_top_viewed() - await ShoutsCache.prepare_recent_shouts() + await ShoutsCache.prepare_recent_published() await ShoutsCache.prepare_recent_all() await ShoutsCache.prepare_recent_commented() print("shouts cache update finished") @@ -242,9 +242,9 @@ async def top_overall(_, info, page, size): return ShoutsCache.top_overall[(page - 1) * size : page * size] @query.field("recentPublished") -async def recent_shouts(_, info, page, size): +async def recent_published(_, info, page, size): async with ShoutsCache.lock: - return ShoutsCache.recent_shouts[(page - 1) * size : page * size] + return ShoutsCache.recent_published[(page - 1) * size : page * size] @query.field("recentAll") async def recent_all(_, info, page, size): From f89cb47daf19947fca23f7a7e930cba25985180b Mon Sep 17 00:00:00 2001 From: knst-kotov Date: Sun, 12 Jun 2022 09:17:02 +0300 Subject: [PATCH 2/6] shoutsSubscribed return published and unpublished shouts --- resolvers/zine.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resolvers/zine.py b/resolvers/zine.py index 9f7c934a..2b96c8ee 100644 --- a/resolvers/zine.py +++ b/resolvers/zine.py @@ -446,13 +446,13 @@ async def shouts_subscribed(_, info, page, size): shouts_by_topic = session.query(Shout).\ join(ShoutTopic).\ join(TopicSubscription, ShoutTopic.topic == TopicSubscription.topic).\ - where(and_(Shout.publishedAt != None, TopicSubscription.subscriber == user.slug)) + where(TopicSubscription.subscriber == user.slug) shouts_by_author = session.query(Shout).\ join(ShoutAuthor).\ join(AuthorSubscription, ShoutAuthor.user == AuthorSubscription.author).\ - where(and_(Shout.publishedAt != None, AuthorSubscription.subscriber == user.slug)) + where(AuthorSubscription.subscriber == user.slug) shouts = shouts_by_topic.union(shouts_by_author).\ - order_by(desc(Shout.publishedAt)).\ + order_by(desc(Shout.createdAt)).\ limit(size).\ offset( (page - 1) * size) From 39070dc3594dd92a5dda3434bc29a8794cf00380 Mon Sep 17 00:00:00 2001 From: knst-kotov Date: Sun, 12 Jun 2022 10:51:22 +0300 Subject: [PATCH 3/6] add community subscription; unify subscription interface --- orm/__init__.py | 2 +- orm/community.py | 8 +++++++ resolvers/community.py | 20 ++++++++++++++++- resolvers/profile.py | 49 +++++++++++++++++++++++++++++++----------- resolvers/topics.py | 18 +++------------- schema.graphql | 12 +++++++---- 6 files changed, 76 insertions(+), 33 deletions(-) diff --git a/orm/__init__.py b/orm/__init__.py index 0cafbcb4..5aa2c2ee 100644 --- a/orm/__init__.py +++ b/orm/__init__.py @@ -1,5 +1,5 @@ from orm.rbac import Operation, Resource, Permission, Role, RoleStorage -from orm.community import Community +from orm.community import Community, CommunitySubscription from orm.user import User, UserRating, UserRole, UserStorage from orm.topic import Topic, TopicSubscription, TopicStorage from orm.notification import Notification diff --git a/orm/community.py b/orm/community.py index ca5459fc..3ffdad1d 100644 --- a/orm/community.py +++ b/orm/community.py @@ -3,6 +3,14 @@ from sqlalchemy import Column, Integer, String, ForeignKey, DateTime from sqlalchemy.orm import relationship, backref from orm.base import Base, local_session +class CommunitySubscription(Base): + __tablename__ = 'community_subscription' + + id = None + subscriber = Column(ForeignKey('user.slug'), primary_key = True) + community = Column(ForeignKey('community.slug'), primary_key = True) + createdAt: str = Column(DateTime, nullable=False, default = datetime.now, comment="Created at") + class Community(Base): __tablename__ = 'community' diff --git a/resolvers/community.py b/resolvers/community.py index 0a2778e4..5a9a3e04 100644 --- a/resolvers/community.py +++ b/resolvers/community.py @@ -1,10 +1,12 @@ -from orm import Community +from orm import Community, CommunitySubscription from orm.base import local_session from resolvers.base import mutation, query, subscription from auth.authenticate import login_required import asyncio from datetime import datetime +from sqlalchemy import and_ + @mutation.field("createCommunity") @login_required async def create_community(_, info, title, desc): @@ -68,3 +70,19 @@ async def get_communities(_, info): with local_session() as session: communities = session.query(Community) return communities + +def community_subscribe(user, slug): + CommunitySubscription.create( + subscriber = user.slug, + community = slug + ) + +def community_unsubscribe(user, slug): + with local_session() as session: + sub = session.query(CommunitySubscription).\ + filter(and_(CommunitySubscription.subscriber == user.slug, CommunitySubscription.community == slug)).\ + first() + if not sub: + raise Exception("subscription not exist") + session.delete(sub) + session.commit() diff --git a/resolvers/profile.py b/resolvers/profile.py index 86184da3..e3b01b21 100644 --- a/resolvers/profile.py +++ b/resolvers/profile.py @@ -4,6 +4,8 @@ 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.topics import topic_subscribe, topic_unsubscribe +from resolvers.community import community_subscribe, community_unsubscribe from auth.authenticate import login_required from inbox_resolvers.inbox import get_total_unread_messages_for_user @@ -133,30 +135,53 @@ async def rate_user(_, info, slug, value): return {} -@mutation.field("authorSubscribe") -@login_required -async def author_subscribe(_, info, slug): - user = info.context["request"].user +def author_subscribe(user, slug): AuthorSubscription.create( subscriber = user.slug, author = slug ) - return {} - -@mutation.field("authorUnsubscribe") -@login_required -async def author_unsubscribe(_, info, slug): - user = info.context["request"].user - +def author_unsubscribe(user, slug): with local_session() as session: sub = session.query(AuthorSubscription).\ filter(and_(AuthorSubscription.subscriber == user.slug, AuthorSubscription.author == slug)).\ first() if not sub: - return { "error" : "subscription not exist" } + raise Exception("subscription not exist") session.delete(sub) session.commit() +@mutation.field("subscribe") +@login_required +async def subscribe(_, info, subscription, slug): + user = info.context["request"].user + + try: + if subscription == "AUTHOR": + author_subscribe(user, slug) + elif subscription == "TOPIC": + topic_subscribe(user, slug) + elif subscription == "COMMUNITY": + community_subscribe(user, slug) + except Exception as e: + return {"error" : e} + + return {} + +@mutation.field("unsubscribe") +@login_required +async def unsubscribe(_, info, subscription, slug): + user = info.context["request"].user + + try: + if subscription == "AUTHOR": + author_unsubscribe(user, slug) + elif subscription == "TOPIC": + topic_unsubscribe(user, slug) + elif subscription == "COMMUNITY": + community_unsubscribe(user, slug) + except Exception as e: + return {"error" : e} + return {} diff --git a/resolvers/topics.py b/resolvers/topics.py index 9e2e4d14..1d372286 100644 --- a/resolvers/topics.py +++ b/resolvers/topics.py @@ -60,29 +60,17 @@ async def update_topic(_, info, input): return { "topic" : topic } -@mutation.field("topicSubscribe") -@login_required -async def topic_subscribe(_, info, slug): - user = info.context["request"].user - +def topic_subscribe(user, slug): TopicSubscription.create( subscriber = user.slug, topic = slug) - return {} - -@mutation.field("topicUnsubscribe") -@login_required -async def topic_unsubscribe(_, info, slug): - user = info.context["request"].user - +def topic_unsubscribe(user, slug): with local_session() as session: sub = session.query(TopicSubscription).\ filter(and_(TopicSubscription.subscriber == user.slug, TopicSubscription.topic == slug)).\ first() if not sub: - return { "error" : "subscription not exist" } + raise Exception("subscription not exist") session.delete(sub) session.commit() - - return {} diff --git a/schema.graphql b/schema.graphql index dccda6a2..ad60d00e 100644 --- a/schema.graphql +++ b/schema.graphql @@ -93,6 +93,12 @@ type CommentUpdatedResult { comment: Comment } +enum SubscriptionType { + TOPIC + AUTHOR + COMMUNITY +} + ################################### Mutation type Mutation { @@ -118,8 +124,6 @@ type Mutation { # topics createTopic(input: TopicInput!): TopicResult! updateTopic(input: TopicInput!): TopicResult! - topicSubscribe(slug: String!): Result! - topicUnsubscribe(slug: String!): Result! createComment(body: String!, shout: String!, replyTo: Int): CommentResult! updateComment(id: Int!, body: String!): CommentResult! @@ -130,8 +134,8 @@ type Mutation { updateCommunity(community: CommunityInput!): Community! deleteCommunity(id: Int!): Result! - authorSubscribe(slug: String!): Result! - authorUnsubscribe(slug: String!): Result! + subscribe(subscription : SubscriptionType!, slug: String!): Result! + unsubscribe(subscription : SubscriptionType!, slug: String!): Result! } ################################### Query From 7fd0b7e64348a67270e0d2410d8abf4c9f22eadd Mon Sep 17 00:00:00 2001 From: knst-kotov Date: Sun, 12 Jun 2022 11:33:24 +0300 Subject: [PATCH 4/6] add community to shoutsSubscribed --- resolvers/zine.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resolvers/zine.py b/resolvers/zine.py index 2b96c8ee..ac044378 100644 --- a/resolvers/zine.py +++ b/resolvers/zine.py @@ -1,5 +1,6 @@ from orm import Shout, ShoutAuthor, ShoutTopic, ShoutRating, ShoutViewByDay, User, Community, Resource,\ ShoutRatingStorage, ShoutViewStorage, Comment, CommentRating, Topic +from orm.community import CommunitySubscription from orm.base import local_session from orm.user import UserStorage, AuthorSubscription from orm.topic import TopicSubscription @@ -451,7 +452,12 @@ async def shouts_subscribed(_, info, page, size): join(ShoutAuthor).\ join(AuthorSubscription, ShoutAuthor.user == AuthorSubscription.author).\ where(AuthorSubscription.subscriber == user.slug) + shouts_by_community = session.query(Shout).\ + join(Community).\ + join(CommunitySubscription).\ + where(CommunitySubscription.subscriber == user.slug) shouts = shouts_by_topic.union(shouts_by_author).\ + union(shouts_by_community).\ order_by(desc(Shout.createdAt)).\ limit(size).\ offset( (page - 1) * size) From f92beaaeeb0dd7146f5516e6075c7f27f7c11d21 Mon Sep 17 00:00:00 2001 From: knst-kotov Date: Sun, 12 Jun 2022 11:45:08 +0300 Subject: [PATCH 5/6] return subscribed communities in user info --- resolvers/community.py | 9 +++++++++ resolvers/profile.py | 9 +++++---- schema.graphql | 7 ++++--- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/resolvers/community.py b/resolvers/community.py index 5a9a3e04..f3ce65b1 100644 --- a/resolvers/community.py +++ b/resolvers/community.py @@ -86,3 +86,12 @@ def community_unsubscribe(user, slug): raise Exception("subscription not exist") session.delete(sub) session.commit() + +def get_subscribed_communities(user_slug): + with local_session() as session: + rows = session.query(Community.slug).\ + join(CommunitySubscription).\ + where(CommunitySubscription.subscriber == user_slug).\ + all() + slugs = [row.slug for row in rows] + return slugs diff --git a/resolvers/profile.py b/resolvers/profile.py index e3b01b21..9e7ed6b2 100644 --- a/resolvers/profile.py +++ b/resolvers/profile.py @@ -5,7 +5,7 @@ from orm.base import local_session from orm.topic import Topic, TopicSubscription from resolvers.base import mutation, query, subscription from resolvers.topics import topic_subscribe, topic_unsubscribe -from resolvers.community import community_subscribe, community_unsubscribe +from resolvers.community import community_subscribe, community_unsubscribe, get_subscribed_communities from auth.authenticate import login_required from inbox_resolvers.inbox import get_total_unread_messages_for_user @@ -32,9 +32,10 @@ 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) + "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) } @query.field("getCurrentUser") diff --git a/schema.graphql b/schema.graphql index ad60d00e..96c40139 100644 --- a/schema.graphql +++ b/schema.graphql @@ -7,9 +7,10 @@ type Result { } type CurrentUserInfo { - totalUnreadMessages : Int - userSubscribedTopics : [String]! - userSubscribedAuthors: [User]! + totalUnreadMessages : Int + userSubscribedTopics : [String]! + userSubscribedAuthors : [User]! + userSubscribedCommunities : [String]! } type AuthResult { From 874551c42fd3ae4c5f7b9143ec8e8946bda04f3b Mon Sep 17 00:00:00 2001 From: knst-kotov Date: Sun, 12 Jun 2022 11:55:14 +0300 Subject: [PATCH 6/6] update httpx version --- Pipfile | 2 +- requirements.txt | 38 +++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Pipfile b/Pipfile index 90fed477..8f16daad 100644 --- a/Pipfile +++ b/Pipfile @@ -13,7 +13,7 @@ passlib = "*" PyJWT = "*" SQLAlchemy = "*" itsdangerous = "*" -httpx = "<0.18.2" +httpx = ">=0.23.0" psycopg2-binary = "*" Authlib = "*" bson = "*" diff --git a/requirements.txt b/requirements.txt index 1a97e2d9..e369a526 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,19 +1,19 @@ -aioredis -ariadne -pyjwt>=2.0.0 -starlette -sqlalchemy -uvicorn -pydantic -passlib -itsdangerous -authlib==0.15.5 -httpx==0.20.0 -psycopg2-binary -bson -python-frontmatter -transliterate -requests -bcrypt -bs4 -websockets +aioredis +ariadne +pyjwt>=2.0.0 +starlette +sqlalchemy +uvicorn +pydantic +passlib +itsdangerous +authlib==0.15.5 +httpx>=0.23.0 +psycopg2-binary +bson +python-frontmatter +transliterate +requests +bcrypt +bs4 +websockets