format and lint orm

This commit is contained in:
2022-09-03 13:50:14 +03:00
parent 85892a88bc
commit a89a44f660
55 changed files with 4811 additions and 4174 deletions

View File

@@ -1,76 +1,109 @@
from resolvers.auth import login, sign_out, is_email_used, register, confirm, auth_forget, auth_reset
from resolvers.zine import get_shout_by_slug, follow, unfollow, view_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, get_user_reacted_shouts, get_user_roles
from resolvers.topics import topic_follow, topic_unfollow, topics_by_author, topics_by_community, topics_all
from resolvers.auth import (
login,
sign_out,
is_email_used,
register,
confirm,
auth_forget,
auth_reset,
)
from resolvers.zine import (
get_shout_by_slug,
follow,
unfollow,
view_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,
get_user_reacted_shouts,
get_user_roles,
)
from resolvers.topics import (
topic_follow,
topic_unfollow,
topics_by_author,
topics_by_community,
topics_all,
)
# from resolvers.feed import shouts_for_feed, my_candidates
from resolvers.reactions import create_reaction, delete_reaction, update_reaction, get_all_reactions
from resolvers.reactions import (
create_reaction,
delete_reaction,
update_reaction,
get_all_reactions,
)
from resolvers.collab import invite_author, remove_author
from resolvers.editor import create_shout, delete_shout, update_shout
from resolvers.community import create_community, delete_community, get_community, get_communities
from resolvers.community import (
create_community,
delete_community,
get_community,
get_communities,
)
__all__ = [
"follow",
"unfollow",
# auth
"login",
"register",
"is_email_used",
"confirm",
"auth_forget",
"auth_reset"
"sign_out",
# profile
"get_current_user",
"get_users_by_slugs",
# zine
"shouts_for_feed",
"my_candidates",
"recent_published",
"recent_reacted",
"recent_all",
"shouts_by_topics",
"shouts_by_authors",
"shouts_by_communities",
"get_user_reacted_shouts",
"top_month",
"top_overall",
"top_viewed",
"view_shout",
"view_reaction",
"get_shout_by_slug",
# editor
"create_shout",
"update_shout",
"delete_shout",
# collab
"invite_author",
"remove_author"
# topics
"topics_all",
"topics_by_community",
"topics_by_author",
"topic_follow",
"topic_unfollow",
# communities
"get_community",
"get_communities",
"create_community",
"delete_community",
# reactions
"get_shout_reactions",
"reactions_follow",
"reactions_unfollow",
"create_reaction",
"update_reaction",
"delete_reaction",
"get_all_reactions",
]
# auth
"login",
"register",
"is_email_used",
"confirm",
"auth_forget",
"auth_reset" "sign_out",
# profile
"get_current_user",
"get_users_by_slugs",
# zine
"shouts_for_feed",
"my_candidates",
"recent_published",
"recent_reacted",
"recent_all",
"shouts_by_topics",
"shouts_by_authors",
"shouts_by_communities",
"get_user_reacted_shouts",
"top_month",
"top_overall",
"top_viewed",
"view_shout",
"view_reaction",
"get_shout_by_slug",
# editor
"create_shout",
"update_shout",
"delete_shout",
# collab
"invite_author",
"remove_author"
# topics
"topics_all",
"topics_by_community",
"topics_by_author",
"topic_follow",
"topic_unfollow",
# communities
"get_community",
"get_communities",
"create_community",
"delete_community",
# reactions
"get_shout_reactions",
"reactions_follow",
"reactions_unfollow",
"create_reaction",
"update_reaction",
"delete_reaction",
"get_all_reactions",
]

View File

@@ -13,119 +13,126 @@ from resolvers.profile import get_user_info
from base.exceptions import InvalidPassword, InvalidToken
from settings import JWT_AUTH_HEADER
@mutation.field("confirmEmail")
async def confirm(*_, confirm_token):
''' confirm owning email address '''
auth_token, user = await Authorize.confirm(confirm_token)
if auth_token:
user.emailConfirmed = True
user.save()
return { "token": auth_token, "user" : user}
else:
return { "error": "email not confirmed"}
"""confirm owning email address"""
auth_token, user = await Authorize.confirm(confirm_token)
if auth_token:
user.emailConfirmed = True
user.save()
return {"token": auth_token, "user": user}
else:
return {"error": "email not confirmed"}
@mutation.field("registerUser")
async def register(*_, email: str, password: str = ""):
''' creates new user account '''
with local_session() as session:
user = session.query(User).filter(User.email == email).first()
if user:
return {"error" : "user already exist"}
"""creates new user account"""
with local_session() as session:
user = session.query(User).filter(User.email == email).first()
if user:
return {"error": "user already exist"}
user_dict = { "email": email }
username = email.split('@')[0]
user_dict["username"] = username
user_dict["slug"] = quote_plus(translit(username, 'ru', reversed=True).replace('.', '-').lower())
if password:
user_dict["password"] = Password.encode(password)
user = User(**user_dict)
user.roles.append(Role.default_role)
with local_session() as session:
session.add(user)
session.commit()
user_dict = {"email": email}
username = email.split("@")[0]
user_dict["username"] = username
user_dict["slug"] = quote_plus(
translit(username, "ru", reversed=True).replace(".", "-").lower()
)
if password:
user_dict["password"] = Password.encode(password)
user = User(**user_dict)
user.roles.append(Role.default_role)
with local_session() as session:
session.add(user)
session.commit()
await send_confirm_email(user)
await send_confirm_email(user)
return {"user": user}
return { "user": user }
@mutation.field("requestPasswordUpdate")
async def auth_forget(_, info, email):
''' send email to recover account '''
with local_session() as session:
user = session.query(User).filter(User.email == email).first()
if not user:
return {"error" : "user not exist"}
"""send email to recover account"""
with local_session() as session:
user = session.query(User).filter(User.email == email).first()
if not user:
return {"error": "user not exist"}
await send_reset_password_email(user)
await send_reset_password_email(user)
return {}
return {}
@mutation.field("updatePassword")
async def auth_reset(_, info, password, resetToken):
''' set the new password '''
try:
user_id = await ResetPassword.verify(resetToken)
except InvalidToken as e:
return {"error" : e.message}
"""set the new password"""
try:
user_id = await ResetPassword.verify(resetToken)
except InvalidToken as e:
return {"error": e.message}
with local_session() as session:
user = session.query(User).filter_by(id = user_id).first()
if not user:
return {"error" : "user not exist"}
user.password = Password.encode(password)
session.commit()
with local_session() as session:
user = session.query(User).filter_by(id=user_id).first()
if not user:
return {"error": "user not exist"}
user.password = Password.encode(password)
session.commit()
return {}
return {}
@query.field("signIn")
async def login(_, info: GraphQLResolveInfo, email: str, password: str = ""):
with local_session() as session:
orm_user = session.query(User).filter(User.email == email).first()
if orm_user is None:
print(f"signIn {email}: email not found")
return {"error" : "email not found"}
with local_session() as session:
orm_user = session.query(User).filter(User.email == email).first()
if orm_user is None:
print(f"signIn {email}: email not found")
return {"error": "email not found"}
if not password:
print(f"signIn {email}: send auth email")
await send_auth_email(orm_user)
return {}
if not password:
print(f"signIn {email}: send auth email")
await send_auth_email(orm_user)
return {}
if not orm_user.emailConfirmed:
return {"error" : "email not confirmed"}
if not orm_user.emailConfirmed:
return {"error": "email not confirmed"}
try:
device = info.context["request"].headers['device']
except KeyError:
device = "pc"
auto_delete = False if device == "mobile" else True # why autodelete with mobile?
try:
device = info.context["request"].headers["device"]
except KeyError:
device = "pc"
auto_delete = False if device == "mobile" else True # why autodelete with mobile?
try:
user = Identity.identity(orm_user, password)
except InvalidPassword:
print(f"signIn {email}: invalid password")
return {"error" : "invalid password"}
token = await Authorize.authorize(user, device=device, auto_delete=auto_delete)
print(f"signIn {email}: OK")
try:
user = Identity.identity(orm_user, password)
except InvalidPassword:
print(f"signIn {email}: invalid password")
return {"error": "invalid password"}
return {
"token" : token,
"user": orm_user,
"info": await get_user_info(orm_user.slug)
}
token = await Authorize.authorize(user, device=device, auto_delete=auto_delete)
print(f"signIn {email}: OK")
return {
"token": token,
"user": orm_user,
"info": await get_user_info(orm_user.slug),
}
@query.field("signOut")
@login_required
async def sign_out(_, info: GraphQLResolveInfo):
token = info.context["request"].headers[JWT_AUTH_HEADER]
status = await Authorize.revoke(token)
return True
token = info.context["request"].headers[JWT_AUTH_HEADER]
status = await Authorize.revoke(token)
return True
@query.field("isEmailUsed")
async def is_email_used(_, info, email):
with local_session() as session:
user = session.query(User).filter(User.email == email).first()
return not user is None
with local_session() as session:
user = session.query(User).filter(User.email == email).first()
return not user is None

