From 44ee8a75f6d1affa5a9f1befb63def6c137a962d Mon Sep 17 00:00:00 2001 From: atomi <1456417373@qq.com> Date: Tue, 19 Sep 2023 17:37:36 +0800 Subject: [PATCH] feat: BaseAuthFieldModelAdmin add the perm_fields attribute and add the test file --- fastapi_amis_admin/admin/extensions/admin.py | 18 ++- .../admin/extensions/schemas.py | 1 + fastapi_amis_admin/admin/extensions/utils.py | 7 +- tests/test_admin/test_extensions/__init__.py | 0 .../test_BaseAuthFieldModelAdmin.py | 143 ++++++++++++++++++ 5 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 tests/test_admin/test_extensions/__init__.py create mode 100644 tests/test_admin/test_extensions/test_BaseAuthFieldModelAdmin.py diff --git a/fastapi_amis_admin/admin/extensions/admin.py b/fastapi_amis_admin/admin/extensions/admin.py index 40091ba2..b5ac6e1c 100644 --- a/fastapi_amis_admin/admin/extensions/admin.py +++ b/fastapi_amis_admin/admin/extensions/admin.py @@ -112,6 +112,8 @@ class BaseAuthFieldModelAdmin(ModelAdmin): #todo 优化 """ + perm_fields: Dict[Union[FieldPermEnum, int], Sequence[str]] = None + """指定的字段,进行权限验证.""" perm_fields_exclude: Dict[Union[FieldPermEnum, int], Sequence[str]] = None """exclude指定的字段,不进行权限验证.""" @@ -120,8 +122,6 @@ def __init__(self, app: "AdminApp"): def get_permission_fields(self, action: str) -> Dict[str, str]: """获取权限字段""" - if not self.perm_fields_exclude: - return {} info = { "list": (self.schema_list, "列表展示-", FieldPermEnum.LIST), "filter": (self.schema_filter, "列表筛选-", FieldPermEnum.FILTER), @@ -132,11 +132,17 @@ def get_permission_fields(self, action: str) -> Dict[str, str]: if action not in info: return {} schema, prefix, perm = info[action] - exlude = set() - for k, fileds in self.perm_fields_exclude.items(): + perm_fields_exclude = self.perm_fields_exclude or {} + perm_fields = self.perm_fields or {} + exclude = set() + for k, fields in perm_fields_exclude.items(): + if (k & perm) == perm: + exclude.update(set(fields)) + include = set() + for k, fields in perm_fields.items(): if (k & perm) == perm: - exlude.update(set(fileds)) - return get_schema_fields_name_label(schema, prefix=prefix, exclude_required=True, exclude=exlude) + include.update(set(fields)) + return get_schema_fields_name_label(schema, prefix=prefix, exclude_required=True, exclude=exclude, include=include) @cached_property def create_permission_fields(self) -> Dict[str, str]: diff --git a/fastapi_amis_admin/admin/extensions/schemas.py b/fastapi_amis_admin/admin/extensions/schemas.py index 9d8e82b0..5f5c1d54 100644 --- a/fastapi_amis_admin/admin/extensions/schemas.py +++ b/fastapi_amis_admin/admin/extensions/schemas.py @@ -44,6 +44,7 @@ class RecentTimeSelectPerm(SelectPerm): time_column: str = "create_time" def __post_init__(self): + super().__post_init__() # 如果td为int,则表示秒数 self.td = timedelta(seconds=self.td) if isinstance(self.td, int) else self.td diff --git a/fastapi_amis_admin/admin/extensions/utils.py b/fastapi_amis_admin/admin/extensions/utils.py index f091f9d0..804ce5bd 100644 --- a/fastapi_amis_admin/admin/extensions/utils.py +++ b/fastapi_amis_admin/admin/extensions/utils.py @@ -11,18 +11,21 @@ def get_schema_fields_name_label( prefix: str = "", exclude_required: bool = False, exclude: Iterable[str] = None, + include: Iterable[str] = None, ) -> Dict[str, str]: """获取schema字段名和标签.如果exclude中包含__all__,则返回空字典.""" if not schema: return {} - if exclude and "__all__" in exclude: + exclude = set(exclude or []) + if "__all__" in exclude: return {} + include = set(include or ["__all__"]) fields = {} for field in model_fields(schema).values(): if exclude_required and field.required: continue name = field.alias or field.name - if exclude and name in exclude: + if name in exclude or (name not in include and "__all__" not in include): continue label = field.field_info.title or field.name fields[name] = prefix + label diff --git a/tests/test_admin/test_extensions/__init__.py b/tests/test_admin/test_extensions/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_admin/test_extensions/test_BaseAuthFieldModelAdmin.py b/tests/test_admin/test_extensions/test_BaseAuthFieldModelAdmin.py new file mode 100644 index 00000000..ec125d79 --- /dev/null +++ b/tests/test_admin/test_extensions/test_BaseAuthFieldModelAdmin.py @@ -0,0 +1,143 @@ +from fastapi_amis_admin import admin +from fastapi_amis_admin.admin import AdminSite, FieldPermEnum + + +async def test_perm_fields(site: AdminSite, models): + @site.register_admin + class ArticleAdmin(admin.BaseAuthFieldModelAdmin): + model = models.Article + read_fields = [ + models.Article.id, + models.Article.title, + models.Article.description, + models.Article.status, + models.Article.category_id, + ] + perm_fields = { + FieldPermEnum.VIEW: ["id", "title"], + FieldPermEnum.UPDATE: ["status"], + FieldPermEnum.CREATE: ["description", "status"], + } + + site.register_router() + ins = site.get_admin_or_create(ArticleAdmin) + # create_permission_fields + assert "description" in ins.create_permission_fields + assert "status" in ins.create_permission_fields + assert "category_id" not in ins.create_permission_fields + + # update_permission_fields + assert "status" in ins.update_permission_fields + assert "category_id" not in ins.update_permission_fields + + # read_permission_fields + assert "id" in ins.read_permission_fields + # title not in read_permission_fields, because title is required in schema_read + assert "title" not in ins.read_permission_fields + assert "category_id" not in ins.read_permission_fields + + # list_permission_fields + assert "id" in ins.list_permission_fields + assert "title" in ins.list_permission_fields + assert "category_id" not in ins.create_permission_fields + + # filter_permission_fields + assert "id" in ins.filter_permission_fields + assert "title" in ins.filter_permission_fields + assert "category_id" not in ins.create_permission_fields + + +async def test_perm_fields_exclude(site: AdminSite, models): + @site.register_admin + class ArticleAdmin(admin.BaseAuthFieldModelAdmin): + model = models.Article + read_fields = [ + models.Article.id, + models.Article.title, + models.Article.description, + models.Article.status, + models.Article.category_id, + ] + perm_fields_exclude = { + FieldPermEnum.VIEW: ["id", "title"], + FieldPermEnum.UPDATE: ["status"], + FieldPermEnum.CREATE: ["description", "status"], + } + + site.register_router() + ins = site.get_admin_or_create(ArticleAdmin) + # create_permission_fields + assert "description" not in ins.create_permission_fields + assert "status" not in ins.create_permission_fields + assert "category_id" in ins.create_permission_fields + + # update_permission_fields + assert "status" not in ins.update_permission_fields + assert "category_id" in ins.update_permission_fields + + # read_permission_fields + assert "id" not in ins.read_permission_fields + # title not in read_permission_fields, because title is required in schema_read + assert "title" not in ins.read_permission_fields + assert "category_id" in ins.read_permission_fields + + # list_permission_fields + assert "id" not in ins.list_permission_fields + assert "title" not in ins.list_permission_fields + assert "category_id" in ins.create_permission_fields + + # filter_permission_fields + assert "id" not in ins.filter_permission_fields + assert "title" not in ins.filter_permission_fields + assert "category_id" in ins.create_permission_fields + + +async def test_perm_fields_and_exclude(site: AdminSite, models): + @site.register_admin + class ArticleAdmin(admin.BaseAuthFieldModelAdmin): + model = models.Article + read_fields = [ + models.Article.id, + models.Article.title, + models.Article.description, + models.Article.status, + models.Article.category_id, + ] + perm_fields = { + FieldPermEnum.VIEW: ["id", "title"], + FieldPermEnum.UPDATE: ["status", "title"], + FieldPermEnum.CREATE: ["description", "status"], + } + perm_fields_exclude = { + FieldPermEnum.VIEW: ["title"], + FieldPermEnum.UPDATE: ["status"], + FieldPermEnum.CREATE: ["description"], + } + + site.register_router() + ins = site.get_admin_or_create(ArticleAdmin) + # create_permission_fields + assert "description" not in ins.create_permission_fields + assert "status" in ins.create_permission_fields + assert "category_id" not in ins.create_permission_fields + + # update_permission_fields + assert "title" in ins.update_permission_fields + assert "status" not in ins.update_permission_fields + assert "category_id" not in ins.update_permission_fields + + # read_permission_fields + assert "id" in ins.read_permission_fields + # title not in read_permission_fields, because title is required in schema_read + assert "title" not in ins.read_permission_fields + assert "category_id" not in ins.read_permission_fields + + # list_permission_fields + assert "id" in ins.list_permission_fields + assert "title" not in ins.list_permission_fields + assert "category_id" not in ins.create_permission_fields + + # filter_permission_fields + assert "id" in ins.filter_permission_fields + assert "title" not in ins.filter_permission_fields + assert "category_id" not in ins.create_permission_fields