diff --git a/fastapi_admin/common.py b/fastapi_admin/common.py index 8ddfa8a..ca66a9c 100644 --- a/fastapi_admin/common.py +++ b/fastapi_admin/common.py @@ -1,6 +1,7 @@ import importlib from copy import deepcopy +from fastapi import HTTPException from passlib.context import CryptContext from tortoise import Tortoise diff --git a/fastapi_admin/depends.py b/fastapi_admin/depends.py index 07140e6..4d69f30 100644 --- a/fastapi_admin/depends.py +++ b/fastapi_admin/depends.py @@ -10,6 +10,7 @@ from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN, HTTP_404 from . import enums from .factory import app +from .models import AbstractUser auth_schema = HTTPBearer() @@ -137,21 +138,12 @@ class HasPermission: def __init__(self, action: enums.PermissionAction): self.action = action - async def __call__(self, resource: str = Path(...), user=Depends(get_current_user)): - if not app.permission or user.is_superuser: - return True # Hmm. Should superuser really cirumvent all permission checks. not a good practice!?!?!?!!?!!! - if not user.is_active: - return False - has_permission = False - await user.fetch_related("roles") - for role in user.roles: - if await role.permissions.filter(model=resource, action=self.action): - return True - if not has_permission: - return False - -has_read_permission = HasPermission(action=enums.PermissionAction.read) -has_create_permission = HasPermission(action=enums.PermissionAction.create) -has_update_permission = HasPermission(action=enums.PermissionAction.update) -has_delete_permission = HasPermission(action=enums.PermissionAction.delete) +async def has_resource_permission( + action: enums.PermissionAction, resource: str, user: AbstractUser +) -> bool: + try: + await PermissionsChecker(action=action)(resource, user) + return True + except HTTPException: + return False diff --git a/fastapi_admin/routes/rest.py b/fastapi_admin/routes/rest.py index c1eb082..5042aca 100644 --- a/fastapi_admin/routes/rest.py +++ b/fastapi_admin/routes/rest.py @@ -12,6 +12,7 @@ from tortoise.contrib.pydantic import pydantic_model_creator from tortoise.exceptions import IntegrityError from tortoise.fields import ManyToManyRelation +from .. import enums from ..common import handle_m2m_fields_create_or_update from ..depends import ( QueryItem, @@ -23,10 +24,7 @@ from ..depends import ( get_current_user, get_model, get_query, - has_create_permission, - has_delete_permission, - has_read_permission, - has_update_permission, + has_resource_permission, parse_body, read_checker, update_checker, @@ -129,14 +127,16 @@ async def form(resource: str,): @router.get("/{resource}/grid", dependencies=[Depends(read_checker)]) async def grid(resource: str, user=Depends(get_current_user)): - resource = await app.get_resource(resource) - resource = resource.dict(by_alias=True, exclude_unset=True) - resource["fields"]["_actions"] = { - "delete": await has_delete_permission(resource, user), - "edit": await has_update_permission(resource, user), - "toolbar": {"create": await has_create_permission(resource, user)}, + fetched_resource = await app.get_resource(resource) + resource_response = fetched_resource.dict(by_alias=True, exclude_unset=True) + resource_response["fields"]["_actions"] = { + "delete": await has_resource_permission(enums.PermissionAction.delete, resource, user), + "edit": await has_resource_permission(enums.PermissionAction.update, resource, user), + "toolbar": { + "create": await has_resource_permission(enums.PermissionAction.create, resource, user) + }, } - return resource + return resource_response @router.get("/{resource}/view", dependencies=[Depends(read_checker)])