View File

@@ -6,67 +6,69 @@ from orm.user import User
from base.resolvers import query, mutation
from auth.authenticate import login_required
@query.field("getCollabs")
@login_required
async def get_collabs(_, info):
auth = info.context["request"].auth
user_id = auth.user_id
collabs = []
with local_session() as session:
user = session.query(User).where(User.id == user_id).first()
collabs = session.query(Collab).filter(user.slug in Collab.authors)
return collabs
auth = info.context["request"].auth
user_id = auth.user_id
collabs = []
with local_session() as session:
user = session.query(User).where(User.id == user_id).first()
collabs = session.query(Collab).filter(user.slug in Collab.authors)
return collabs
@mutation.field("inviteAuthor")
@login_required
async def invite_author(_, info, author, shout):
auth = info.context["request"].auth
user_id = auth.user_id
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
shout = session.query(Shout).filter(Shout.slug == shout).first()
if not shout:
return {"error": "invalid shout slug"}
authors = [a.id for a in shout.authors]
if user_id not in authors:
return {"error": "access denied"}
author = session.query(User).filter(User.slug == author).first()
if author.id in authors:
return {"error": "already added"}
shout.authors.append(author)
shout.updated_at = datetime.now()
shout.save()
session.commit()
with local_session() as session:
shout = session.query(Shout).filter(Shout.slug == shout).first()
if not shout:
return {"error": "invalid shout slug"}
authors = [a.id for a in shout.authors]
if user_id not in authors:
return {"error": "access denied"}
author = session.query(User).filter(User.slug == author).first()
if author.id in authors:
return {"error": "already added"}
shout.authors.append(author)
shout.updated_at = datetime.now()
shout.save()
session.commit()
# TODO: email notify
# TODO: email notify
return {}
return {}
@mutation.field("removeAuthor")
@login_required
async def remove_author(_, info, author, shout):
auth = info.context["request"].auth
user_id = auth.user_id
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
shout = session.query(Shout).filter(Shout.slug == shout).first()
if not shout:
return {"error": "invalid shout slug"}
authors = [author.id for author in shout.authors]
if user_id not in authors:
return {"error": "access denied"}
author = session.query(User).filter(User.slug == author).first()
if author.id not in authors:
return {"error": "not in authors"}
shout.authors.remove(author)
shout.updated_at = datetime.now()
shout.save()
session.commit()
with local_session() as session:
shout = session.query(Shout).filter(Shout.slug == shout).first()
if not shout:
return {"error": "invalid shout slug"}
authors = [author.id for author in shout.authors]
if user_id not in authors:
return {"error": "access denied"}
author = session.query(User).filter(User.slug == author).first()
if author.id not in authors:
return {"error": "not in authors"}
shout.authors.remove(author)
shout.updated_at = datetime.now()
shout.save()
session.commit()
# result = Result("INVITED")
# FIXME: await ShoutStorage.put(result)
# result = Result("INVITED")
# FIXME: await ShoutStorage.put(result)
# TODO: email notify
# TODO: email notify
return {}
return {}

View File

@@ -7,93 +7,121 @@ from datetime import datetime
from typing import Collection
from sqlalchemy import and_
@mutation.field("createCollection")
@login_required
async def create_collection(_, info, input):
auth = info.context["request"].auth
user_id = auth.user_id
collection = Collection.create(
slug = input.get('slug', ''),
title = input.get('title', ''),
desc = input.get('desc', ''),
pic = input.get('pic', '')
)
auth = info.context["request"].auth
user_id = auth.user_id
collection = Collection.create(
slug=input.get("slug", ""),
title=input.get("title", ""),
desc=input.get("desc", ""),
pic=input.get("pic", ""),
)
return {"collection": collection}
return {"collection": collection}
@mutation.field("updateCollection")
@login_required
async def update_collection(_, info, input):
auth = info.context["request"].auth
user_id = auth.user_id
collection_slug = input.get('slug', '')
with local_session() as session:
owner = session.query(User).filter(User.id == user_id) # note list here
collection = session.query(Collection).filter(Collection.slug == collection_slug).first()
editors = [e.slug for e in collection.editors]
if not collection:
return {"error": "invalid collection id"}
if collection.createdBy not in (owner + editors):
return {"error": "access denied"}
collection.title = input.get('title', '')
collection.desc = input.get('desc', '')
collection.pic = input.get('pic', '')
collection.updatedAt = datetime.now()
session.commit()
auth = info.context["request"].auth
user_id = auth.user_id
collection_slug = input.get("slug", "")
with local_session() as session:
owner = session.query(User).filter(User.id == user_id) # note list here
collection = (
session.query(Collection).filter(Collection.slug == collection_slug).first()
)
editors = [e.slug for e in collection.editors]
if not collection:
return {"error": "invalid collection id"}
if collection.createdBy not in (owner + editors):
return {"error": "access denied"}
collection.title = input.get("title", "")
collection.desc = input.get("desc", "")
collection.pic = input.get("pic", "")
collection.updatedAt = datetime.now()
session.commit()
@mutation.field("deleteCollection")
@login_required
async def delete_collection(_, info, slug):
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
collection = session.query(Collection).filter(Collection.slug == slug).first()
if not collection:
return {"error": "invalid collection slug"}
if collection.owner != user_id:
return {"error": "access denied"}
collection.deletedAt = datetime.now()
session.commit()
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
collection = session.query(Collection).filter(Collection.slug == slug).first()
if not collection:
return {"error": "invalid collection slug"}
if collection.owner != user_id:
return {"error": "access denied"}
collection.deletedAt = datetime.now()
session.commit()
return {}
return {}
@query.field("getUserCollections")
async def get_user_collections(_, info, userslug):
collections = []
with local_session() as session:
user = session.query(User).filter(User.slug == userslug).first()
if user:
# TODO: check rights here
collections = session.\
query(Collection).\
where(and_(Collection.createdBy == userslug, Collection.publishedAt != None)).\
all()
for c in collections:
shouts = session.query(ShoutCollection).filter(ShoutCollection.collection == c.id).all()
c.amount = len(shouts)
return collections
collections = []
with local_session() as session:
user = session.query(User).filter(User.slug == userslug).first()
if user:
# TODO: check rights here
collections = (
session.query(Collection)
.where(
and_(
Collection.createdBy == userslug, Collection.publishedAt != None
)
)
.all()
)
for c in collections:
shouts = (
session.query(ShoutCollection)
.filter(ShoutCollection.collection == c.id)
.all()
)
c.amount = len(shouts)
return collections
@query.field("getMyCollections")
async def get_user_collections(_, info, userslug):
collections = []
with local_session() as session:
user = session.query(User).filter(User.slug == userslug).first()
if user:
# TODO: check rights here
collections = session.\
query(Collection).\
where(and_(Collection.createdBy == userslug, Collection.publishedAt != None)).\
all()
for c in collections:
shouts = session.query(ShoutCollection).filter(ShoutCollection.collection == c.id).all()
c.amount = len(shouts)
return collections
collections = []
with local_session() as session:
user = session.query(User).filter(User.slug == userslug).first()
if user:
# TODO: check rights here
collections = (
session.query(Collection)
.where(
and_(
Collection.createdBy == userslug, Collection.publishedAt != None
)
)
.all()
)
for c in collections:
shouts = (
session.query(ShoutCollection)
.filter(ShoutCollection.collection == c.id)
.all()
)
c.amount = len(shouts)
return collections
@query.field("getMyColelctions")
@login_required
async def get_my_collections(_, info):
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
collections = session.query(Collection).when(Collection.createdBy == user_id).all()
return collections
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
collections = (
session.query(Collection).when(Collection.createdBy == user_id).all()
)
return collections

