From 786bd20275a4f83511f8ede73d8f94b8ed78b339 Mon Sep 17 00:00:00 2001 From: tonyrewin Date: Thu, 24 Nov 2022 11:27:01 +0300 Subject: [PATCH] init --- auth/authenticate.py | 15 ++++++ migration/tables/replacements.json | 1 + orm/__init__.py | 2 +- orm/community.py | 12 ++--- orm/rbac.py | 84 ++++++++++++++++++++++++------ resolvers/auth.py | 2 +- 6 files changed, 91 insertions(+), 25 deletions(-) diff --git a/auth/authenticate.py b/auth/authenticate.py index 425b5d1d..6a84214f 100644 --- a/auth/authenticate.py +++ b/auth/authenticate.py @@ -89,3 +89,18 @@ def login_required(func): return await func(parent, info, *args, **kwargs) return wrap + + +def permission_required(resource, operation, func): + @wraps(func) + async def wrap(parent, info: GraphQLResolveInfo, *args, **kwargs): + # print('[auth.authenticate] login required for %r with info %r' % (func, info)) # debug only + auth: AuthCredentials = info.context["request"].auth + if not auth.logged_in: + return {"error": auth.error_message or "Please login"} + + # TODO: add check permission logix + + return await func(parent, info, *args, **kwargs) + + return wrap diff --git a/migration/tables/replacements.json b/migration/tables/replacements.json index 74a0cc68..0aa081d2 100644 --- a/migration/tables/replacements.json +++ b/migration/tables/replacements.json @@ -420,6 +420,7 @@ "marketing": "marketing", "marksizm": "marxism", "marsel-dyushan": "marchel-duchamp", + "marsel-prust": "marcel-proust", "martin-haydegger": "martin-hidegger", "matematika": "maths", "mayakovskiy": "vladimir-mayakovsky", diff --git a/orm/__init__.py b/orm/__init__.py index dfe0a323..c8251256 100644 --- a/orm/__init__.py +++ b/orm/__init__.py @@ -32,8 +32,8 @@ def init_tables(): Resource.init_table() User.init_table() Community.init_table() + Role.init_table() UserRating.init_table() Shout.init_table() - Role.init_table() ViewedEntry.init_table() print("[orm] tables initialized") diff --git a/orm/community.py b/orm/community.py index d789d0e3..8c339714 100644 --- a/orm/community.py +++ b/orm/community.py @@ -1,7 +1,6 @@ from datetime import datetime -from sqlalchemy import Column, String, ForeignKey, DateTime, Boolean - +from sqlalchemy import Column, String, ForeignKey, DateTime from base.orm import Base, local_session @@ -11,10 +10,10 @@ class CommunityFollower(Base): id = None # type: ignore follower = Column(ForeignKey("user.slug"), primary_key=True) community = Column(ForeignKey("community.slug"), primary_key=True) - createdAt = Column( + joinedAt = Column( DateTime, nullable=False, default=datetime.now, comment="Created at" ) - auto = Column(Boolean, nullable=False, default=False) + # role = Column(ForeignKey(Role.id), nullable=False, comment="Role for member") class Community(Base): @@ -27,7 +26,6 @@ class Community(Base): createdAt = Column( DateTime, nullable=False, default=datetime.now, comment="Created at" ) - createdBy = Column(ForeignKey("user.slug"), nullable=False, comment="Author") @staticmethod def init_table(): @@ -36,9 +34,7 @@ class Community(Base): session.query(Community).filter(Community.slug == "discours").first() ) if not d: - d = Community.create( - name="Дискурс", slug="discours", createdBy="anonymous" - ) + d = Community.create(name="Дискурс", slug="discours") session.add(d) session.commit() Community.default_community = d diff --git a/orm/rbac.py b/orm/rbac.py index fccfc5ae..ad288798 100644 --- a/orm/rbac.py +++ b/orm/rbac.py @@ -7,6 +7,8 @@ from base.orm import Base, REGISTRY, engine, local_session from orm.community import Community +# Role Based Access Control # + class ClassType(TypeDecorator): impl = String @@ -42,18 +44,44 @@ class Role(Base): @staticmethod def init_table(): with local_session() as session: - default = session.query(Role).filter(Role.name == "author").first() - if default: - Role.default_role = default - return + r = session.query(Role).filter(Role.name == "author").first() + if r: + Role.default_role = r + return - default = Role.create( + r1 = Role.create( name="author", - desc="Role for author", + desc="Role for an author", community=1, ) - Role.default_role = default + session.add(r1) + + Role.default_role = r1 + + r2 = Role.create( + name="reader", + desc="Role for a reader", + community=1, + ) + + session.add(r2) + + r3 = Role.create( + name="expert", + desc="Role for an expert", + community=1, + ) + + session.add(r3) + + r4 = Role.create( + name="editor", + desc="Role for an editor", + community=1, + ) + + session.add(r4) class Operation(Base): @@ -63,10 +91,33 @@ class Operation(Base): @staticmethod def init_table(): with local_session() as session: - edit_op = session.query(Operation).filter(Operation.name == "edit").first() - if not edit_op: - edit_op = Operation.create(name="edit") - Operation.edit_id = edit_op.id # type: ignore + for name in ["create", "update", "delete", "load"]: + """ + * everyone can: + - load shouts + - load topics + - load reactions + - create an account to become a READER + * readers can: + - update and delete their account + - load chats + - load messages + - create reaction of some shout's author allowed kinds + - create shout to become an AUTHOR + * authors can: + - update and delete their shout + - invite other authors to edit shout and chat + - manage allowed reactions for their shout + * pros can: + - create/update/delete their community + - create/update/delete topics for their community + + """ + op = session.query(Operation).filter(Operation.name == name).first() + if not op: + op = Operation.create(name=name) + session.add(op) + session.commit() class Resource(Base): @@ -75,14 +126,17 @@ class Resource(Base): String, nullable=False, unique=True, comment="Resource class" ) name = Column(String, nullable=False, unique=True, comment="Resource name") + # TODO: community = Column(ForeignKey()) @staticmethod def init_table(): with local_session() as session: - shout_res = session.query(Resource).filter(Resource.name == "shout").first() - if not shout_res: - shout_res = Resource.create(name="shout", resource_class="shout") - Resource.shout_id = shout_res.id # type: ignore + for res in ["shout", "topic", "reaction", "chat", "message", "invite", "community", "user"]: + r = session.query(Resource).filter(Resource.name == res).first() + if not r: + r = Resource.create(name=res, resource_class=res) + session.add(r) + session.commit() class Permission(Base): diff --git a/resolvers/auth.py b/resolvers/auth.py index 8f9fe0e9..54947f9a 100644 --- a/resolvers/auth.py +++ b/resolvers/auth.py @@ -80,8 +80,8 @@ async def confirm_email_handler(request): def create_user(user_dict): user = User(**user_dict) - user.roles.append(Role.default_role) with local_session() as session: + user.roles.append(session.query(Role).first()) session.add(user) session.commit() return user