Merge branch 'prealpha' into main
This commit is contained in:
commit
50b2ae4154
|
@ -9,7 +9,7 @@ from starlette.requests import HTTPConnection
|
|||
|
||||
from auth.credentials import AuthCredentials, AuthUser
|
||||
from base.orm import local_session
|
||||
from orm.user import User, Role, UserRole
|
||||
from orm.user import User, Role
|
||||
|
||||
from settings import SESSION_TOKEN_HEADER
|
||||
from auth.tokenstorage import SessionToken
|
||||
|
@ -39,12 +39,14 @@ class JWTAuthenticate(AuthenticationBackend):
|
|||
user = None
|
||||
with local_session() as session:
|
||||
try:
|
||||
q = select(
|
||||
User
|
||||
).filter(
|
||||
User.id == payload.user_id
|
||||
).select_from(User)
|
||||
user = session.execute(q).unique().one()
|
||||
user = (
|
||||
session.query(User).options(
|
||||
joinedload(User.roles).options(joinedload(Role.permissions)),
|
||||
joinedload(User.ratings)
|
||||
).filter(
|
||||
User.id == payload.user_id
|
||||
).one()
|
||||
)
|
||||
except exc.NoResultFound:
|
||||
user = None
|
||||
|
||||
|
@ -59,7 +61,7 @@ class JWTAuthenticate(AuthenticationBackend):
|
|||
scopes=scopes,
|
||||
logged_in=True
|
||||
),
|
||||
user,
|
||||
AuthUser(user_id=user.id),
|
||||
)
|
||||
else:
|
||||
InvalidToken("please try again")
|
||||
|
|
|
@ -10,7 +10,7 @@ lang_subject = {
|
|||
}
|
||||
|
||||
|
||||
async def send_auth_email(user, token, template="email_confirmation", lang="ru"):
|
||||
async def send_auth_email(user, token, lang="ru", template="email_confirmation"):
|
||||
try:
|
||||
to = "%s <%s>" % (user.name, user.email)
|
||||
if lang not in ['ru', 'en']:
|
||||
|
|
2
main.py
2
main.py
|
@ -41,6 +41,7 @@ async def start_up():
|
|||
|
||||
async def dev_start_up():
|
||||
if exists(DEV_SERVER_STATUS_FILE_NAME):
|
||||
await redis.connect()
|
||||
return
|
||||
else:
|
||||
with open(DEV_SERVER_STATUS_FILE_NAME, 'w', encoding='utf-8') as f:
|
||||
|
@ -71,6 +72,7 @@ app.mount("/", GraphQL(schema, debug=True))
|
|||
dev_app = app = Starlette(
|
||||
debug=True,
|
||||
on_startup=[dev_start_up],
|
||||
on_shutdown=[shutdown],
|
||||
middleware=middleware,
|
||||
routes=routes,
|
||||
)
|
||||
|
|
|
@ -9,7 +9,6 @@ from orm.shout import ShoutReactionsFollower
|
|||
from orm.topic import TopicFollower
|
||||
from orm.user import User
|
||||
from orm.shout import Shout
|
||||
# from services.stat.reacted import ReactedStorage
|
||||
|
||||
ts = datetime.now(tz=timezone.utc)
|
||||
|
||||
|
@ -84,7 +83,6 @@ def migrate_ratings(session, entry, reaction_dict):
|
|||
)
|
||||
session.add(following2)
|
||||
session.add(rr)
|
||||
# await ReactedStorage.react(rr)
|
||||
|
||||
except Exception as e:
|
||||
print("[migration] comment rating error: %r" % re_reaction_dict)
|
||||
|
|
|
@ -9,7 +9,6 @@ from orm.reaction import Reaction, ReactionKind
|
|||
from orm.shout import Shout, ShoutTopic, ShoutReactionsFollower
|
||||
from orm.user import User
|
||||
from orm.topic import TopicFollower, Topic
|
||||
# from services.stat.reacted import ReactedStorage
|
||||
from services.stat.viewed import ViewedStorage
|
||||
import re
|
||||
|
||||
|
@ -365,7 +364,6 @@ async def content_ratings_to_reactions(entry, slug):
|
|||
else:
|
||||
rea = Reaction.create(**reaction_dict)
|
||||
session.add(rea)
|
||||
# await ReactedStorage.react(rea)
|
||||
# shout_dict['ratings'].append(reaction_dict)
|
||||
|
||||
session.commit()
|
||||
|
|
|
@ -35,11 +35,12 @@ def migrate(entry):
|
|||
slug = entry["profile"].get("path").lower()
|
||||
slug = re.sub('[^0-9a-zA-Z]+', '-', slug).strip()
|
||||
user_dict["slug"] = slug
|
||||
bio = BeautifulSoup(entry.get("profile").get("bio") or "", features="lxml").text
|
||||
if bio.startswith('<'):
|
||||
print('[migration] bio! ' + bio)
|
||||
bio = BeautifulSoup(bio, features="lxml").text
|
||||
bio = bio.replace('\(', '(').replace('\)', ')')
|
||||
bio = (entry.get("profile", {"bio": ""}).get("bio") or "").replace('\(', '(').replace('\)', ')')
|
||||
bio_html = BeautifulSoup(bio, features="lxml").text
|
||||
if bio == bio_html:
|
||||
user_dict["bio"] = bio
|
||||
else:
|
||||
user_dict["about"] = bio
|
||||
|
||||
# userpic
|
||||
try:
|
||||
|
|
|
@ -56,7 +56,8 @@ class User(Base):
|
|||
email = Column(String, unique=True, nullable=False, comment="Email")
|
||||
username = Column(String, nullable=False, comment="Login")
|
||||
password = Column(String, nullable=True, comment="Password")
|
||||
bio = Column(String, nullable=True, comment="Bio")
|
||||
bio = Column(String, nullable=True, comment="Bio") # status description
|
||||
about = Column(String, nullable=True, comment="About") # long and formatted
|
||||
userpic = Column(String, nullable=True, comment="Userpic")
|
||||
name = Column(String, nullable=True, comment="Display name")
|
||||
slug = Column(String, unique=True, comment="User's slug")
|
||||
|
@ -100,7 +101,7 @@ class User(Base):
|
|||
session.commit()
|
||||
User.default_user = default
|
||||
|
||||
async def get_permission(self):
|
||||
def get_permission(self):
|
||||
scope = {}
|
||||
for role in self.roles:
|
||||
for p in role.permissions:
|
||||
|
|
|
@ -8,6 +8,7 @@ from starlette.responses import RedirectResponse
|
|||
from transliterate import translit
|
||||
|
||||
from auth.authenticate import login_required
|
||||
from auth.credentials import AuthCredentials
|
||||
from auth.email import send_auth_email
|
||||
from auth.identity import Identity, Password
|
||||
from auth.jwtcodec import JWTCodec
|
||||
|
@ -24,20 +25,19 @@ from settings import SESSION_TOKEN_HEADER, FRONTEND_URL
|
|||
@mutation.field("getSession")
|
||||
@login_required
|
||||
async def get_current_user(_, info):
|
||||
user = info.context["request"].user
|
||||
token = info.context["request"].headers.get("Authorization")
|
||||
if user and token:
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
token = info.context["request"].headers.get(SESSION_TOKEN_HEADER)
|
||||
|
||||
with local_session() as session:
|
||||
user = session.query(User).where(User.id == auth.user_id).one()
|
||||
user.lastSeen = datetime.now(tz=timezone.utc)
|
||||
with local_session() as session:
|
||||
session.add(user)
|
||||
session.commit()
|
||||
return {
|
||||
"token": token,
|
||||
"user": user,
|
||||
"news": await user_subscriptions(user.slug),
|
||||
}
|
||||
else:
|
||||
raise Unauthorized("No session token present in request, try to login")
|
||||
session.commit()
|
||||
|
||||
return {
|
||||
"token": token,
|
||||
"user": user,
|
||||
"news": await user_subscriptions(user.id),
|
||||
}
|
||||
|
||||
|
||||
@mutation.field("confirmEmail")
|
||||
|
@ -58,7 +58,7 @@ async def confirm_email(_, info, token):
|
|||
return {
|
||||
"token": session_token,
|
||||
"user": user,
|
||||
"news": await user_subscriptions(user.slug)
|
||||
"news": await user_subscriptions(user.id)
|
||||
}
|
||||
except InvalidToken as e:
|
||||
raise InvalidToken(e.message)
|
||||
|
@ -174,7 +174,7 @@ async def login(_, info, email: str, password: str = "", lang: str = "ru"):
|
|||
return {
|
||||
"token": session_token,
|
||||
"user": user,
|
||||
"news": await user_subscriptions(user.slug),
|
||||
"news": await user_subscriptions(user.id),
|
||||
}
|
||||
except InvalidPassword:
|
||||
print(f"[auth] {email}: invalid password")
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from auth.authenticate import login_required
|
||||
from auth.credentials import AuthCredentials
|
||||
from base.orm import local_session
|
||||
from base.resolvers import query, mutation
|
||||
from base.exceptions import ObjectNotExist, BaseHttpException
|
||||
|
@ -10,26 +11,28 @@ from orm.user import User
|
|||
@query.field("getCollabs")
|
||||
@login_required
|
||||
async def get_collabs(_, info):
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
with local_session() as session:
|
||||
collabs = session.query(Collab).filter(user.slug in Collab.authors)
|
||||
collabs = session.query(Collab).filter(auth.user_id in Collab.authors)
|
||||
return collabs
|
||||
|
||||
|
||||
@mutation.field("inviteCoauthor")
|
||||
@login_required
|
||||
async def invite_coauthor(_, info, author: str, shout: int):
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
with local_session() as session:
|
||||
s = session.query(Shout).where(Shout.id == shout).one()
|
||||
if not s:
|
||||
raise ObjectNotExist("invalid shout id")
|
||||
else:
|
||||
c = session.query(Collab).where(Collab.shout == shout).one()
|
||||
if user.slug not in c.authors:
|
||||
if auth.user_id not in c.authors:
|
||||
raise BaseHttpException("you are not in authors list")
|
||||
else:
|
||||
invited_user = session.query(User).where(User.slug == author).one()
|
||||
invited_user = session.query(User).where(User.id == author).one()
|
||||
c.invites.append(invited_user)
|
||||
session.add(c)
|
||||
session.commit()
|
||||
|
@ -41,16 +44,17 @@ async def invite_coauthor(_, info, author: str, shout: int):
|
|||
@mutation.field("removeCoauthor")
|
||||
@login_required
|
||||
async def remove_coauthor(_, info, author: str, shout: int):
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
with local_session() as session:
|
||||
s = session.query(Shout).where(Shout.id == shout).one()
|
||||
if not s:
|
||||
raise ObjectNotExist("invalid shout id")
|
||||
if user.slug != s.createdBy.slug:
|
||||
raise BaseHttpException("only onwer can remove coauthors")
|
||||
if auth.user_id != s.createdBy:
|
||||
raise BaseHttpException("only owner can remove coauthors")
|
||||
else:
|
||||
c = session.query(Collab).where(Collab.shout == shout).one()
|
||||
ca = session.query(CollabAuthor).where(c.shout == shout, c.author == author).one()
|
||||
ca = session.query(CollabAuthor).join(User).where(c.shout == shout, User.slug == author).one()
|
||||
session.remve(ca)
|
||||
c.invites = filter(lambda x: x.slug == author, c.invites)
|
||||
c.authors = filter(lambda x: x.slug == author, c.authors)
|
||||
|
@ -64,14 +68,15 @@ async def remove_coauthor(_, info, author: str, shout: int):
|
|||
@mutation.field("acceptCoauthor")
|
||||
@login_required
|
||||
async def accept_coauthor(_, info, shout: int):
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
with local_session() as session:
|
||||
s = session.query(Shout).where(Shout.id == shout).one()
|
||||
if not s:
|
||||
raise ObjectNotExist("invalid shout id")
|
||||
else:
|
||||
c = session.query(Collab).where(Collab.shout == shout).one()
|
||||
accepted = filter(lambda x: x.slug == user.slug, c.invites).pop()
|
||||
accepted = filter(lambda x: x.id == auth.user_id, c.invites).pop()
|
||||
if accepted:
|
||||
c.authors.append(accepted)
|
||||
s.authors.append(accepted)
|
||||
|
|
|
@ -3,6 +3,7 @@ from datetime import datetime, timezone
|
|||
from sqlalchemy import and_
|
||||
|
||||
from auth.authenticate import login_required
|
||||
from auth.credentials import AuthCredentials
|
||||
from base.orm import local_session
|
||||
from base.resolvers import mutation
|
||||
from orm.rbac import Resource
|
||||
|
@ -19,7 +20,7 @@ from orm.collab import Collab
|
|||
@mutation.field("createShout")
|
||||
@login_required
|
||||
async def create_shout(_, info, inp):
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
topic_slugs = inp.get("topic_slugs", [])
|
||||
if topic_slugs:
|
||||
|
@ -37,24 +38,24 @@ async def create_shout(_, info, inp):
|
|||
"mainTopic": inp.get("topics", []).pop(),
|
||||
"visibility": "authors"
|
||||
})
|
||||
authors.remove(user.slug)
|
||||
authors.remove(auth.user_id)
|
||||
if authors:
|
||||
chat = create_chat(None, info, new_shout.title, members=authors)
|
||||
# create a cooperative chatroom
|
||||
MessagesStorage.register_chat(chat)
|
||||
await MessagesStorage.register_chat(chat)
|
||||
# now we should create a collab
|
||||
new_collab = Collab.create({
|
||||
"shout": new_shout.id,
|
||||
"authors": [user.slug, ],
|
||||
"authors": [auth.user_id, ],
|
||||
"invites": authors
|
||||
})
|
||||
session.add(new_collab)
|
||||
|
||||
# NOTE: shout made by one first author
|
||||
sa = ShoutAuthor.create(shout=new_shout.id, user=user.id)
|
||||
sa = ShoutAuthor.create(shout=new_shout.id, user=auth.user_id)
|
||||
session.add(sa)
|
||||
|
||||
reactions_follow(user, new_shout.slug, True)
|
||||
reactions_follow(auth.user_id, new_shout.slug, True)
|
||||
|
||||
if "mainTopic" in inp:
|
||||
topic_slugs.append(inp["mainTopic"])
|
||||
|
@ -65,11 +66,11 @@ async def create_shout(_, info, inp):
|
|||
st = ShoutTopic.create(shout=new_shout.id, topic=topic.id)
|
||||
session.add(st)
|
||||
tf = session.query(TopicFollower).where(
|
||||
and_(TopicFollower.follower == user.id, TopicFollower.topic == topic.id)
|
||||
and_(TopicFollower.follower == auth.user_id, TopicFollower.topic == topic.id)
|
||||
)
|
||||
|
||||
if not tf:
|
||||
tf = TopicFollower.create(follower=user.id, topic=topic.id, auto=True)
|
||||
tf = TopicFollower.create(follower=auth.user_id, topic=topic.id, auto=True)
|
||||
session.add(tf)
|
||||
|
||||
new_shout.topic_slugs = topic_slugs
|
||||
|
@ -77,7 +78,8 @@ async def create_shout(_, info, inp):
|
|||
|
||||
session.commit()
|
||||
|
||||
GitTask(inp, user.username, user.email, "new shout %s" % new_shout.slug)
|
||||
# TODO
|
||||
# GitTask(inp, user.username, user.email, "new shout %s" % new_shout.slug)
|
||||
|
||||
return {"shout": new_shout}
|
||||
|
||||
|
@ -85,18 +87,17 @@ async def create_shout(_, info, inp):
|
|||
@mutation.field("updateShout")
|
||||
@login_required
|
||||
async def update_shout(_, info, inp):
|
||||
auth = info.context["request"].auth
|
||||
user_id = auth.user_id
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
slug = inp["slug"]
|
||||
|
||||
with local_session() as session:
|
||||
user = session.query(User).filter(User.id == user_id).first()
|
||||
user = session.query(User).filter(User.id == auth.user_id).first()
|
||||
shout = session.query(Shout).filter(Shout.slug == slug).first()
|
||||
if not shout:
|
||||
return {"error": "shout not found"}
|
||||
|
||||
authors = [author.id for author in shout.authors]
|
||||
if user_id not in authors:
|
||||
if auth.user_id not in authors:
|
||||
scopes = auth.scopes
|
||||
print(scopes)
|
||||
if Resource.shout not in scopes:
|
||||
|
@ -115,7 +116,7 @@ async def update_shout(_, info, inp):
|
|||
ShoutTopic.create(shout=slug, topic=topic)
|
||||
session.commit()
|
||||
|
||||
GitTask(inp, user.username, user.email, "update shout %s" % (slug))
|
||||
GitTask(inp, user.username, user.email, "update shout %s" % slug)
|
||||
|
||||
return {"shout": shout}
|
||||
|
||||
|
@ -123,18 +124,17 @@ async def update_shout(_, info, inp):
|
|||
@mutation.field("deleteShout")
|
||||
@login_required
|
||||
async def delete_shout(_, info, slug):
|
||||
auth = info.context["request"].auth
|
||||
user_id = auth.user_id
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
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:
|
||||
if auth.user_id not in authors:
|
||||
return {"error": "access denied"}
|
||||
for a in authors:
|
||||
reactions_unfollow(a.slug, slug, True)
|
||||
reactions_unfollow(a.id, slug)
|
||||
shout.deletedAt = datetime.now(tz=timezone.utc)
|
||||
session.add(shout)
|
||||
session.commit()
|
||||
|
|
|
@ -3,6 +3,7 @@ import uuid
|
|||
from datetime import datetime, timezone
|
||||
|
||||
from auth.authenticate import login_required
|
||||
from auth.credentials import AuthCredentials
|
||||
from base.redis import redis
|
||||
from base.resolvers import mutation
|
||||
|
||||
|
@ -18,7 +19,7 @@ async def update_chat(_, info, chat_new: dict):
|
|||
:param chat_new: dict with chat data
|
||||
:return: Result { error chat }
|
||||
"""
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
chat_id = chat_new["id"]
|
||||
chat = await redis.execute("GET", f"chats/{chat_id}")
|
||||
if not chat:
|
||||
|
@ -26,7 +27,9 @@ async def update_chat(_, info, chat_new: dict):
|
|||
"error": "chat not exist"
|
||||
}
|
||||
chat = dict(json.loads(chat))
|
||||
if user.slug in chat["admins"]:
|
||||
|
||||
# TODO
|
||||
if auth.user_id in chat["admins"]:
|
||||
chat.update({
|
||||
"title": chat_new.get("title", chat["title"]),
|
||||
"description": chat_new.get("description", chat["description"]),
|
||||
|
@ -46,10 +49,11 @@ async def update_chat(_, info, chat_new: dict):
|
|||
@mutation.field("createChat")
|
||||
@login_required
|
||||
async def create_chat(_, info, title="", members=[]):
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
chat = {}
|
||||
if user.slug not in members:
|
||||
members.append(user.slug)
|
||||
|
||||
if auth.user_id not in members:
|
||||
members.append(auth.user_id)
|
||||
|
||||
# reuse chat craeted before if exists
|
||||
if len(members) == 2 and title == "":
|
||||
|
@ -73,7 +77,7 @@ async def create_chat(_, info, title="", members=[]):
|
|||
"id": chat_id,
|
||||
"users": members,
|
||||
"title": title,
|
||||
"createdBy": user.slug,
|
||||
"createdBy": auth.user_id,
|
||||
"createdAt": int(datetime.now(tz=timezone.utc).timestamp()),
|
||||
"updatedAt": int(datetime.now(tz=timezone.utc).timestamp()),
|
||||
"admins": []
|
||||
|
@ -93,13 +97,14 @@ async def create_chat(_, info, title="", members=[]):
|
|||
@mutation.field("deleteChat")
|
||||
@login_required
|
||||
async def delete_chat(_, info, chat_id: str):
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
chat = await redis.execute("GET", f"/chats/{chat_id}")
|
||||
if chat:
|
||||
chat = dict(json.loads(chat))
|
||||
if user.slug in chat['admins']:
|
||||
if auth.user_id in chat['admins']:
|
||||
await redis.execute("DEL", f"chats/{chat_id}")
|
||||
await redis.execute("SREM", "chats_by_user/" + user, chat_id)
|
||||
await redis.execute("SREM", "chats_by_user/" + str(auth.user_id), chat_id)
|
||||
await redis.execute("COMMIT")
|
||||
else:
|
||||
return {
|
||||
|
|
|
@ -2,6 +2,7 @@ import json
|
|||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from auth.authenticate import login_required
|
||||
from auth.credentials import AuthCredentials
|
||||
from base.redis import redis
|
||||
from base.orm import local_session
|
||||
from base.resolvers import query
|
||||
|
@ -30,12 +31,9 @@ async def load_messages(chat_id: str, limit: int, offset: int):
|
|||
@login_required
|
||||
async def load_chats(_, info, limit: int = 50, offset: int = 0):
|
||||
""" load :limit chats of current user with :offset """
|
||||
user = info.context["request"].user
|
||||
if user:
|
||||
print('[inbox] load user\'s chats %s' % user.slug)
|
||||
else:
|
||||
raise Unauthorized("Please login to load chats")
|
||||
cids = await redis.execute("SMEMBERS", "chats_by_user/" + user.slug)
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
cids = await redis.execute("SMEMBERS", "chats_by_user/" + str(auth.user_id))
|
||||
if cids:
|
||||
cids = list(cids)[offset:offset + limit]
|
||||
if not cids:
|
||||
|
@ -47,7 +45,7 @@ async def load_chats(_, info, limit: int = 50, offset: int = 0):
|
|||
if c:
|
||||
c = dict(json.loads(c))
|
||||
c['messages'] = await load_messages(cid, 5, 0)
|
||||
c['unread'] = await get_unread_counter(cid, user.slug)
|
||||
c['unread'] = await get_unread_counter(cid, auth.user_id)
|
||||
with local_session() as session:
|
||||
c['members'] = []
|
||||
for userslug in c["users"]:
|
||||
|
@ -65,11 +63,11 @@ async def load_chats(_, info, limit: int = 50, offset: int = 0):
|
|||
}
|
||||
|
||||
|
||||
async def search_user_chats(by, messages: set, slug: str, limit, offset):
|
||||
async def search_user_chats(by, messages: set, user_id: int, limit, offset):
|
||||
cids = set([])
|
||||
by_author = by.get('author')
|
||||
body_like = by.get('body')
|
||||
cids.unioin(set(await redis.execute("SMEMBERS", "chats_by_user/" + slug)))
|
||||
cids.unioin(set(await redis.execute("SMEMBERS", "chats_by_user/" + str(user_id))))
|
||||
if by_author:
|
||||
# all author's messages
|
||||
cids.union(set(await redis.execute("SMEMBERS", f"chats_by_user/{by_author}")))
|
||||
|
@ -104,9 +102,11 @@ async def load_messages_by(_, info, by, limit: int = 10, offset: int = 0):
|
|||
# everyone's messages in filtered chat
|
||||
messages.union(set(await load_messages(by_chat, limit, offset)))
|
||||
|
||||
user = info.context["request"].user
|
||||
if user and len(messages) == 0:
|
||||
messages.union(search_user_chats(by, messages, user.slug, limit, offset))
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
if len(messages) == 0:
|
||||
# FIXME
|
||||
messages.union(search_user_chats(by, messages, auth.user_id, limit, offset))
|
||||
|
||||
days = by.get("days")
|
||||
if days:
|
||||
|
@ -126,9 +126,10 @@ async def load_messages_by(_, info, by, limit: int = 10, offset: int = 0):
|
|||
@query.field("loadRecipients")
|
||||
async def load_recipients(_, info, limit=50, offset=0):
|
||||
chat_users = []
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
try:
|
||||
chat_users += await followed_authors(user.slug)
|
||||
chat_users += await followed_authors(auth.user_id)
|
||||
limit = limit - len(chat_users)
|
||||
except Exception:
|
||||
pass
|
||||
|
|
|
@ -3,6 +3,7 @@ import json
|
|||
from datetime import datetime, timezone
|
||||
|
||||
from auth.authenticate import login_required
|
||||
from auth.credentials import AuthCredentials
|
||||
from base.redis import redis
|
||||
from base.resolvers import mutation, subscription
|
||||
from services.inbox import ChatFollowing, MessageResult, MessagesStorage
|
||||
|
@ -12,7 +13,8 @@ from services.inbox import ChatFollowing, MessageResult, MessagesStorage
|
|||
@login_required
|
||||
async def create_message(_, info, chat: str, body: str, replyTo=None):
|
||||
""" create message with :body for :chat_id replying to :replyTo optionally """
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
chat = await redis.execute("GET", f"chats/{chat}")
|
||||
if not chat:
|
||||
return {
|
||||
|
@ -25,7 +27,7 @@ async def create_message(_, info, chat: str, body: str, replyTo=None):
|
|||
new_message = {
|
||||
"chatId": chat['id'],
|
||||
"id": message_id,
|
||||
"author": user.slug,
|
||||
"author": auth.user_id,
|
||||
"body": body,
|
||||
"replyTo": replyTo,
|
||||
"createdAt": int(datetime.now(tz=timezone.utc).timestamp()),
|
||||
|
@ -55,7 +57,7 @@ async def create_message(_, info, chat: str, body: str, replyTo=None):
|
|||
@mutation.field("updateMessage")
|
||||
@login_required
|
||||
async def update_message(_, info, chat_id: str, message_id: int, body: str):
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
chat = await redis.execute("GET", f"chats/{chat_id}")
|
||||
if not chat:
|
||||
|
@ -66,7 +68,7 @@ async def update_message(_, info, chat_id: str, message_id: int, body: str):
|
|||
return {"error": "message not exist"}
|
||||
|
||||
message = json.loads(message)
|
||||
if message["author"] != user.slug:
|
||||
if message["author"] != auth.user_id:
|
||||
return {"error": "access denied"}
|
||||
|
||||
message["body"] = body
|
||||
|
@ -86,7 +88,7 @@ async def update_message(_, info, chat_id: str, message_id: int, body: str):
|
|||
@mutation.field("deleteMessage")
|
||||
@login_required
|
||||
async def delete_message(_, info, chat_id: str, message_id: int):
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
chat = await redis.execute("GET", f"chats/{chat_id}")
|
||||
if not chat:
|
||||
|
@ -97,15 +99,15 @@ async def delete_message(_, info, chat_id: str, message_id: int):
|
|||
if not message:
|
||||
return {"error": "message not exist"}
|
||||
message = json.loads(message)
|
||||
if message["author"] != user.slug:
|
||||
if message["author"] != auth.user_id:
|
||||
return {"error": "access denied"}
|
||||
|
||||
await redis.execute("LREM", f"chats/{chat_id}/message_ids", 0, str(message_id))
|
||||
await redis.execute("DEL", f"chats/{chat_id}/messages/{str(message_id)}")
|
||||
|
||||
users = chat["users"]
|
||||
for user_slug in users:
|
||||
await redis.execute("LREM", f"chats/{chat_id}/unread/{user_slug}", 0, str(message_id))
|
||||
for user_id in users:
|
||||
await redis.execute("LREM", f"chats/{chat_id}/unread/{user_id}", 0, str(message_id))
|
||||
|
||||
result = MessageResult("DELETED", message)
|
||||
await MessagesStorage.put(result)
|
||||
|
@ -116,7 +118,7 @@ async def delete_message(_, info, chat_id: str, message_id: int):
|
|||
@mutation.field("markAsRead")
|
||||
@login_required
|
||||
async def mark_as_read(_, info, chat_id: str, messages: [int]):
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
chat = await redis.execute("GET", f"chats/{chat_id}")
|
||||
if not chat:
|
||||
|
@ -124,11 +126,11 @@ async def mark_as_read(_, info, chat_id: str, messages: [int]):
|
|||
|
||||
chat = json.loads(chat)
|
||||
users = set(chat["users"])
|
||||
if user.slug not in users:
|
||||
if auth.user_id not in users:
|
||||
return {"error": "access denied"}
|
||||
|
||||
for message_id in messages:
|
||||
await redis.execute("LREM", f"chats/{chat_id}/unread/{user.slug}", 0, str(message_id))
|
||||
await redis.execute("LREM", f"chats/{chat_id}/unread/{auth.user_id}", 0, str(message_id))
|
||||
|
||||
return {
|
||||
"error": None
|
||||
|
@ -139,8 +141,9 @@ async def mark_as_read(_, info, chat_id: str, messages: [int]):
|
|||
@login_required
|
||||
async def message_generator(obj, info):
|
||||
try:
|
||||
user = info.context["request"].user
|
||||
user_following_chats = await redis.execute("GET", f"chats_by_user/{user.slug}")
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
user_following_chats = await redis.execute("GET", f"chats_by_user/{auth.user_id}")
|
||||
if user_following_chats:
|
||||
user_following_chats = list(json.loads(user_following_chats)) # chat ids
|
||||
else:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import json
|
||||
|
||||
from auth.authenticate import login_required
|
||||
from auth.credentials import AuthCredentials
|
||||
from base.redis import redis
|
||||
from base.resolvers import query
|
||||
from base.orm import local_session
|
||||
|
@ -12,8 +13,8 @@ from orm.user import AuthorFollower, User
|
|||
async def search_recipients(_, info, query: str, limit: int = 50, offset: int = 0):
|
||||
result = []
|
||||
# TODO: maybe redis scan?
|
||||
user = info.context["request"].user
|
||||
talk_before = await redis.execute("GET", f"/chats_by_user/{user.slug}")
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
talk_before = await redis.execute("GET", f"/chats_by_user/{auth.user_id}")
|
||||
if talk_before:
|
||||
talk_before = list(json.loads(talk_before))[offset:offset + limit]
|
||||
for chat_id in talk_before:
|
||||
|
@ -24,7 +25,6 @@ async def search_recipients(_, info, query: str, limit: int = 50, offset: int =
|
|||
if member.startswith(query):
|
||||
if member not in result:
|
||||
result.append(member)
|
||||
user = info.context["request"].user
|
||||
|
||||
more_amount = limit - len(result)
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from auth.authenticate import login_required
|
||||
from auth.credentials import AuthCredentials
|
||||
from base.resolvers import mutation
|
||||
# from resolvers.community import community_follow, community_unfollow
|
||||
from resolvers.zine.profile import author_follow, author_unfollow
|
||||
|
@ -9,17 +10,18 @@ from resolvers.zine.topics import topic_follow, topic_unfollow
|
|||
@mutation.field("follow")
|
||||
@login_required
|
||||
async def follow(_, info, what, slug):
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
try:
|
||||
if what == "AUTHOR":
|
||||
author_follow(user, slug)
|
||||
author_follow(auth.user_id, slug)
|
||||
elif what == "TOPIC":
|
||||
topic_follow(user, slug)
|
||||
topic_follow(auth.user_id, slug)
|
||||
elif what == "COMMUNITY":
|
||||
# community_follow(user, slug)
|
||||
pass
|
||||
elif what == "REACTIONS":
|
||||
reactions_follow(user, slug)
|
||||
reactions_follow(auth.user_id, slug)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
@ -29,18 +31,18 @@ async def follow(_, info, what, slug):
|
|||
@mutation.field("unfollow")
|
||||
@login_required
|
||||
async def unfollow(_, info, what, slug):
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
try:
|
||||
if what == "AUTHOR":
|
||||
author_unfollow(user, slug)
|
||||
author_unfollow(auth.user_id, slug)
|
||||
elif what == "TOPIC":
|
||||
topic_unfollow(user, slug)
|
||||
topic_unfollow(auth.user_id, slug)
|
||||
elif what == "COMMUNITY":
|
||||
# community_unfollow(user, slug)
|
||||
pass
|
||||
elif what == "REACTIONS":
|
||||
reactions_unfollow(user, slug)
|
||||
reactions_unfollow(auth.user_id, slug)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from datetime import datetime, timedelta, timezone
|
||||
from sqlalchemy.orm import joinedload, aliased
|
||||
from sqlalchemy.sql.expression import desc, asc, select, func
|
||||
|
||||
from auth.credentials import AuthCredentials
|
||||
from base.orm import local_session
|
||||
from base.resolvers import query
|
||||
from orm import ViewedEntry
|
||||
|
@ -15,10 +17,10 @@ def add_stat_columns(q):
|
|||
return add_common_stat_columns(q)
|
||||
|
||||
|
||||
def apply_filters(q, filters, user=None):
|
||||
def apply_filters(q, filters, user_id=None):
|
||||
|
||||
if filters.get("reacted") and user:
|
||||
q.join(Reaction, Reaction.createdBy == user.id)
|
||||
if filters.get("reacted") and user_id:
|
||||
q.join(Reaction, Reaction.createdBy == user_id)
|
||||
|
||||
v = filters.get("visibility")
|
||||
if v == "public":
|
||||
|
@ -105,17 +107,15 @@ async def load_shouts_by(_, info, options):
|
|||
|
||||
q = add_stat_columns(q)
|
||||
|
||||
user = info.context["request"].user
|
||||
q = apply_filters(q, options.get("filters", {}), user)
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
q = apply_filters(q, options.get("filters", {}), auth.user_id)
|
||||
|
||||
order_by = options.get("order_by", Shout.createdAt)
|
||||
if order_by == 'reacted':
|
||||
aliased_reaction = aliased(Reaction)
|
||||
q.outerjoin(aliased_reaction).add_columns(func.max(aliased_reaction.createdAt).label('reacted'))
|
||||
|
||||
order_by_desc = options.get('order_by_desc', True)
|
||||
|
||||
query_order_by = desc(order_by) if order_by_desc else asc(order_by)
|
||||
query_order_by = desc(order_by) if options.get('order_by_desc', True) else asc(order_by)
|
||||
offset = options.get("offset", 0)
|
||||
limit = options.get("limit", 10)
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ from sqlalchemy import and_, func, distinct, select, literal
|
|||
from sqlalchemy.orm import aliased, joinedload
|
||||
|
||||
from auth.authenticate import login_required
|
||||
from auth.credentials import AuthCredentials
|
||||
from base.orm import local_session
|
||||
from base.resolvers import mutation, query
|
||||
from orm.reaction import Reaction
|
||||
|
@ -40,11 +41,10 @@ def add_author_stat_columns(q):
|
|||
# func.sum(user_rating_aliased.value).label('rating_stat')
|
||||
# )
|
||||
|
||||
# q = q.add_columns(literal(0).label('commented_stat'))
|
||||
|
||||
q = q.outerjoin(Reaction, and_(Reaction.createdBy == User.id, Reaction.body.is_not(None))).add_columns(
|
||||
func.count(distinct(Reaction.id)).label('commented_stat')
|
||||
)
|
||||
q = q.add_columns(literal(0).label('commented_stat'))
|
||||
# q = q.outerjoin(Reaction, and_(Reaction.createdBy == User.id, Reaction.body.is_not(None))).add_columns(
|
||||
# func.count(distinct(Reaction.id)).label('commented_stat')
|
||||
# )
|
||||
|
||||
q = q.group_by(User.id)
|
||||
|
||||
|
@ -74,25 +74,25 @@ def get_authors_from_query(q):
|
|||
return authors
|
||||
|
||||
|
||||
async def user_subscriptions(slug: str):
|
||||
async def user_subscriptions(user_id: int):
|
||||
return {
|
||||
"unread": await get_total_unread_counter(slug), # unread inbox messages counter
|
||||
"topics": [t.slug for t in await followed_topics(slug)], # followed topics slugs
|
||||
"authors": [a.slug for a in await followed_authors(slug)], # followed authors slugs
|
||||
"reactions": await followed_reactions(slug)
|
||||
"unread": await get_total_unread_counter(user_id), # unread inbox messages counter
|
||||
"topics": [t.slug for t in await followed_topics(user_id)], # followed topics slugs
|
||||
"authors": [a.slug for a in await followed_authors(user_id)], # followed authors slugs
|
||||
"reactions": await followed_reactions(user_id)
|
||||
# "communities": [c.slug for c in followed_communities(slug)], # communities
|
||||
}
|
||||
|
||||
|
||||
# @query.field("userFollowedDiscussions")
|
||||
@login_required
|
||||
async def followed_discussions(_, info, slug) -> List[Topic]:
|
||||
return await followed_reactions(slug)
|
||||
# @login_required
|
||||
async def followed_discussions(_, info, user_id) -> List[Topic]:
|
||||
return await followed_reactions(user_id)
|
||||
|
||||
|
||||
async def followed_reactions(slug):
|
||||
async def followed_reactions(user_id):
|
||||
with local_session() as session:
|
||||
user = session.query(User).where(User.slug == slug).first()
|
||||
user = session.query(User).where(User.id == user_id).first()
|
||||
return session.query(
|
||||
Reaction.shout
|
||||
).where(
|
||||
|
@ -104,31 +104,26 @@ async def followed_reactions(slug):
|
|||
|
||||
@query.field("userFollowedTopics")
|
||||
@login_required
|
||||
async def get_followed_topics(_, info, slug) -> List[Topic]:
|
||||
return await followed_topics(slug)
|
||||
async def get_followed_topics(_, info, user_id) -> List[Topic]:
|
||||
return await followed_topics(user_id)
|
||||
|
||||
|
||||
async def followed_topics(slug):
|
||||
return followed_by_user(slug)
|
||||
async def followed_topics(user_id):
|
||||
return followed_by_user(user_id)
|
||||
|
||||
|
||||
@query.field("userFollowedAuthors")
|
||||
async def get_followed_authors(_, _info, slug) -> List[User]:
|
||||
return await followed_authors(slug)
|
||||
async def get_followed_authors(_, _info, user_id: int) -> List[User]:
|
||||
return await followed_authors(user_id)
|
||||
|
||||
|
||||
async def followed_authors(slug):
|
||||
with local_session() as session:
|
||||
user = session.query(User).where(User.slug == slug).first()
|
||||
q = select(User)
|
||||
q = add_author_stat_columns(q)
|
||||
aliased_user = aliased(User)
|
||||
q = q.join(AuthorFollower, AuthorFollower.author == user.id).join(
|
||||
aliased_user, aliased_user.id == AuthorFollower.follower
|
||||
).where(
|
||||
aliased_user.slug == slug
|
||||
)
|
||||
return get_authors_from_query(q)
|
||||
async def followed_authors(user_id):
|
||||
q = select(User)
|
||||
q = add_author_stat_columns(q)
|
||||
q = q.join(AuthorFollower, AuthorFollower.author == User.id).where(
|
||||
AuthorFollower.follower == user_id
|
||||
)
|
||||
return get_authors_from_query(q)
|
||||
|
||||
|
||||
@query.field("userFollowers")
|
||||
|
@ -157,25 +152,16 @@ async def get_user_roles(slug):
|
|||
.all()
|
||||
)
|
||||
|
||||
return roles
|
||||
return [] # roles
|
||||
|
||||
|
||||
@mutation.field("updateProfile")
|
||||
@login_required
|
||||
async def update_profile(_, info, profile):
|
||||
print('[zine] update_profile')
|
||||
print(profile)
|
||||
auth = info.context["request"].auth
|
||||
user_id = auth.user_id
|
||||
with local_session() as session:
|
||||
session.query(User).filter(User.id == user_id).update({
|
||||
"name": profile['name'],
|
||||
"slug": profile['slug'],
|
||||
"bio": profile['bio'],
|
||||
"userpic": profile['userpic'],
|
||||
"about": profile['about'],
|
||||
"links": profile['links']
|
||||
})
|
||||
session.query(User).filter(User.id == user_id).update(profile)
|
||||
session.commit()
|
||||
return {}
|
||||
|
||||
|
@ -183,11 +169,12 @@ async def update_profile(_, info, profile):
|
|||
@mutation.field("rateUser")
|
||||
@login_required
|
||||
async def rate_user(_, info, rated_userslug, value):
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
with local_session() as session:
|
||||
rating = (
|
||||
session.query(UserRating)
|
||||
.filter(and_(UserRating.rater == user.slug, UserRating.user == rated_userslug))
|
||||
.filter(and_(UserRating.rater == auth.user_id, UserRating.user == rated_userslug))
|
||||
.first()
|
||||
)
|
||||
if rating:
|
||||
|
@ -195,30 +182,30 @@ async def rate_user(_, info, rated_userslug, value):
|
|||
session.commit()
|
||||
return {}
|
||||
try:
|
||||
UserRating.create(rater=user.slug, user=rated_userslug, value=value)
|
||||
UserRating.create(rater=auth.user_id, user=rated_userslug, value=value)
|
||||
except Exception as err:
|
||||
return {"error": err}
|
||||
return {}
|
||||
|
||||
|
||||
# for mutation.field("follow")
|
||||
def author_follow(user, slug):
|
||||
def author_follow(user_id, slug):
|
||||
with local_session() as session:
|
||||
author = session.query(User).where(User.slug == slug).one()
|
||||
af = AuthorFollower.create(follower=user.id, author=author.id)
|
||||
af = AuthorFollower.create(follower=user_id, author=author.id)
|
||||
session.add(af)
|
||||
session.commit()
|
||||
|
||||
|
||||
# for mutation.field("unfollow")
|
||||
def author_unfollow(user, slug):
|
||||
def author_unfollow(user_id, slug):
|
||||
with local_session() as session:
|
||||
flw = (
|
||||
session.query(
|
||||
AuthorFollower
|
||||
).join(User, User.id == AuthorFollower.author).filter(
|
||||
and_(
|
||||
AuthorFollower.follower == user.id, User.slug == slug
|
||||
AuthorFollower.follower == user_id, User.slug == slug
|
||||
)
|
||||
).first()
|
||||
)
|
||||
|
|
|
@ -2,6 +2,7 @@ from datetime import datetime, timedelta, timezone
|
|||
from sqlalchemy import and_, asc, desc, select, text, func
|
||||
from sqlalchemy.orm import aliased
|
||||
from auth.authenticate import login_required
|
||||
from auth.credentials import AuthCredentials
|
||||
from base.orm import local_session
|
||||
from base.resolvers import mutation, query
|
||||
from orm.reaction import Reaction, ReactionKind
|
||||
|
@ -14,20 +15,20 @@ def add_reaction_stat_columns(q):
|
|||
return add_common_stat_columns(q)
|
||||
|
||||
|
||||
def reactions_follow(user: User, slug: str, auto=False):
|
||||
def reactions_follow(user_id, slug: str, auto=False):
|
||||
with local_session() as session:
|
||||
shout = session.query(Shout).where(Shout.slug == slug).one()
|
||||
|
||||
following = (
|
||||
session.query(ShoutReactionsFollower).where(and_(
|
||||
ShoutReactionsFollower.follower == user.id,
|
||||
ShoutReactionsFollower.follower == user_id,
|
||||
ShoutReactionsFollower.shout == shout.id,
|
||||
)).first()
|
||||
)
|
||||
|
||||
if not following:
|
||||
following = ShoutReactionsFollower.create(
|
||||
follower=user.id,
|
||||
follower=user_id,
|
||||
shout=shout.id,
|
||||
auto=auto
|
||||
)
|
||||
|
@ -35,13 +36,13 @@ def reactions_follow(user: User, slug: str, auto=False):
|
|||
session.commit()
|
||||
|
||||
|
||||
def reactions_unfollow(user, slug):
|
||||
def reactions_unfollow(user_id, slug):
|
||||
with local_session() as session:
|
||||
shout = session.query(Shout).where(Shout.slug == slug).one()
|
||||
|
||||
following = (
|
||||
session.query(ShoutReactionsFollower).where(and_(
|
||||
ShoutReactionsFollower.follower == user.id,
|
||||
ShoutReactionsFollower.follower == user_id,
|
||||
ShoutReactionsFollower.shout == shout.id
|
||||
)).first()
|
||||
)
|
||||
|
@ -51,12 +52,12 @@ def reactions_unfollow(user, slug):
|
|||
session.commit()
|
||||
|
||||
|
||||
def is_published_author(session, userslug):
|
||||
def is_published_author(session, user_id):
|
||||
''' checks if user has at least one publication '''
|
||||
return session.query(
|
||||
Shout
|
||||
).where(
|
||||
Shout.authors.contains(userslug)
|
||||
Shout.authors.contains(user_id)
|
||||
).filter(
|
||||
and_(
|
||||
Shout.publishedAt.is_not(None),
|
||||
|
@ -65,17 +66,17 @@ def is_published_author(session, userslug):
|
|||
).count() > 0
|
||||
|
||||
|
||||
def check_to_publish(session, user, reaction):
|
||||
def check_to_publish(session, user_id, reaction):
|
||||
''' set shout to public if publicated approvers amount > 4 '''
|
||||
if not reaction.replyTo and reaction.kind in [
|
||||
ReactionKind.ACCEPT,
|
||||
ReactionKind.LIKE,
|
||||
ReactionKind.PROOF
|
||||
]:
|
||||
if is_published_author(user):
|
||||
if is_published_author(user_id):
|
||||
# now count how many approvers are voted already
|
||||
approvers_reactions = session.query(Reaction).where(Reaction.shout == reaction.shout).all()
|
||||
approvers = [user.slug, ]
|
||||
approvers = [user_id, ]
|
||||
for ar in approvers_reactions:
|
||||
a = ar.createdBy
|
||||
if is_published_author(session, a):
|
||||
|
@ -85,7 +86,7 @@ def check_to_publish(session, user, reaction):
|
|||
return False
|
||||
|
||||
|
||||
def check_to_hide(session, user, reaction):
|
||||
def check_to_hide(session, user_id, reaction):
|
||||
''' hides any shout if 20% of reactions are negative '''
|
||||
if not reaction.replyTo and reaction.kind in [
|
||||
ReactionKind.DECLINE,
|
||||
|
@ -107,8 +108,8 @@ def check_to_hide(session, user, reaction):
|
|||
return False
|
||||
|
||||
|
||||
def set_published(session, slug, publisher):
|
||||
s = session.query(Shout).where(Shout.slug == slug).first()
|
||||
def set_published(session, shout_id, publisher):
|
||||
s = session.query(Shout).where(Shout.id == shout_id).first()
|
||||
s.publishedAt = datetime.now(tz=timezone.utc)
|
||||
s.publishedBy = publisher
|
||||
s.visibility = text('public')
|
||||
|
@ -116,8 +117,8 @@ def set_published(session, slug, publisher):
|
|||
session.commit()
|
||||
|
||||
|
||||
def set_hidden(session, slug):
|
||||
s = session.query(Shout).where(Shout.slug == slug).first()
|
||||
def set_hidden(session, shout_id):
|
||||
s = session.query(Shout).where(Shout.id == shout_id).first()
|
||||
s.visibility = text('authors')
|
||||
s.publishedAt = None # TODO: discuss
|
||||
s.publishedBy = None # TODO: store changes history in git
|
||||
|
@ -128,7 +129,7 @@ def set_hidden(session, slug):
|
|||
@mutation.field("createReaction")
|
||||
@login_required
|
||||
async def create_reaction(_, info, inp):
|
||||
user = info.context["request"].user
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
with local_session() as session:
|
||||
reaction = Reaction.create(**inp)
|
||||
|
@ -137,13 +138,13 @@ async def create_reaction(_, info, inp):
|
|||
|
||||
# self-regulation mechanics
|
||||
|
||||
if check_to_hide(session, user, reaction):
|
||||
if check_to_hide(session, auth.user_id, reaction):
|
||||
set_hidden(session, reaction.shout)
|
||||
elif check_to_publish(session, user, reaction):
|
||||
elif check_to_publish(session, auth.user_id, reaction):
|
||||
set_published(session, reaction.shout, reaction.createdBy)
|
||||
|
||||
try:
|
||||
reactions_follow(user, inp["shout"], True)
|
||||
reactions_follow(auth.user_id, inp["shout"], True)
|
||||
except Exception as e:
|
||||
print(f"[resolvers.reactions] error on reactions autofollowing: {e}")
|
||||
|
||||
|
@ -158,11 +159,10 @@ async def create_reaction(_, info, inp):
|
|||
@mutation.field("updateReaction")
|
||||
@login_required
|
||||
async def update_reaction(_, info, inp):
|
||||
auth = info.context["request"].auth
|
||||
user_id = auth.user_id
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
with local_session() as session:
|
||||
user = session.query(User).where(User.id == user_id).first()
|
||||
user = session.query(User).where(User.id == auth.user_id).first()
|
||||
q = select(Reaction).filter(Reaction.id == inp.id)
|
||||
q = add_reaction_stat_columns(q)
|
||||
|
||||
|
@ -193,10 +193,10 @@ async def update_reaction(_, info, inp):
|
|||
@mutation.field("deleteReaction")
|
||||
@login_required
|
||||
async def delete_reaction(_, info, rid):
|
||||
auth = info.context["request"].auth
|
||||
user_id = auth.user_id
|
||||
auth: AuthCredentials = info.context["request"].auth
|
||||
|
||||
with local_session() as session:
|
||||
user = session.query(User).where(User.id == user_id).first()
|
||||
user = session.query(User).where(User.id == auth.user_id).first()
|
||||
reaction = session.query(Reaction).filter(Reaction.id == rid).first()
|
||||
if not reaction:
|
||||
return {"error": "invalid reaction id"}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
from sqlalchemy import and_, select, distinct, func
|
||||
from sqlalchemy.orm import aliased
|
||||
|
||||
from auth.authenticate import login_required
|
||||
from base.orm import local_session
|
||||
from base.resolvers import mutation, query
|
||||
|
@ -8,16 +10,20 @@ from orm import Shout, User
|
|||
|
||||
|
||||
def add_topic_stat_columns(q):
|
||||
q = q.outerjoin(ShoutTopic, Topic.id == ShoutTopic.topic).add_columns(
|
||||
func.count(distinct(ShoutTopic.shout)).label('shouts_stat')
|
||||
).outerjoin(ShoutAuthor, ShoutTopic.shout == ShoutAuthor.shout).add_columns(
|
||||
func.count(distinct(ShoutAuthor.user)).label('authors_stat')
|
||||
).outerjoin(TopicFollower,
|
||||
aliased_shout_topic = aliased(ShoutTopic)
|
||||
aliased_shout_author = aliased(ShoutAuthor)
|
||||
aliased_topic_follower = aliased(TopicFollower)
|
||||
|
||||
q = q.outerjoin(aliased_shout_topic, Topic.id == aliased_shout_topic.topic).add_columns(
|
||||
func.count(distinct(aliased_shout_topic.shout)).label('shouts_stat')
|
||||
).outerjoin(aliased_shout_author, aliased_shout_topic.shout == aliased_shout_author.shout).add_columns(
|
||||
func.count(distinct(aliased_shout_author.user)).label('authors_stat')
|
||||
).outerjoin(aliased_topic_follower,
|
||||
and_(
|
||||
TopicFollower.topic == Topic.id,
|
||||
TopicFollower.follower == ShoutAuthor.id
|
||||
aliased_topic_follower.topic == Topic.id,
|
||||
aliased_topic_follower.follower == aliased_shout_author.id
|
||||
)).add_columns(
|
||||
func.count(distinct(TopicFollower.follower)).label('followers_stat')
|
||||
func.count(distinct(aliased_topic_follower.follower)).label('followers_stat')
|
||||
)
|
||||
|
||||
q = q.group_by(Topic.id)
|
||||
|
@ -46,10 +52,10 @@ def get_topics_from_query(q):
|
|||
return topics
|
||||
|
||||
|
||||
def followed_by_user(user_slug):
|
||||
def followed_by_user(user_id):
|
||||
q = select(Topic)
|
||||
q = add_topic_stat_columns(q)
|
||||
q = q.join(User).where(User.slug == user_slug)
|
||||
q = q.join(TopicFollower).where(TopicFollower.follower == user_id)
|
||||
|
||||
return get_topics_from_query(q)
|
||||
|
||||
|
@ -115,21 +121,21 @@ async def update_topic(_, _info, inp):
|
|||
return {"topic": topic}
|
||||
|
||||
|
||||
async def topic_follow(user, slug):
|
||||
def topic_follow(user_id, slug):
|
||||
with local_session() as session:
|
||||
topic = session.query(Topic).where(Topic.slug == slug).one()
|
||||
|
||||
following = TopicFollower.create(topic=topic.id, follower=user.id)
|
||||
following = TopicFollower.create(topic=topic.id, follower=user_id)
|
||||
session.add(following)
|
||||
session.commit()
|
||||
|
||||
|
||||
async def topic_unfollow(user, slug):
|
||||
def topic_unfollow(user_id, slug):
|
||||
with local_session() as session:
|
||||
sub = (
|
||||
session.query(TopicFollower).join(Topic).filter(
|
||||
and_(
|
||||
TopicFollower.follower == user.id,
|
||||
TopicFollower.follower == user_id,
|
||||
Topic.slug == slug
|
||||
)
|
||||
).first()
|
||||
|
@ -145,7 +151,7 @@ async def topic_unfollow(user, slug):
|
|||
async def topics_random(_, info, amount=12):
|
||||
q = select(Topic)
|
||||
q = add_topic_stat_columns(q)
|
||||
q = q.join(Shout, ShoutTopic.shout == Shout.id).group_by(Topic.id).having(func.count(Shout.id) > 2)
|
||||
q = q.join(ShoutTopic).join(Shout, ShoutTopic.shout == Shout.id).group_by(Topic.id).having(func.count(Shout.id) > 2)
|
||||
q = q.order_by(func.random()).limit(amount)
|
||||
|
||||
return get_topics_from_query(q)
|
||||
|
|
Loading…
Reference in New Issue
Block a user