View File

@@ -7,96 +7,112 @@ from datetime import datetime
from typing import List
from sqlalchemy import and_
@mutation.field("createCommunity")
@login_required
async def create_community(_, info, input):
auth = info.context["request"].auth
user_id = auth.user_id
auth = info.context["request"].auth
user_id = auth.user_id
community = Community.create(
slug = input.get('slug', ''),
title = input.get('title', ''),
desc = input.get('desc', ''),
pic = input.get('pic', '')
)
community = Community.create(
slug=input.get("slug", ""),
title=input.get("title", ""),
desc=input.get("desc", ""),
pic=input.get("pic", ""),
)
return {"community": community}
return {"community": community}
@mutation.field("updateCommunity")
@login_required
async def update_community(_, info, input):
auth = info.context["request"].auth
user_id = auth.user_id
community_slug = input.get('slug', '')
auth = info.context["request"].auth
user_id = auth.user_id
community_slug = input.get("slug", "")
with local_session() as session:
owner = session.query(User).filter(User.id == user_id) # note list here
community = (
session.query(Community).filter(Community.slug == community_slug).first()
)
editors = [e.slug for e in community.editors]
if not community:
return {"error": "invalid community id"}
if community.createdBy not in (owner + editors):
return {"error": "access denied"}
community.title = input.get("title", "")
community.desc = input.get("desc", "")
community.pic = input.get("pic", "")
community.updatedAt = datetime.now()
session.commit()
with local_session() as session:
owner = session.query(User).filter(User.id == user_id) # note list here
community = session.query(Community).filter(Community.slug == community_slug).first()
editors = [e.slug for e in community.editors]
if not community:
return {"error": "invalid community id"}
if community.createdBy not in (owner + editors):
return {"error": "access denied"}
community.title = input.get('title', '')
community.desc = input.get('desc', '')
community.pic = input.get('pic', '')
community.updatedAt = datetime.now()
session.commit()
@mutation.field("deleteCommunity")
@login_required
async def delete_community(_, info, slug):
auth = info.context["request"].auth
user_id = auth.user_id
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
community = session.query(Community).filter(Community.slug == slug).first()
if not community:
return {"error": "invalid community slug"}
if community.owner != user_id:
return {"error": "access denied"}
community.deletedAt = datetime.now()
session.commit()
with local_session() as session:
community = session.query(Community).filter(Community.slug == slug).first()
if not community:
return {"error": "invalid community slug"}
if community.owner != user_id:
return {"error": "access denied"}
community.deletedAt = datetime.now()
session.commit()
return {}
return {}
@query.field("getCommunity")
async def get_community(_, info, slug):
with local_session() as session:
community = session.query(Community).filter(Community.slug == slug).first()
if not community:
return {"error": "invalid community id"}
with local_session() as session:
community = session.query(Community).filter(Community.slug == slug).first()
if not community:
return {"error": "invalid community id"}
return community
return community
@query.field("getCommunities")
async def get_communities(_, info):
with local_session() as session:
communities = session.query(Community)
return communities
with local_session() as session:
communities = session.query(Community)
return communities
def community_follow(user, slug):
CommunityFollower.create(
follower = user.slug,
community = slug
)
CommunityFollower.create(follower=user.slug, community=slug)
def community_unfollow(user, slug):
with local_session() as session:
following = session.query(CommunityFollower).\
filter(and_(CommunityFollower.follower == user.slug, CommunityFollower.community == slug)).\
first()
if not following:
raise Exception("[orm.community] following was not exist")
session.delete(following)
session.commit()
with local_session() as session:
following = (
session.query(CommunityFollower)
.filter(
and_(
CommunityFollower.follower == user.slug,
CommunityFollower.community == slug,
)
)
.first()
)
if not following:
raise Exception("[orm.community] following was not exist")
session.delete(following)
session.commit()
@query.field("userFollowedCommunities")
def get_followed_communities(_, user_slug) -> List[Community]:
ccc = []
with local_session() as session:
ccc = session.query(Community.slug).\
join(CommunityFollower).\
where(CommunityFollower.follower == user_slug).\
all()
return ccc
ccc = []
with local_session() as session:
ccc = (
session.query(Community.slug)
.join(CommunityFollower)
.where(CommunityFollower.follower == user_slug)
.all()
)
return ccc

View File

@@ -13,106 +13,82 @@ from services.zine.gittask import GitTask
@mutation.field("createShout")
@login_required
async def create_shout(_, info, input):
user = info.context["request"].user
user = info.context["request"].user
topic_slugs = input.get("topic_slugs", [])
if topic_slugs:
del input["topic_slugs"]
topic_slugs = input.get("topic_slugs", [])
if topic_slugs:
del input["topic_slugs"]
new_shout = Shout.create(**input)
ShoutAuthor.create(
shout = new_shout.slug,
user = user.slug
)
new_shout = Shout.create(**input)
ShoutAuthor.create(shout=new_shout.slug, user=user.slug)
reactions_follow(user, new_shout.slug, True)
reactions_follow(user, new_shout.slug, True)
if "mainTopic" in input:
topic_slugs.append(input["mainTopic"])
if "mainTopic" in input:
topic_slugs.append(input["mainTopic"])
for slug in topic_slugs:
topic = ShoutTopic.create(
shout = new_shout.slug,
topic = slug)
new_shout.topic_slugs = topic_slugs
for slug in topic_slugs:
topic = ShoutTopic.create(shout=new_shout.slug, topic=slug)
new_shout.topic_slugs = topic_slugs
task = GitTask(
input,
user.username,
user.email,
"new shout %s" % (new_shout.slug)
)
# await ShoutCommentsStorage.send_shout(new_shout)
task = GitTask(input, user.username, user.email, "new shout %s" % (new_shout.slug))
# await ShoutCommentsStorage.send_shout(new_shout)
return {"shout": new_shout}
return {
"shout" : new_shout
}
@mutation.field("updateShout")
@login_required
async def update_shout(_, info, input):
auth = info.context["request"].auth
user_id = auth.user_id
auth = info.context["request"].auth
user_id = auth.user_id
slug = input["slug"]
slug = input["slug"]
session = local_session()
user = session.query(User).filter(User.id == user_id).first()
shout = session.query(Shout).filter(Shout.slug == slug).first()
session = local_session()
user = session.query(User).filter(User.id == user_id).first()
shout = session.query(Shout).filter(Shout.slug == slug).first()
if not shout:
return {
"error" : "shout not found"
}
if not shout:
return {"error": "shout not found"}
authors = [author.id for author in shout.authors]
if not user_id in authors:
scopes = auth.scopes
print(scopes)
if not Resource.shout_id in scopes:
return {
"error" : "access denied"
}
authors = [author.id for author in shout.authors]
if not user_id in authors:
scopes = auth.scopes
print(scopes)
if not Resource.shout_id in scopes:
return {"error": "access denied"}
shout.update(input)
shout.updatedAt = datetime.now()
session.commit()
session.close()
shout.update(input)
shout.updatedAt = datetime.now()
session.commit()
session.close()
for topic in input.get("topic_slugs", []):
ShoutTopic.create(
shout = slug,
topic = topic)
for topic in input.get("topic_slugs", []):
ShoutTopic.create(shout=slug, topic=topic)
task = GitTask(
input,
user.username,
user.email,
"update shout %s" % (slug)
)
task = GitTask(input, user.username, user.email, "update shout %s" % (slug))
return {"shout": shout}
return {
"shout" : shout
}
@mutation.field("deleteShout")
@login_required
async def delete_shout(_, info, slug):
auth = info.context["request"].auth
user_id = auth.user_id
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
shout = session.query(Shout).filter(Shout.slug == slug).first()
authors = [a.id for a in shout.authors]
if not shout:
return {"error": "invalid shout slug"}
if user_id not in authors:
return {"error": "access denied"}
for a in authors:
reactions_unfollow(a.slug, slug, True)
shout.deletedAt = datetime.now()
session.commit()
with local_session() as session:
shout = session.query(Shout).filter(Shout.slug == slug).first()
authors = [a.id for a in shout.authors]
if not shout:
return {"error": "invalid shout slug"}
if user_id not in authors:
return {"error": "access denied"}
for a in authors:
reactions_unfollow(a.slug, slug, True)
shout.deletedAt = datetime.now()
session.commit()
return {}
return {}

