From 123537cd1699b35c311a47e763408f1a158c75a3 Mon Sep 17 00:00:00 2001 From: Patrick Jentsch Date: Fri, 3 Dec 2021 14:07:03 +0100 Subject: [PATCH] Add new roles and a new permission --- app/__init__.py | 3 ++- app/decorators.py | 39 ++++++++++++++++++++++++++++++---- app/models.py | 13 +++++++++--- app/templates/_sidenav.html.j2 | 6 ++++-- app/utils.py | 5 +++++ 5 files changed, 56 insertions(+), 10 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index c6df4293..0b14dc23 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -39,8 +39,9 @@ def create_app(config_class=Config): message_queue=app.config.get('NOPAQUE_SOCKETIO_MESSAGE_QUEUE_URI') ) - from .utils import HashidConverter + from .utils import HashidConverter, permission_context_processor app.url_map.converters['hashid'] = HashidConverter + app.context_processor(permission_context_processor) from .events import socketio as socketio_events from .events import sqlalchemy as sqlalchemy_events diff --git a/app/decorators.py b/app/decorators.py index 98809122..74b37a66 100644 --- a/app/decorators.py +++ b/app/decorators.py @@ -2,16 +2,47 @@ from flask import abort, current_app from flask_login import current_user from functools import wraps from threading import Thread +from .models import Permission + + +def permission_required(permission): + def decorator(f): + @wraps(f) + def decorated_function(*args, **kwargs): + if not current_user.can(permission): + abort(403) + return f(*args, **kwargs) + return decorated_function + return decorator def admin_required(f): + return permission_required(Permission.ADMINISTRATE)(f) + + +def socketio_login_required(f): @wraps(f) - def wrapped(*args, **kwargs): - if current_user.is_administrator: + def decorated_function(*args, **kwargs): + if current_user.is_authenticated: return f(*args, **kwargs) else: - abort(403) - return wrapped + return {'code': 401, 'msg': 'Unauthorized'} + return decorated_function + + +def socketio_permission_required(permission): + def decorator(f): + @wraps(f) + def decorated_function(*args, **kwargs): + if not current_user.can(permission): + return {'code': 403, 'msg': 'Forbidden'} + return f(*args, **kwargs) + return decorated_function + return decorator + + +def socketio_admin_required(f): + return socketio_permission_required(Permission.ADMINISTRATE)(f) def background(f): diff --git a/app/models.py b/app/models.py index 1572a144..a00db66d 100644 --- a/app/models.py +++ b/app/models.py @@ -38,8 +38,9 @@ class Permission(enum.IntEnum): Defines User permissions as integers by the power of 2. User permission can be evaluated using the bitwise operator &. ''' - ADMINISTRATE = 1 - USE_API = 2 + ADMINISTRATE = 4 + CONTRIBUTE = 2 + USE_API = 1 class Role(HashidMixin, db.Model): @@ -93,7 +94,13 @@ class Role(HashidMixin, db.Model): def insert_roles(): roles = { 'User': [], - 'Administrator': [Permission.USE_API, Permission.ADMINISTRATE] + 'API user': [Permission.USE_API], + 'Contributor': [Permission.CONTRIBUTE], + 'Administrator': [ + Permission.ADMINISTRATE, + Permission.CONTRIBUTE, + Permission.USE_API + ] } default_role_name = 'User' for role_name, permissions in roles.items(): diff --git a/app/templates/_sidenav.html.j2 b/app/templates/_sidenav.html.j2 index aaa71647..e50e345a 100644 --- a/app/templates/_sidenav.html.j2 +++ b/app/templates/_sidenav.html.j2 @@ -22,10 +22,12 @@
  • Account
  • settingsSettings
  • Log out
  • - {% if current_user.is_administrator() %} + {% if current_user.can(Permission.ADMINISTRATE) %}
  • -
  • Administration
  • +
  • Specials
  • admin_panel_settingsAdministration
  • + {% endif %} + {% if current_user.can(Permission.USE_API) %}
  • apiAPI
  • {% endif %} diff --git a/app/utils.py b/app/utils.py index a320d4bb..04ca4a45 100644 --- a/app/utils.py +++ b/app/utils.py @@ -1,5 +1,6 @@ from app import hashids from werkzeug.routing import BaseConverter +from .models import Permission class HashidConverter(BaseConverter): @@ -8,3 +9,7 @@ class HashidConverter(BaseConverter): def to_url(self, value): return hashids.encode(value) + + +def permission_context_processor(): + return {'Permission': Permission}