From 1ce88a351589a28d4261d6a5e4227ba4117dbfe7 Mon Sep 17 00:00:00 2001 From: knst-kotov Date: Wed, 18 Aug 2021 19:53:55 +0300 Subject: [PATCH] updateShout --- auth/authenticate.py | 104 ++++++++++++++++++++++--------------------- orm/user.py | 6 ++- resolvers/zine.py | 31 ++++++++++--- 3 files changed, 83 insertions(+), 58 deletions(-) diff --git a/auth/authenticate.py b/auth/authenticate.py index 354fc37a..5c4764c8 100644 --- a/auth/authenticate.py +++ b/auth/authenticate.py @@ -15,63 +15,65 @@ from settings import JWT_AUTH_HEADER class _Authenticate: - @classmethod - async def verify(cls, token: str): - """ - Rules for a token to be valid. - 1. token format is legal && - token exists in redis database && - token is not expired - 2. token format is legal && - token exists in redis database && - token is expired && - token is of specified type - """ - try: - payload = Token.decode(token) - except ExpiredSignatureError: - payload = Token.decode(token, verify_exp=False) - if not await cls.exists(payload.user_id, token): - raise InvalidToken("Login expired, please login again") - if payload.device == "mobile": # noqa - "we cat set mobile token to be valid forever" - return payload - except DecodeError as e: - raise InvalidToken("token format error") from e - else: - if not await cls.exists(payload.user_id, token): - raise InvalidToken("Login expired, please login again") - return payload + @classmethod + async def verify(cls, token: str): + """ + Rules for a token to be valid. + 1. token format is legal && + token exists in redis database && + token is not expired + 2. token format is legal && + token exists in redis database && + token is expired && + token is of specified type + """ + try: + payload = Token.decode(token) + except ExpiredSignatureError: + payload = Token.decode(token, verify_exp=False) + if not await cls.exists(payload.user_id, token): + raise InvalidToken("Login expired, please login again") + if payload.device == "mobile": # noqa + "we cat set mobile token to be valid forever" + return payload + except DecodeError as e: + raise InvalidToken("token format error") from e + else: + if not await cls.exists(payload.user_id, token): + raise InvalidToken("Login expired, please login again") + return payload - @classmethod - async def exists(cls, user_id, token): - token = await redis.execute("GET", f"{user_id}-{token}") - return token is not None + @classmethod + async def exists(cls, user_id, token): + token = await redis.execute("GET", f"{user_id}-{token}") + return token is not None class JWTAuthenticate(AuthenticationBackend): - async def authenticate( - self, request: HTTPConnection - ) -> Optional[Tuple[AuthCredentials, AuthUser]]: - if JWT_AUTH_HEADER not in request.headers: - return AuthCredentials(scopes=[]), AuthUser(user_id=None) + async def authenticate( + self, request: HTTPConnection + ) -> Optional[Tuple[AuthCredentials, AuthUser]]: + if JWT_AUTH_HEADER not in request.headers: + return AuthCredentials(scopes=[]), AuthUser(user_id=None) - token = request.headers[JWT_AUTH_HEADER] - try: - payload = await _Authenticate.verify(token) - except Exception as exc: - return AuthCredentials(scopes=[], error_message=str(exc)), AuthUser(user_id=None) + token = request.headers[JWT_AUTH_HEADER] + try: + payload = await _Authenticate.verify(token) + except Exception as exc: + return AuthCredentials(scopes=[], error_message=str(exc)), AuthUser(user_id=None) + + if payload is None: + return AuthCredentials(scopes=[]), AuthUser(user_id=None) - scopes = User.get_permission(user_id=payload.user_id) - print(scopes) - return AuthCredentials(user_id=payload.user_id, scopes=scopes, logged_in=True), AuthUser(user_id=payload.user_id) + scopes = User.get_permission(user_id=payload.user_id) + return AuthCredentials(user_id=payload.user_id, scopes=scopes, logged_in=True), AuthUser(user_id=payload.user_id) def login_required(func): - @wraps(func) - async def wrap(parent, info: GraphQLResolveInfo, *args, **kwargs): - auth: AuthCredentials = info.context["request"].auth - if not auth.logged_in: - return {"error" : auth.error_message or "Please login"} - return await func(parent, info, *args, **kwargs) - return wrap + @wraps(func) + async def wrap(parent, info: GraphQLResolveInfo, *args, **kwargs): + auth: AuthCredentials = info.context["request"].auth + if not auth.logged_in: + return {"error" : auth.error_message or "Please login"} + return await func(parent, info, *args, **kwargs) + return wrap diff --git a/orm/user.py b/orm/user.py index 7fec296f..804c7b2b 100644 --- a/orm/user.py +++ b/orm/user.py @@ -17,7 +17,7 @@ class UserRole(Base): class User(Base): __tablename__ = 'user' - email: str = Column(String, nullable=False) + email: str = Column(String, unique=True, nullable=False) username: str = Column(String, nullable=False, comment="Name") password: str = Column(String, nullable=True, comment="Password") @@ -32,7 +32,9 @@ class User(Base): user = session.query(User).filter(User.id == user_id).first() for role in user.roles: for p in role.permissions: - scope[p.resource_id] = p.operation_id + if not p.resource_id in scope: + scope[p.resource_id] = set() + scope[p.resource_id].add(p.operation_id) return scope diff --git a/resolvers/zine.py b/resolvers/zine.py index 97d311b3..581f820b 100644 --- a/resolvers/zine.py +++ b/resolvers/zine.py @@ -1,4 +1,4 @@ -from orm import Shout, User, Organization +from orm import Shout, User, Organization, Resource from orm.base import local_session from resolvers.base import mutation, query @@ -119,13 +119,16 @@ async def create_shout(_, info, input): @mutation.field("updateShout") @login_required -async def update_shout(_, info, shout_id, input): +async def update_shout(_, info, input): auth = info.context["request"].auth user_id = auth.user_id + slug = input["slug"] + org_id = org = input["org_id"] with local_session() as session: user = session.query(User).filter(User.id == user_id).first() - shout = session.query(Shout).filter(Shout.id == shout_id).first() + shout = session.query(Shout).filter(Shout.slug == slug).first() + org = session.query(Organization).filter(Organization.id == org_id).first() if not shout: return { @@ -133,12 +136,30 @@ async def update_shout(_, info, shout_id, input): } if shout.author_id != user_id: - scope = info.context["request"].scope - if not Resource.shout_id in scope: + scopes = auth.scopes + print(scopes) + if not Resource.shout_id in scopes: return { "error" : "access denied" } + shout.body = input["body"], + shout.replyTo = input.get("replyTo"), + shout.versionOf = input.get("versionOf"), + shout.tags = input.get("tags"), + shout.topics = input.get("topics") + + with local_session() as session: + session.commit() + + task = GitTask( + input, + org.name, + user.username, + user.email, + "update shout %s" % (shout.slug) + ) + return { "shout" : shout }