View File

@@ -7,36 +7,44 @@ from orm.topic import TopicFollower
from orm.user import AuthorFollower
from typing import List
@query.field("shoutsForFeed")
@login_required
def get_user_feed(_, info, page, size) -> List[Shout]:
user = info.context["request"].user
shouts = []
with local_session() as session:
shouts = session.query(Shout).\
join(ShoutAuthor).\
join(AuthorFollower).\
where(AuthorFollower.follower == user.slug).\
order_by(desc(Shout.createdAt))
topicrows = session.query(Shout).\
join(ShoutTopic).\
join(TopicFollower).\
where(TopicFollower.follower == user.slug).\
order_by(desc(Shout.createdAt))
shouts = shouts.union(topicrows).limit(size).offset(page * size).all()
return shouts
user = info.context["request"].user
shouts = []
with local_session() as session:
shouts = (
session.query(Shout)
.join(ShoutAuthor)
.join(AuthorFollower)
.where(AuthorFollower.follower == user.slug)
.order_by(desc(Shout.createdAt))
)
topicrows = (
session.query(Shout)
.join(ShoutTopic)
.join(TopicFollower)
.where(TopicFollower.follower == user.slug)
.order_by(desc(Shout.createdAt))
)
shouts = shouts.union(topicrows).limit(size).offset(page * size).all()
return shouts
@query.field("myCandidates")
@login_required
async def user_unpublished_shouts(_, info, page = 1, size = 10) -> List[Shout]:
user = info.context["request"].user
shouts = []
with local_session() as session:
shouts = session.query(Shout).\
join(ShoutAuthor).\
where(and_(Shout.publishedAt == None, ShoutAuthor.user == user.slug)).\
order_by(desc(Shout.createdAt)).\
limit(size).\
offset( page * size).\
all()
return shouts
async def user_unpublished_shouts(_, info, page=1, size=10) -> List[Shout]:
user = info.context["request"].user
shouts = []
with local_session() as session:
shouts = (
session.query(Shout)
.join(ShoutAuthor)
.where(and_(Shout.publishedAt == None, ShoutAuthor.user == user.slug))
.order_by(desc(Shout.createdAt))
.limit(size)
.offset(page * size)
.all()
)
return shouts

View File

