diff --git a/auth/authenticate.py b/auth/authenticate.py index 4e8248c7..958560cb 100644 --- a/auth/authenticate.py +++ b/auth/authenticate.py @@ -28,6 +28,7 @@ class SessionToken: token is of specified type """ try: + print('[auth.authenticate] session token verify') payload = JWTCodec.decode(token) except ExpiredSignatureError: payload = JWTCodec.decode(token, verify_exp=False) @@ -58,6 +59,8 @@ class JWTAuthenticate(AuthenticationBackend): try: payload = await SessionToken.verify(token) except Exception as exc: + print("[auth.authenticate] session token verify error") + print(exc) return AuthCredentials(scopes=[], error_message=str(exc)), AuthUser( user_id=None ) diff --git a/auth/identity.py b/auth/identity.py index 197f9fd7..efcec0ec 100644 --- a/auth/identity.py +++ b/auth/identity.py @@ -81,6 +81,7 @@ class Identity: @staticmethod async def onetime(token: str) -> User: try: + print('[auth.identity] using one time token') payload = JWTCodec.decode(token) if not await TokenStorage.exist(f"{payload.user_id}-{token}"): raise InvalidToken("Login token has expired, please login again") diff --git a/auth/tokenstorage.py b/auth/tokenstorage.py index 2c84ca67..c27c7d97 100644 --- a/auth/tokenstorage.py +++ b/auth/tokenstorage.py @@ -36,11 +36,13 @@ class TokenStorage: @staticmethod async def revoke(token: str) -> bool: + payload = None try: + print("[auth.tokenstorage] revoke token") payload = JWTCodec.decode(token) except: # noqa pass - else: + finally: await redis.execute("DEL", f"{payload.user_id}-{token}") return True diff --git a/base/redis.py b/base/redis.py index 39f5d47a..7468af0a 100644 --- a/base/redis.py +++ b/base/redis.py @@ -1,5 +1,5 @@ from aioredis import from_url - +from asyncio import sleep from settings import REDIS_URL @@ -21,7 +21,12 @@ class RedisCache: self._instance = None async def execute(self, command, *args, **kwargs): - return await self._instance.execute_command(command, *args, **kwargs) + while not self._instance: + await sleep(1) + try: + await self._instance.execute_command(command, *args, **kwargs) + except Exception: + pass async def lrange(self, key, start, stop): return await self._instance.lrange(key, start, stop) diff --git a/resolvers/auth.py b/resolvers/auth.py index b2923ce3..c167394b 100644 --- a/resolvers/auth.py +++ b/resolvers/auth.py @@ -42,6 +42,7 @@ async def get_current_user(_, info): async def confirm_email(_, info, token): """confirm owning email address""" try: + print('[resolvers.auth] confirm email by token') payload = JWTCodec.decode(token) user_id = payload.user_id await TokenStorage.get(f"{user_id}-{token}") @@ -175,7 +176,7 @@ async def login(_, info, email: str, password: str = "", lang: str = "ru"): } except InvalidPassword: print(f"[auth] {email}: invalid password") - raise InvalidPassword("invalid passoword") # contains webserver status + raise InvalidPassword("invalid password") # contains webserver status # return {"error": "invalid password"} diff --git a/resolvers/inbox/load.py b/resolvers/inbox/load.py index 264e5c24..d3ca0ff1 100644 --- a/resolvers/inbox/load.py +++ b/resolvers/inbox/load.py @@ -33,18 +33,24 @@ async def load_messages(chatId: str, limit: int, offset: int): async def load_chats(_, info, limit: int, offset: int): """ load :limit chats of current user with :offset """ user = info.context["request"].user - chats = await redis.execute("GET", f"chats_by_user/{user.slug}") - if chats: - chats = list(json.loads(chats))[offset:offset + limit] - if not chats: - chats = [] - for c in chats: - c['messages'] = await load_messages(c['id'], limit, offset) - c['unread'] = await get_unread_counter(c['id'], user.slug) - return { - "chats": chats, - "error": None - } + if user: + chats = await redis.execute("GET", f"chats_by_user/{user.slug}") + if chats: + chats = list(json.loads(chats))[offset:offset + limit] + if not chats: + chats = [] + for c in chats: + c['messages'] = await load_messages(c['id'], limit, offset) + c['unread'] = await get_unread_counter(c['id'], user.slug) + return { + "chats": chats, + "error": None + } + else: + return { + "error": "please login", + "chats": [] + } @query.field("loadMessagesBy") diff --git a/resolvers/zine/load.py b/resolvers/zine/load.py index 3dbda0ee..4f37f9c2 100644 --- a/resolvers/zine/load.py +++ b/resolvers/zine/load.py @@ -31,6 +31,7 @@ def apply_filters(q, filters, user=None): q = q.filter(Shout.createdAt > before) return q + @query.field("loadShout") async def load_shout(_, info, slug): with local_session() as session: diff --git a/resolvers/zine/reactions.py b/resolvers/zine/reactions.py index f74d6ee7..1f4d48c2 100644 --- a/resolvers/zine/reactions.py +++ b/resolvers/zine/reactions.py @@ -1,5 +1,5 @@ from datetime import datetime, timedelta -from sqlalchemy import and_, asc, desc, select, text, func, column +from sqlalchemy import and_, asc, desc, select, text, func from sqlalchemy.orm import aliased from auth.authenticate import login_required @@ -23,12 +23,10 @@ async def get_reaction_stat(reaction_id): def reactions_follow(user: User, slug: str, auto=False): with local_session() as session: following = ( - session.query(ShoutReactionsFollower) - .where(and_( + session.query(ShoutReactionsFollower).where(and_( ShoutReactionsFollower.follower == user.slug, ShoutReactionsFollower.shout == slug - )) - .first() + )).first() ) if not following: following = ShoutReactionsFollower.create( @@ -43,12 +41,10 @@ def reactions_follow(user: User, slug: str, auto=False): def reactions_unfollow(user, slug): with local_session() as session: following = ( - session.query(ShoutReactionsFollower) - .where(and_( + session.query(ShoutReactionsFollower).where(and_( ShoutReactionsFollower.follower == user.slug, ShoutReactionsFollower.shout == slug - )) - .first() + )).first() ) if following: session.delete(following) @@ -199,6 +195,7 @@ async def delete_reaction(_, info, rid): session.commit() return {} + def map_result_item(result_item): reaction = result_item[0] user = result_item[1] diff --git a/services/auth/users.py b/services/auth/users.py index 0d76dfa8..df6a84ee 100644 --- a/services/auth/users.py +++ b/services/auth/users.py @@ -23,10 +23,12 @@ class UserStorage: async def get_user(id): with local_session() as session: user = ( - session.query(User) - .options(selectinload(User.roles), selectinload(User.ratings)) - .filter(User.id == id) - .one() + session.query(User).options( + selectinload(User.roles), + selectinload(User.ratings) + ).filter( + User.id == id + ).one() ) return user diff --git a/services/stat/reacted.py b/services/stat/reacted.py index 00f4fb66..dfded159 100644 --- a/services/stat/reacted.py +++ b/services/stat/reacted.py @@ -35,8 +35,10 @@ class ReactedStorage: @staticmethod async def get_shout_stat(slug): + viewed = int(await ViewedStorage.get_shout(slug)) + print(viewed) return { - "viewed": await ViewedStorage.get_shout(slug), + "viewed": viewed, "reacted": len(await ReactedStorage.get_shout(slug)), "commented": len(await ReactedStorage.get_comments(slug)), "rating": await ReactedStorage.get_rating(slug), diff --git a/services/stat/viewed.py b/services/stat/viewed.py index ca3dabc1..ece3e8c1 100644 --- a/services/stat/viewed.py +++ b/services/stat/viewed.py @@ -3,7 +3,7 @@ from datetime import timedelta, timezone, datetime from gql import Client, gql from gql.transport.aiohttp import AIOHTTPTransport from base.orm import local_session -from sqlalchemy import func, select +from sqlalchemy import func from orm.shout import ShoutTopic from orm.viewed import ViewedEntry from ssl import create_default_context @@ -119,12 +119,14 @@ class ViewedStorage: if not shout_views: shout_views = 0 with local_session() as session: - shout_views_q = select(func.sum(ViewedEntry.amount)).where( - ViewedEntry.shout == shout_slug - ) - shout_views = session.execute(shout_views_q) - self.by_shouts[shout_slug] = shout_views - self.update_topics(session, shout_slug) + try: + shout_views = session.query(func.sum(ViewedEntry.amount)).where( + ViewedEntry.shout == shout_slug + ).all()[0][0] + self.by_shouts[shout_slug] = shout_views + self.update_topics(session, shout_slug) + except Exception as e: + raise e return shout_views