Merge branch 'main' of github.com:Discours/discours-backend into main

This commit is contained in:
tonyrewin 2022-06-13 20:28:47 +03:00
commit d93f686760
10 changed files with 130 additions and 70 deletions

View File

@ -13,7 +13,7 @@ passlib = "*"
PyJWT = "*"
SQLAlchemy = "*"
itsdangerous = "*"
httpx = "<0.18.2"
httpx = ">=0.23.0"
psycopg2-binary = "*"
Authlib = "*"
bson = "*"

View File

@ -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

View File

@ -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'

View File

@ -8,7 +8,7 @@ pydantic
passlib
itsdangerous
authlib==0.15.5
httpx==0.20.0
httpx>=0.23.0
psycopg2-binary
bson
python-frontmatter

View File

@ -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",

View File

@ -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,28 @@ 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()
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

View File

@ -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, get_subscribed_communities
from auth.authenticate import login_required
from inbox_resolvers.inbox import get_total_unread_messages_for_user
@ -32,7 +34,8 @@ 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)
"userSubscribedAuthors" : _get_user_subscribed_authors(slug),
"userSubscribedCommunities": get_subscribed_communities(slug)
}
@query.field("getCurrentUser")
@ -133,30 +136,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 {}

View File

@ -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 {}

View File

@ -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
@ -83,7 +84,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 +97,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 +199,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 +243,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):
@ -446,13 +447,18 @@ 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_by_community = session.query(Shout).\
join(Community).\
join(CommunitySubscription).\
where(CommunitySubscription.subscriber == user.slug)
shouts = shouts_by_topic.union(shouts_by_author).\
order_by(desc(Shout.publishedAt)).\
union(shouts_by_community).\
order_by(desc(Shout.createdAt)).\
limit(size).\
offset( (page - 1) * size)

View File

@ -9,7 +9,8 @@ type Result {
type CurrentUserInfo {
totalUnreadMessages : Int
userSubscribedTopics : [String]!
userSubscribedAuthors: [User]!
userSubscribedAuthors : [User]!
userSubscribedCommunities : [String]!
}
type AuthResult {
@ -93,6 +94,12 @@ type CommentUpdatedResult {
comment: Comment
}
enum SubscriptionType {
TOPIC
AUTHOR
COMMUNITY
}
################################### Mutation
type Mutation {
@ -118,8 +125,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 +135,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