@@ -4,263 +4,283 @@ import asyncio, uuid, json
from datetime import datetime
from base.redis import redis
class ChatFollowing:
queue = asyncio.Queue()
def __init__(self, chat_id):
self.chat_id = chat_id
class ChatFollowing:
queue = asyncio.Queue()
def __init__(self, chat_id):
self.chat_id = chat_id
class MessagesStorage:
lock = asyncio.Lock()
chats = []
lock = asyncio.Lock()
chats = []
@staticmethod
async def register_chat(chat):
async with MessagesStorage.lock:
MessagesStorage.chats.append(chat)
@staticmethod
async def remove_chat(chat):
async with MessagesStorage.lock:
MessagesStorage.chats.remove(chat)
@staticmethod
async def put(message_result):
async with MessagesStorage.lock:
for chat in MessagesStorage.chats:
if message_result.message["chatId"] == chat.chat_id:
chat.queue.put_nowait(message_result)
@staticmethod
async def register_chat(chat):
async with MessagesStorage.lock:
MessagesStorage.chats.append(chat)
@staticmethod
async def remove_chat(chat):
async with MessagesStorage.lock:
MessagesStorage.chats.remove(chat)
@staticmethod
async def put(message_result):
async with MessagesStorage.lock:
for chat in MessagesStorage.chats:
if message_result.message["chatId"] == chat.chat_id:
chat.queue.put_nowait(message_result)
class MessageResult:
def __init__(self, status, message):
self.status = status
self.message = message
def __init__(self, status, message):
self.status = status
self.message = message
async def get_unread_counter(user_slug):
chats = await redis.execute("GET", f"chats_by_user/{user_slug}")
if not chats:
return 0
chats = await redis.execute("GET", f"chats_by_user/{user_slug}")
if not chats:
return 0
chats = json.loads(chats)
unread = 0
for chat_id in chats:
n = await redis.execute("LLEN", f"chats/{chat_id}/unread/{user_slug}")
unread += n
chats = json.loads(chats)
unread = 0
for chat_id in chats:
n = await redis.execute("LLEN", f"chats/{chat_id}/unread/{user_slug}")
unread += n
return unread
return unread
async def add_user_to_chat(user_slug, chat_id, chat = None):
chats = await redis.execute("GET", f"chats_by_user/{user_slug}")
if not chats:
chats = set()
else:
chats = set(json.loads(chats))
chats.add(str(chat_id))
chats = list(chats)
await redis.execute("SET", f"chats_by_user/{user_slug}", json.dumps(chats))
if chat:
users = set(chat["users"])
users.add(user_slug)
chat["users"] = list(users)
await redis.execute("SET", f"chats/{chat_id}", json.dumps(chat))
async def add_user_to_chat(user_slug, chat_id, chat=None):
chats = await redis.execute("GET", f"chats_by_user/{user_slug}")
if not chats:
chats = set()
else:
chats = set(json.loads(chats))
chats.add(str(chat_id))
chats = list(chats)
await redis.execute("SET", f"chats_by_user/{user_slug}", json.dumps(chats))
if chat:
users = set(chat["users"])
users.add(user_slug)
chat["users"] = list(users)
await redis.execute("SET", f"chats/{chat_id}", json.dumps(chat))
@mutation.field("createChat")
@login_required
async def create_chat(_, info, description):
user = info.context["request"].user
user = info.context["request"].user
chat_id = uuid.uuid4()
chat = {
"description" : description,
"createdAt" : str(datetime.now),
"createdBy" : user.slug,
"id" : str(chat_id),
"users" : [user.slug]
}
chat_id = uuid.uuid4()
chat = {
"description": description,
"createdAt": str(datetime.now),
"createdBy": user.slug,
"id": str(chat_id),
"users": [user.slug],
}
await redis.execute("SET", f"chats/{chat_id}", json.dumps(chat))
await redis.execute("SET", f"chats/{chat_id}/next_message_id", 0)
await redis.execute("SET", f"chats/{chat_id}", json.dumps(chat))
await redis.execute("SET", f"chats/{chat_id}/next_message_id", 0)
await add_user_to_chat(user.slug, chat_id)
await add_user_to_chat(user.slug, chat_id)
return {"chatId": chat_id}
return { "chatId" : chat_id }
async def load_messages(chatId, size, page):
message_ids = await redis.lrange(f"chats/{chatId}/message_ids",
size * (page -1), size * page - 1)
messages = []
if message_ids:
message_keys = [f"chats/{chatId}/messages/{id.decode('UTF-8')}" for id in message_ids]
messages = await redis.mget(*message_keys)
messages = [json.loads(msg) for msg in messages]
return messages
message_ids = await redis.lrange(
f"chats/{chatId}/message_ids", size * (page - 1), size * page - 1
)
messages = []
if message_ids:
message_keys = [
f"chats/{chatId}/messages/{id.decode('UTF-8')}" for id in message_ids
]
messages = await redis.mget(*message_keys)
messages = [json.loads(msg) for msg in messages]
return messages
@query.field("userChats")
@login_required
async def user_chats(_, info):
user = info.context["request"].user
user = info.context["request"].user
chats = await redis.execute("GET", f"chats_by_user/{user.slug}")
if not chats:
chats = list()
else:
chats = list(json.loads(chats))
chats = await redis.execute("GET", f"chats_by_user/{user.slug}")
if not chats:
chats = list()
else:
chats = list(json.loads(chats))
return {"chats": chats}
return {"chats" : chats}
@query.field("enterChat")
@login_required
async def enter_chat(_, info, chatId, size):
user = info.context["request"].user
user = info.context["request"].user
chat = await redis.execute("GET", f"chats/{chatId}")
if not chat:
return { "error" : "chat not exist" }
chat = json.loads(chat)
chat = await redis.execute("GET", f"chats/{chatId}")
if not chat:
return {"error": "chat not exist"}
chat = json.loads(chat)
messages = await load_messages(chatId, size, 1)
messages = await load_messages(chatId, size, 1)
await add_user_to_chat(user.slug, chatId, chat)
await add_user_to_chat(user.slug, chatId, chat)
return {"chat": chat, "messages": messages}
return {
"chat" : chat,
"messages" : messages
}
@mutation.field("createMessage")
@login_required
async def create_message(_, info, chatId, body, replyTo = None):
user = info.context["request"].user
async def create_message(_, info, chatId, body, replyTo=None):
user = info.context["request"].user
chat = await redis.execute("GET", f"chats/{chatId}")
if not chat:
return { "error" : "chat not exist" }
chat = await redis.execute("GET", f"chats/{chatId}")
if not chat:
return {"error": "chat not exist"}
message_id = await redis.execute("GET", f"chats/{chatId}/next_message_id")
message_id = int(message_id)
message_id = await redis.execute("GET", f"chats/{chatId}/next_message_id")
message_id = int(message_id)
new_message = {
"chatId" : chatId,
"id" : message_id,
"author" : user.slug,
"body" : body,
"replyTo" : replyTo,
"createdAt" : datetime.now().isoformat()
}
new_message = {
"chatId": chatId,
"id": message_id,
"author": user.slug,
"body": body,
"replyTo": replyTo,
"createdAt": datetime.now().isoformat(),
}
await redis.execute("SET", f"chats/{chatId}/messages/{message_id}", json.dumps(new_message))
await redis.execute("LPUSH", f"chats/{chatId}/message_ids", str(message_id))
await redis.execute("SET", f"chats/{chatId}/next_message_id", str(message_id + 1))
await redis.execute(
"SET", f"chats/{chatId}/messages/{message_id}", json.dumps(new_message)
)
await redis.execute("LPUSH", f"chats/{chatId}/message_ids", str(message_id))
await redis.execute("SET", f"chats/{chatId}/next_message_id", str(message_id + 1))
chat = json.loads(chat)
users = chat["users"]
for user_slug in users:
await redis.execute("LPUSH", f"chats/{chatId}/unread/{user_slug}", str(message_id))
chat = json.loads(chat)
users = chat["users"]
for user_slug in users:
await redis.execute(
"LPUSH", f"chats/{chatId}/unread/{user_slug}", str(message_id)
)
result = MessageResult("NEW", new_message)
await MessagesStorage.put(result)
result = MessageResult("NEW", new_message)
await MessagesStorage.put(result)
return {"message": new_message}
return {"message" : new_message}
@query.field("getMessages")
@login_required
async def get_messages(_, info, chatId, size, page):
chat = await redis.execute("GET", f"chats/{chatId}")
if not chat:
return { "error" : "chat not exist" }
chat = await redis.execute("GET", f"chats/{chatId}")
if not chat:
return {"error": "chat not exist"}
messages = await load_messages(chatId, size, page)
messages = await load_messages(chatId, size, page)
return messages
return messages
@mutation.field("updateMessage")
@login_required
async def update_message(_, info, chatId, id, body):
user = info.context["request"].user
user = info.context["request"].user
chat = await redis.execute("GET", f"chats/{chatId}")
if not chat:
return { "error" : "chat not exist" }
chat = await redis.execute("GET", f"chats/{chatId}")
if not chat:
return {"error": "chat not exist"}
message = await redis.execute("GET", f"chats/{chatId}/messages/{id}")
if not message:
return { "error" : "message not exist" }
message = await redis.execute("GET", f"chats/{chatId}/messages/{id}")
if not message:
return {"error": "message not exist"}
message = json.loads(message)
if message["author"] != user.slug:
return { "error" : "access denied" }
message = json.loads(message)
if message["author"] != user.slug:
return {"error": "access denied"}
message["body"] = body
message["updatedAt"] = datetime.now().isoformat()
message["body"] = body
message["updatedAt"] = datetime.now().isoformat()
await redis.execute("SET", f"chats/{chatId}/messages/{id}", json.dumps(message))
await redis.execute("SET", f"chats/{chatId}/messages/{id}", json.dumps(message))
result = MessageResult("UPDATED", message)
await MessagesStorage.put(result)
result = MessageResult("UPDATED", message)
await MessagesStorage.put(result)
return {"message": message}
return {"message" : message}
@mutation.field("deleteMessage")
@login_required
async def delete_message(_, info, chatId, id):
user = info.context["request"].user
user = info.context["request"].user
chat = await redis.execute("GET", f"chats/{chatId}")
if not chat:
return { "error" : "chat not exist" }
chat = await redis.execute("GET", f"chats/{chatId}")
if not chat:
return {"error": "chat not exist"}
message = await redis.execute("GET", f"chats/{chatId}/messages/{id}")
if not message:
return { "error" : "message not exist" }
message = json.loads(message)
if message["author"] != user.slug:
return { "error" : "access denied" }
message = await redis.execute("GET", f"chats/{chatId}/messages/{id}")
if not message:
return {"error": "message not exist"}
message = json.loads(message)
if message["author"] != user.slug:
return {"error": "access denied"}
await redis.execute("LREM", f"chats/{chatId}/message_ids", 0, str(id))
await redis.execute("DEL", f"chats/{chatId}/messages/{id}")
await redis.execute("LREM", f"chats/{chatId}/message_ids", 0, str(id))
await redis.execute("DEL", f"chats/{chatId}/messages/{id}")
chat = json.loads(chat)
users = chat["users"]
for user_slug in users:
await redis.execute("LREM", f"chats/{chatId}/unread/{user_slug}", 0, str(id))
chat = json.loads(chat)
users = chat["users"]
for user_slug in users:
await redis.execute("LREM", f"chats/{chatId}/unread/{user_slug}", 0, str(id))
result = MessageResult("DELETED", message)
await MessagesStorage.put(result)
result = MessageResult("DELETED", message)
await MessagesStorage.put(result)
return {}
return {}
@mutation.field("markAsRead")
@login_required
async def mark_as_read(_, info, chatId, ids):
user = info.context["request"].user
user = info.context["request"].user
chat = await redis.execute("GET", f"chats/{chatId}")
if not chat:
return { "error" : "chat not exist" }
chat = await redis.execute("GET", f"chats/{chatId}")
if not chat:
return {"error": "chat not exist"}
chat = json.loads(chat)
users = set(chat["users"])
if not user.slug in users:
return { "error" : "access denied" }
chat = json.loads(chat)
users = set(chat["users"])
if not user.slug in users:
return {"error": "access denied"}
for id in ids:
await redis.execute("LREM", f"chats/{chatId}/unread/{user.slug}", 0, str(id))
for id in ids:
await redis.execute("LREM", f"chats/{chatId}/unread/{user.slug}", 0, str(id))
return {}
return {}
@subscription.source("chatUpdated")
@login_required
async def message_generator(obj, info, chatId):
try:
following_chat = ChatFollowing(chatId)
await MessagesStorage.register_chat(following_chat)
while True:
msg = await following_chat.queue.get()
yield msg
finally:
await MessagesStorage.remove_chat(following_chat)
try:
following_chat = ChatFollowing(chatId)
await MessagesStorage.register_chat(following_chat)
while True:
msg = await following_chat.queue.get()
yield msg
finally:
await MessagesStorage.remove_chat(following_chat)
@subscription.field("chatUpdated")
def message_resolver(message, info, chatId):
return message
return message

