From 2d8dc5c3bd7eb09f76059664ac0d27d94f7fdb32 Mon Sep 17 00:00:00 2001 From: knst-kotov Date: Wed, 24 Nov 2021 18:53:01 +0300 Subject: [PATCH] add RoleStorage; add mutations for community --- auth/authenticate.py | 2 +- orm/__init__.py | 3 ++- orm/rbac.py | 31 ++++++++++++++++++++++++++++++- orm/user.py | 19 +++++++++---------- resolvers/community.py | 12 ++++++------ schema.graphql | 4 ++++ 6 files changed, 52 insertions(+), 19 deletions(-) diff --git a/auth/authenticate.py b/auth/authenticate.py index 3e5a43a6..bf09ddbf 100644 --- a/auth/authenticate.py +++ b/auth/authenticate.py @@ -71,7 +71,7 @@ class JWTAuthenticate(AuthenticationBackend): return AuthCredentials(scopes=[]), AuthUser(user_id=None) user = await UserStorage.get_user(payload.user_id) - scopes = user.get_permission() + scopes = await user.get_permission() return AuthCredentials(user_id=payload.user_id, scopes=scopes, logged_in=True), user class EmailAuthenticate: diff --git a/orm/__init__.py b/orm/__init__.py index a9b3dbc0..da7965d2 100644 --- a/orm/__init__.py +++ b/orm/__init__.py @@ -1,4 +1,4 @@ -from orm.rbac import Operation, Resource, Permission, Role +from orm.rbac import Operation, Resource, Permission, Role, RoleStorage from orm.community import Community from orm.user import User, UserRating, UserRole, UserStorage from orm.message import Message @@ -18,4 +18,5 @@ Resource.init_table() with local_session() as session: ShoutRatingStorage.init(session) ShoutViewStorage.init(session) + RoleStorage.init(session) UserStorage.init(session) diff --git a/orm/rbac.py b/orm/rbac.py index e6094027..24600113 100644 --- a/orm/rbac.py +++ b/orm/rbac.py @@ -1,9 +1,10 @@ import warnings from typing import Type +import asyncio from sqlalchemy import String, Integer, Column, ForeignKey, UniqueConstraint, TypeDecorator -from sqlalchemy.orm import relationship +from sqlalchemy.orm import relationship, selectinload from orm.base import Base, REGISTRY, engine, local_session @@ -72,6 +73,34 @@ class Permission(Base): operation_id: int = Column(ForeignKey("operation.id", ondelete="CASCADE"), nullable=False, comment="Operation") resource_id: int = Column(ForeignKey("resource.id", ondelete="CASCADE"), nullable=False, comment="Resource") +class RoleStorage: + roles = {} + lock = asyncio.Lock() + + @staticmethod + def init(session): + self = RoleStorage + roles = session.query(Role).\ + options(selectinload(Role.permissions)).all() + self.roles = dict([(role.id, role) for role in roles]) + + @staticmethod + async def get_role(id): + self = RoleStorage + async with self.lock: + return self.roles.get(id) + + @staticmethod + async def add_role(role): + self = RoleStorage + async with self.lock: + self.roles[id] = role + + @staticmethod + async def del_role(id): + self = RoleStorage + async with self.lock: + del self.roles[id] if __name__ == '__main__': Base.metadata.create_all(engine) diff --git a/orm/user.py b/orm/user.py index 2d00b648..25296d67 100644 --- a/orm/user.py +++ b/orm/user.py @@ -4,7 +4,7 @@ from datetime import datetime from sqlalchemy import Table, Column, Integer, String, ForeignKey, Boolean, DateTime, JSON as JSONType from sqlalchemy.orm import relationship, selectinload -from orm import Permission +from orm import RoleStorage from orm.base import Base, local_session from orm.rbac import Role from orm.topic import Topic @@ -63,15 +63,14 @@ class User(Base): topics = relationship(lambda: Topic, secondary=UserTopics) old_id: str = Column(String, nullable = True) - @classmethod - def get_permission(self): + async def get_permission(self): scope = {} - #TODO implement RoleStorage - #for role in self.roles: - # for p in role.permissions: - # if not p.resource_id in scope: - # scope[p.resource_id] = set() - # scope[p.resource_id].add(p.operation_id) + for user_role in self.roles: + role = await RoleStorage.get_role(user_role.id) + for p in role.permissions: + if not p.resource_id in scope: + scope[p.resource_id] = set() + scope[p.resource_id].add(p.operation_id) return scope class UserStorage: @@ -98,7 +97,7 @@ class UserStorage: self.users[id] = user @staticmethod - async def del_user(user): + async def del_user(id): self = UserStorage async with self.lock: del self.users[id] diff --git a/resolvers/community.py b/resolvers/community.py index e60f5585..114d2063 100644 --- a/resolvers/community.py +++ b/resolvers/community.py @@ -56,15 +56,15 @@ async def delete_community(_, info, id): @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: + with local_session() as session: + community = session.query(Community).filter(Community.slug == slug).first() + if not community: return {"error": "invalid community id"} return { community } @query.field("getCommunities") async def get_communities(_, info): - with local_session() as session: - communities = session.query(Community) - return { communities } \ No newline at end of file + with local_session() as session: + communities = session.query(Community) + return { communities } diff --git a/schema.graphql b/schema.graphql index 8e17e54d..6296b697 100644 --- a/schema.graphql +++ b/schema.graphql @@ -100,6 +100,10 @@ type Mutation { updateComment(id: Int!, body: String!): CommentResult! deleteComment(id: Int!): Result! rateComment(id: Int!, value: Int!): Result! + + createCommunity(title: String!, desc: String!): Community! + updateCommunity(id: Int!, title: String!, desc: String!, pic: String!): Community! + deleteCommunity(id: Int!): Result! } ################################### Query