View File

@@ -14,154 +14,176 @@ from sqlalchemy import and_, desc
from sqlalchemy.orm import selectinload
from typing import List
@query.field("userReactedShouts")
async def get_user_reacted_shouts(_, info, slug, page, size) -> List[Shout]:
user = await UserStorage.get_user_by_slug(slug)
if not user: return {}
with local_session() as session:
shouts = session.query(Shout).\
join(Reaction).\
where(Reaction.createdBy == user.slug).\
order_by(desc(Reaction.createdAt)).\
limit(size).\
offset(page * size).all()
return shouts
user = await UserStorage.get_user_by_slug(slug)
if not user:
return []
with local_session() as session:
shouts = (
session.query(Shout)
.join(Reaction)
.where(Reaction.createdBy == user.slug)
.order_by(desc(Reaction.createdAt))
.limit(size)
.offset(page * size)
.all()
)
return shouts
@query.field("userFollowedTopics")
@login_required
def get_followed_topics(_, slug) -> List[Topic]:
rows = []
with local_session() as session:
rows = session.query(Topic).\
join(TopicFollower).\
where(TopicFollower.follower == slug).\
all()
return rows
rows = []
with local_session() as session:
rows = (
session.query(Topic)
.join(TopicFollower)
.where(TopicFollower.follower == slug)
.all()
)
return rows
@query.field("userFollowedAuthors")
def get_followed_authors(_, slug) -> List[User]:
authors = []
with local_session() as session:
authors = session.query(User).\
join(AuthorFollower, User.slug == AuthorFollower.author).\
where(AuthorFollower.follower == slug).\
all()
return authors
authors = []
with local_session() as session:
authors = (
session.query(User)
.join(AuthorFollower, User.slug == AuthorFollower.author)
.where(AuthorFollower.follower == slug)
.all()
)
return authors
@query.field("userFollowers")
async def user_followers(_, slug) -> List[User]:
with local_session() as session:
users = session.query(User).\
join(AuthorFollower, User.slug == AuthorFollower.follower).\
where(AuthorFollower.author == slug).\
all()
return users
with local_session() as session:
users = (
session.query(User)
.join(AuthorFollower, User.slug == AuthorFollower.follower)
.where(AuthorFollower.author == slug)
.all()
)
return users
# for mutation.field("refreshSession")
async def get_user_info(slug):
return {
"unread": await get_unread_counter(slug),
"topics": [t.slug for t in get_followed_topics(0, slug)],
"authors": [a.slug for a in get_followed_authors(0, slug)],
"reactions": [r.shout for r in get_shout_reactions(0, slug)],
"communities": [c.slug for c in get_followed_communities(0, slug)]
}
return {
"unread": await get_unread_counter(slug),
"topics": [t.slug for t in get_followed_topics(0, slug)],
"authors": [a.slug for a in get_followed_authors(0, slug)],
"reactions": [r.shout for r in get_shout_reactions(0, slug)],
"communities": [c.slug for c in get_followed_communities(0, slug)],
}
@mutation.field("refreshSession")
@login_required
async def get_current_user(_, info):
user = info.context["request"].user
with local_session() as session:
user.lastSeen = datetime.now()
user.save()
session.commit()
return {
"token": "", # same token?
"user": user,
"info": await get_user_info(user.slug)
}
user = info.context["request"].user
with local_session() as session:
user.lastSeen = datetime.now()
user.save()
session.commit()
return {
"token": "", # same token?
"user": user,
"info": await get_user_info(user.slug),
}
@query.field("getUsersBySlugs")
async def get_users_by_slugs(_, info, slugs):
with local_session() as session:
users = session.query(User).\
options(selectinload(User.ratings)).\
filter(User.slug.in_(slugs)).all()
return users
with local_session() as session:
users = (
session.query(User)
.options(selectinload(User.ratings))
.filter(User.slug in slugs)
.all()
)
return users
@query.field("getUserRoles")
async def get_user_roles(_, info, slug):
with local_session() as session:
user = session.query(User).where(User.slug == slug).first()
roles = session.query(Role).\
options(selectinload(Role.permissions)).\
join(UserRole).\
where(UserRole.user_id == user.id).all()
return roles
with local_session() as session:
user = session.query(User).where(User.slug == slug).first()
roles = (
session.query(Role)
.options(selectinload(Role.permissions))
.join(UserRole)
.where(UserRole.user_id == user.id)
.all()
)
return roles
@mutation.field("updateProfile")
@login_required
async def update_profile(_, info, profile):
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
user = session.query(User).filter(User.id == user_id).first()
user.update(profile)
session.commit()
return {}
auth = info.context["request"].auth
user_id = auth.user_id
with local_session() as session:
user = session.query(User).filter(User.id == user_id).first()
if user:
User.update(user, **profile)
session.commit()
return {}
@mutation.field("rateUser")
@login_required
async def rate_user(_, info, slug, value):
user = info.context["request"].user
with local_session() as session:
rating = session.query(UserRating).\
filter(and_(UserRating.rater == user.slug, UserRating.user == slug)).\
first()
if rating:
rating.value = value
session.commit()
return {}
try:
UserRating.create(
rater=user.slug,
user=slug,
value=value
)
except Exception as err:
return {"error": err}
return {}
user = info.context["request"].user
with local_session() as session:
rating = (
session.query(UserRating)
.filter(and_(UserRating.rater == user.slug, UserRating.user == slug))
.first()
)
if rating:
rating.value = value
session.commit()
return {}
try:
UserRating.create(rater=user.slug, user=slug, value=value)
except Exception as err:
return {"error": err}
return {}
# for mutation.field("follow")
def author_follow(user, slug):
AuthorFollower.create(
follower=user.slug,
author=slug
)
AuthorFollower.create(follower=user.slug, author=slug)
# for mutation.field("unfollow")
def author_unfollow(user, slug):
with local_session() as session:
flw = session.query(AuthorFollower).\
filter(and_(AuthorFollower.follower == user.slug, AuthorFollower.author == slug)).\
first()
if not flw:
raise Exception("[resolvers.profile] follower not exist, cant unfollow")
else:
session.delete(flw)
session.commit()
with local_session() as session:
flw = (
session.query(AuthorFollower)
.filter(
and_(
AuthorFollower.follower == user.slug, AuthorFollower.author == slug
)
)
.first()
)
if not flw:
raise Exception("[resolvers.profile] follower not exist, cant unfollow")
else:
session.delete(flw)
session.commit()
@query.field("authorsAll")
def get_authors_all(_, info, page, size):
end = page * size
start = end - size
return UserStorage.get_all_users()[start:end]
end = page * size
start = end - size
return list(UserStorage.get_all_users())[start:end] # type: ignore

View File

@@ -10,11 +10,17 @@ from datetime import datetime
from services.auth.users import UserStorage
from services.stat.reacted import ReactedStorage
def reactions_follow(user, slug, auto=False):
with local_session() as session:
fw = session.query(ShoutReactionsFollower).\
filter(ShoutReactionsFollower.follower == user.slug, ShoutReactionsFollower.shout == slug).\
first()
fw = (
session.query(ShoutReactionsFollower)
.filter(
ShoutReactionsFollower.follower == user.slug,
ShoutReactionsFollower.shout == slug,
)
.first()
)
if auto and fw:
return
elif not auto and fw:
@@ -25,17 +31,19 @@ def reactions_follow(user, slug, auto=False):
return
# print("[resolvers.reactions] was followed before")
ShoutReactionsFollower.create(
follower=user.slug,
shout=slug,
auto=auto)
ShoutReactionsFollower.create(follower=user.slug, shout=slug, auto=auto)
def reactions_unfollow(user, slug):
with local_session() as session:
following = session.query(ShoutReactionsFollower).\
filter(ShoutReactionsFollower.follower == user.slug, ShoutReactionsFollower.shout == slug).\
first()
following = (
session.query(ShoutReactionsFollower)
.filter(
ShoutReactionsFollower.follower == user.slug,
ShoutReactionsFollower.shout == slug,
)
.first()
)
if not following:
# print("[resolvers.reactions] was not followed", slug)
return
@@ -56,7 +64,7 @@ async def create_reaction(_, info, inp):
reaction = Reaction.create(**inp)
ReactedStorage.increment(reaction.shout, reaction.replyTo)
try:
reactions_follow(user, inp['shout'], True)
reactions_follow(user, inp["shout"], True)
except Exception as e:
print(f"[resolvers.reactions] error on reactions autofollowing: {e}")
@@ -76,13 +84,13 @@ async def update_reaction(_, info, inp):
return {"error": "invalid reaction id"}
if reaction.createdBy != user.slug:
return {"error": "access denied"}
reaction.body = inp['body']
reaction.body = inp["body"]
reaction.updatedAt = datetime.now()
if reaction.kind != inp['kind']:
if reaction.kind != inp["kind"]:
# NOTE: change mind detection can be here
pass
if inp.get('range'):
reaction.range = inp.get('range')
if inp.get("range"):
reaction.range = inp.get("range")
session.commit()
return {"reaction": reaction}
@@ -104,29 +112,39 @@ async def delete_reaction(_, info, id):
session.commit()
return {}
@query.field("reactionsByShout")
async def get_shout_reactions(_, info, slug, page, size):
offset = page * size
reactions = []
with local_session() as session:
reactions = session.query(Reaction).\
filter(Reaction.shout == slug).\
limit(size).offset(offset).all()
reactions = (
session.query(Reaction)
.filter(Reaction.shout == slug)
.limit(size)
.offset(offset)
.all()
)
for r in reactions:
r.createdBy = await UserStorage.get_user(r.createdBy or 'discours')
r.createdBy = await UserStorage.get_user(r.createdBy or "discours")
return reactions
@query.field("reactionsForSlugs")
async def get_shout_reactions(_, info, slugs, page, size):
offset = page * size
reactions = []
with local_session() as session:
for slug in slugs:
reactions += session.query(Reaction).\
filter(Reaction.shout == slug).\
limit(size).offset(offset).all()
for slug in slugs:
reactions += (
session.query(Reaction)
.filter(Reaction.shout == slug)
.limit(size)
.offset(offset)
.all()
)
for r in reactions:
r.createdBy = await UserStorage.get_user(r.createdBy or 'discours')
r.createdBy = await UserStorage.get_user(r.createdBy or "discours")
return reactions
@@ -135,22 +153,31 @@ async def get_all_reactions(_, info, page=1, size=10):
offset = page * size
reactions = []
with local_session() as session:
reactions = session.query(Reaction).\
filter(Reaction.deletedAt == None).\
order_by(desc("createdAt")).\
offset(offset).limit(size)
reactions = (
session.query(Reaction)
.filter(Reaction.deletedAt == None)
.order_by(desc("createdAt"))
.offset(offset)
.limit(size)
)
for r in reactions:
r.createdBy = await UserStorage.get_user(r.createdBy or 'discours')
r.createdBy = await UserStorage.get_user(r.createdBy or "discours")
reactions = list(reactions)
reactions.sort(key=lambda x: x.createdAt, reverse=True)
return reactions
@query.field("reactionsByAuthor")
async def get_reactions_by_author(_, info, slug, page=1, size=50):
offset = page * size
reactions = []
with local_session() as session:
reactions = session.query(Reaction).filter(Reaction.createdBy == slug).limit(size).offset(offset)
reactions = (
session.query(Reaction)
.filter(Reaction.createdBy == slug)
.limit(size)
.offset(offset)
)
for r in reactions:
r.createdBy = await UserStorage.get_user(r.createdBy or 'discours')
r.createdBy = await UserStorage.get_user(r.createdBy or "discours")
return reactions

View File

@@ -8,68 +8,76 @@ from base.resolvers import mutation, query
from auth.authenticate import login_required
from sqlalchemy import and_
@query.field("topicsAll")
async def topics_all(_, info, page = 1, size = 50):
topics = await TopicStorage.get_topics_all(page, size)
for topic in topics:
topic.stat = await TopicStat.get_stat(topic.slug)
return topics
async def topics_all(_, info, page=1, size=50):
topics = await TopicStorage.get_topics_all(page, size)
for topic in topics:
topic.stat = await TopicStat.get_stat(topic.slug)
return topics
@query.field("topicsByCommunity")
async def topics_by_community(_, info, community):
topics = await TopicStorage.get_topics_by_community(community)
for topic in topics:
topic.stat = await TopicStat.get_stat(topic.slug)
return topics
topics = await TopicStorage.get_topics_by_community(community)
for topic in topics:
topic.stat = await TopicStat.get_stat(topic.slug)
return topics
@query.field("topicsByAuthor")
async def topics_by_author(_, info, author):
slugs = set()
with local_session() as session:
shouts = session.query(Shout).\
filter(Shout.authors.any(User.slug == author))
for shout in shouts:
slugs.update([topic.slug for topic in shout.topics])
return await TopicStorage.get_topics(slugs)
slugs = set()
with local_session() as session:
shouts = session.query(Shout).filter(Shout.authors.any(User.slug == author))
for shout in shouts:
slugs.update([topic.slug for topic in shout.topics])
return await TopicStorage.get_topics(slugs)
@mutation.field("createTopic")
@login_required
async def create_topic(_, info, input):
new_topic = Topic.create(**input)
await TopicStorage.add_topic(new_topic)
new_topic = Topic.create(**input)
await TopicStorage.add_topic(new_topic)
return {"topic": new_topic}
return { "topic" : new_topic }
@mutation.field("updateTopic")
@login_required
async def update_topic(_, info, input):
slug = input["slug"]
slug = input["slug"]
session = local_session()
topic = session.query(Topic).filter(Topic.slug == slug).first()
session = local_session()
topic = session.query(Topic).filter(Topic.slug == slug).first()
if not topic:
return { "error" : "topic not found" }
if not topic:
return {"error": "topic not found"}
topic.update(input)
session.commit()
session.close()
topic.update(input)
session.commit()
session.close()
await TopicStorage.add_topic(topic)
await TopicStorage.add_topic(topic)
return {"topic": topic}
return { "topic" : topic }
def topic_follow(user, slug):
TopicFollower.create(
follower = user.slug,
topic = slug)
TopicFollower.create(follower=user.slug, topic=slug)
def topic_unfollow(user, slug):
with local_session() as session:
sub = session.query(TopicFollower).\
filter(and_(TopicFollower.follower == user.slug, TopicFollower.topic == slug)).\
first()
if not sub:
raise Exception("[resolvers.topics] follower not exist")
session.delete(sub)
session.commit()
with local_session() as session:
sub = (
session.query(TopicFollower)
.filter(
and_(TopicFollower.follower == user.slug, TopicFollower.topic == slug)
)
.first()
)
if not sub:
raise Exception("[resolvers.topics] follower not exist")
session.delete(sub)
session.commit()

View File

@@ -13,138 +13,171 @@ from resolvers.reactions import reactions_follow, reactions_unfollow
from auth.authenticate import login_required
from sqlalchemy import select, desc, and_, text
from sqlalchemy.orm import selectinload
from sqlalchemy.dialects import postgresql
@query.field("topViewed")
async def top_viewed(_, info, page, size):
async with ShoutsCache.lock:
return ShoutsCache.top_viewed[(page - 1) * size : page * size]
@query.field("topMonth")
async def top_month(_, info, page, size):
async with ShoutsCache.lock:
return ShoutsCache.top_month[(page - 1) * size : page * size]
@query.field("topOverall")
async def top_overall(_, info, page, size):
async with ShoutsCache.lock:
return ShoutsCache.top_overall[(page - 1) * size : page * size]
@query.field("recentPublished")
async def recent_published(_, info, page, size):
async with ShoutsCache.lock:
return ShoutsCache.recent_published[(page - 1) * size : page * size]
@query.field("recentAll")
async def recent_all(_, info, page, size):
async with ShoutsCache.lock:
return ShoutsCache.recent_all[(page - 1) * size : page * size]
@query.field("recentReacted")
async def recent_reacted(_, info, page, size):
async with ShoutsCache.lock:
return ShoutsCache.recent_reacted[(page - 1) * size : page * size]
@mutation.field("viewShout")
async def view_shout(_, info, slug):
await ViewedStorage.inc_shout(slug)
return {"error" : ""}
return {"error": ""}
@query.field("getShoutBySlug")
async def get_shout_by_slug(_, info, slug):
all_fields = [node.name.value for node in info.field_nodes[0].selection_set.selections]
all_fields = [
node.name.value for node in info.field_nodes[0].selection_set.selections
]
selected_fields = set(["authors", "topics"]).intersection(all_fields)
select_options = [selectinload(getattr(Shout, field)) for field in selected_fields]
shout = {}
with local_session() as session:
try: s = text(open('src/queries/shout-by-slug.sql', 'r').read() % slug)
except: pass
shout = session.query(Shout).\
options(select_options).\
filter(Shout.slug == slug).first()
try:
s = text(open("src/queries/shout-by-slug.sql", "r").read() % slug)
except:
pass
shout = (
session.query(Shout)
.options(select_options)
.filter(Shout.slug == slug)
.first()
)
if not shout:
print(f"shout with slug {slug} not exist")
return {"error" : "shout not found"}
return {"error": "shout not found"}
else:
for a in shout.authors:
a.caption = await ShoutAuthorStorage.get_author_caption(slug, a.slug)
return shout
@query.field("shoutsByTopics")
async def shouts_by_topics(_, info, slugs, page, size):
page = page - 1
with local_session() as session:
shouts = session.query(Shout).\
join(ShoutTopic).\
where(and_(ShoutTopic.topic.in_(slugs), Shout.publishedAt != None)).\
order_by(desc(Shout.publishedAt)).\
limit(size).\
offset(page * size)
shouts = (
session.query(Shout)
.join(ShoutTopic)
.where(and_(ShoutTopic.topic.in_(slugs), Shout.publishedAt != None))
.order_by(desc(Shout.publishedAt))
.limit(size)
.offset(page * size)
)
for s in shouts:
for a in s.authors:
a.caption = await ShoutAuthorStorage.get_author_caption(s.slug, a.slug)
return shouts
@query.field("shoutsByCollection")
async def shouts_by_topics(_, info, collection, page, size):
page = page - 1
shouts = []
with local_session() as session:
shouts = session.query(Shout).\
join(ShoutCollection, ShoutCollection.collection == collection).\
where(and_(ShoutCollection.shout == Shout.slug, Shout.publishedAt != None)).\
order_by(desc(Shout.publishedAt)).\
limit(size).\
offset(page * size)
shouts = (
session.query(Shout)
.join(ShoutCollection, ShoutCollection.collection == collection)
.where(and_(ShoutCollection.shout == Shout.slug, Shout.publishedAt != None))
.order_by(desc(Shout.publishedAt))
.limit(size)
.offset(page * size)
)
for s in shouts:
for a in s.authors:
a.caption = await ShoutAuthorStorage.get_author_caption(s.slug, a.slug)
return shouts
@query.field("shoutsByAuthors")
async def shouts_by_authors(_, info, slugs, page, size):
page = page - 1
with local_session() as session:
shouts = session.query(Shout).\
join(ShoutAuthor).\
where(and_(ShoutAuthor.user.in_(slugs), Shout.publishedAt != None)).\
order_by(desc(Shout.publishedAt)).\
limit(size).\
offset(page * size)
shouts = (
session.query(Shout)
.join(ShoutAuthor)
.where(and_(ShoutAuthor.user.in_(slugs), Shout.publishedAt != None))
.order_by(desc(Shout.publishedAt))
.limit(size)
.offset(page * size)
)
for s in shouts:
for a in s.authors:
a.caption = await ShoutAuthorStorage.get_author_caption(s.slug, a.slug)
return shouts
SINGLE_COMMUNITY = True
@query.field("shoutsByCommunities")
async def shouts_by_communities(_, info, slugs, page, size):
if SINGLE_COMMUNITY:
if SINGLE_COMMUNITY:
return recent_published(_, info, page, size)
else:
page = page - 1
with local_session() as session:
#TODO fix postgres high load
shouts = session.query(Shout).distinct().\
join(ShoutTopic).\
where(and_(Shout.publishedAt != None,\
ShoutTopic.topic.in_(\
select(Topic.slug).where(Topic.community.in_(slugs))\
))).\
order_by(desc(Shout.publishedAt)).\
limit(size).\
offset(page * size)
# TODO fix postgres high load
shouts = (
session.query(Shout)
.distinct()
.join(ShoutTopic)
.where(
and_(
Shout.publishedAt != None,
ShoutTopic.topic.in_(
select(Topic.slug).where(Topic.community.in_(slugs))
),
)
)
.order_by(desc(Shout.publishedAt))
.limit(size)
.offset(page * size)
)
for s in shouts:
for a in s.authors:
a.caption = await ShoutAuthorStorage.get_author_caption(s.slug, a.slug)
return shouts
@mutation.field("follow")
@login_required
async def follow(_, info, what, slug):
@@ -159,10 +192,11 @@ async def follow(_, info, what, slug):
elif what == "REACTIONS":
reactions_follow(user, slug)
except Exception as e:
return {"error" : str(e)}
return {"error": str(e)}
return {}
@mutation.field("unfollow")
@login_required
async def unfollow(_, info, what, slug):
@@ -178,6 +212,6 @@ async def unfollow(_, info, what, slug):
elif what == "REACTIONS":
reactions_unfollow(user, slug)
except Exception as e:
return {"error" : str(e)}
return {"error": str(e)}
return {}