Skip to content

feat: UserResourcePermission #3039

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions apps/common/auth/handle/impl/user_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,14 @@ def get_workspace_resource_permission_list_by_workspace_user_permission(
workspace_user_resource_permission.workspace_id)]
role_permission_mapping_list = reduce(lambda x, y: [*x, *y], role_permission_mapping_list, [])
# 如果是根据角色
if (workspace_user_resource_permission.auth_target_type == ResourceAuthType.ROLE
if (workspace_user_resource_permission.auth_type == ResourceAuthType.ROLE
and workspace_user_resource_permission.permission_list.__contains__(
ResourcePermissionRole.ROLE)):
return [
f"{role_permission_mapping.permission_id}:/WORKSPACE/{workspace_user_resource_permission.workspace_id}/{workspace_user_resource_permission.auth_target_type}/{workspace_user_resource_permission.target}"
for role_permission_mapping in role_permission_mapping_list]

elif workspace_user_resource_permission.auth_target_type == ResourceAuthType.RESOURCE_PERMISSION_GROUP:
elif workspace_user_resource_permission.auth_type == ResourceAuthType.RESOURCE_PERMISSION_GROUP:
resource_permission_list = [
[
f"{permission}:/WORKSPACE/{workspace_user_resource_permission.workspace_id}/{workspace_user_resource_permission.auth_target_type}/{workspace_user_resource_permission.target}"
Expand Down Expand Up @@ -136,7 +136,7 @@ def get_permission_list(user,
# 获取工作空间 用户 角色映射数据
workspace_user_role_mapping_list = QuerySet(workspace_user_role_mapping_model).filter(user_id=user_id)
workspace_user_role_mapping_dict = group_by(workspace_user_role_mapping_list,
lambda item: item.role_id)
lambda item: item.workspace_id)
# 获取角色权限映射数据
role_permission_mapping_list = QuerySet(role_permission_mapping_model).filter(
role_id__in=[workspace_user_role_mapping.role_id for workspace_user_role_mapping in
Expand Down Expand Up @@ -168,7 +168,7 @@ def get_permission_list(user,
role_permission_mapping_dict = group_by(role_permission_mapping_list, lambda item: item.role_id)
workspace_user_role_mapping_list = get_default_workspace_user_role_mapping_list([user.role])
workspace_user_role_mapping_dict = group_by(workspace_user_role_mapping_list,
lambda item: item.role_id)
lambda item: item.workspace_id)
# 资源权限
workspace_resource_permission_list = get_workspace_resource_permission_list(
workspace_user_resource_permission_list,
Expand Down
7 changes: 7 additions & 0 deletions apps/common/constants/permission_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class Group(Enum):

TOOL = "TOOL"

WORKSPACE_USER_RESOURCE_PERMISSION = "WORKSPACE_USER_RESOURCE_PERMISSION"


class Operate(Enum):
"""
Expand Down Expand Up @@ -218,6 +220,11 @@ class PermissionConstants(Enum):
KNOWLEDGE_CREATE = Permission(group=Group.KNOWLEDGE, operate=Operate.CREATE, role_list=[RoleConstants.ADMIN,
RoleConstants.USER])

WORKSPACE_USER_RESOURCE_PERMISSION_READ = Permission(group=Group.WORKSPACE_USER_RESOURCE_PERMISSION,
operate=Operate.READ,
role_list=[RoleConstants.ADMIN,
RoleConstants.WORKSPACE_MANAGE])

def get_workspace_application_permission(self):
return lambda r, kwargs: Permission(group=self.value.group, operate=self.value.operate,
resource_path=
Expand Down
1 change: 1 addition & 0 deletions apps/maxkb/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
path("api/", include("models_provider.urls")),
path("api/", include("folders.urls")),
path("api/", include("knowledge.urls")),
path("api/", include("system_manage.urls")),
]
urlpatterns += [
path('schema/', SpectacularAPIView.as_view(), name='schema'), # schema的配置文件的路由,下面两个ui也是根据这个配置文件来生成的
Expand Down
8 changes: 8 additions & 0 deletions apps/system_manage/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# coding=utf-8
"""
@project: MaxKB
@Author:虎虎
@file: __init__.py
@date:2025/4/28 17:05
@desc:
"""
44 changes: 44 additions & 0 deletions apps/system_manage/api/user_resource_permission.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# coding=utf-8
"""
@project: MaxKB
@Author:虎虎
@file: workspace_user_resource_permission.py
@date:2025/4/28 18:13
@desc:
"""
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter

from common.mixins.api_mixin import APIMixin
from common.result import ResultSerializer
from system_manage.serializers.user_resource_permission import UserResourcePermissionResponse, \
UpdateUserResourcePermissionRequest


class APIUserResourcePermissionResponse(ResultSerializer):
def get_data(self):
return UserResourcePermissionResponse(many=True)


class UserResourcePermissionAPI(APIMixin):
@staticmethod
def get_parameters():
return [
OpenApiParameter(
name="workspace_id",
description="工作空间id",
type=OpenApiTypes.STR,
location='path',
required=True,
)
]

@staticmethod
def get_response():
return APIUserResourcePermissionResponse


class EditUserResourcePermissionAPI(APIMixin):
@staticmethod
def get_request():
return UpdateUserResourcePermissionRequest()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code is mostly structured correctly. Here are some minor improvements and considerations:

  1. Docstring Formatting: The docstrings can be more detailed if you include additional information about what each part of the class does (UserResourcePermissionAPI and EditUserResourcePermissionAPI).

  2. Class Method Naming: While not strictly necessary, using get_* for methods that return something makes it clear what they do.

  3. Type Annotations: Ensure all parameters have annotations to improve readability and maintainability.

Here's an updated version with improved documentation and type annotations:

# coding=utf-8
"""
@project: MaxKB
@author: Tiger Tiger
@file: workspace_user_resource_permission.py
@date: 2025/4/28 18:13
@desc:
"""

from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter

from common.mixins.api_mixin import APIMixin
from common.results import ResultSerializer
from system_manage.serializers.user_resource_permission import (
    UserResourcePermissionResponse,
    UpdateUserResourcePermissionRequest,
)

class APIUserResourcePermissionResponse(ResultSerializer):
    """Return a list of UserResourcePermission objects."""
    
    def get_data(self) -> List['UserResourcePermission']:
        return super().get_data()

    

class UserResourcePermissionAPI(APIMixin):
    """
    Provides operations related to user resource permissions within a specified workspace.
    
    Attributes:
        response_class (ResultSerializer): A custom serializer for the response data.
        
    Methods:
        get_parameters(): Define query parameters used in GET requests.
        get_response(): Return the serialized response object.
    """

    @staticmethod
    def get_parameters() -> List[OpenApiParameter]:
        """Define the allowed parameters for GET requests."""
        return [
            OpenApiParameter(
                name="workspace_id",
                description="ID of the workspace.",
                type=OpenApiTypes.STR,
                location='path',
                required=True,
            ),
        ]

    @staticmethod
    def get_response(cls=None) -> Type[APIUserResourcePermissionResponse]:
        """Return the default response serializer class."""
        return cls.response_class or APIUserResourcePermissionResponse


class EditUserResourcePermissionAPI(APIMixin):
    """
    Allows editing the permissions linked to a user within a specific workspace.
    
    Attributes:
        request_serializer_cls (BaseSerializer): The serializer class used for receiving
                                               permission updates from clients.
    """
    
    @staticmethod
    def get_request(request_serializer_cls=None) -> BaseSerializer:
        """Return the serializer instance for handling permission update requests."""
        return request_serializer_cls or UpdateUserResourcePermissionRequest

Key Changes:

  • Added comments describing classes and their functionality.
  • Used type hints throughout, making the code easier to understand.
  • Clarified method purpose and attributes where appropriate.
  • Ensured the structure remains logical and consistent across similar APIs.

8 changes: 8 additions & 0 deletions apps/system_manage/serializers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# coding=utf-8
"""
@project: MaxKB
@Author:虎虎
@file: __init__.py
@date:2025/4/28 17:05
@desc:
"""
155 changes: 155 additions & 0 deletions apps/system_manage/serializers/user_resource_permission.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# coding=utf-8
"""
@project: MaxKB
@Author:虎虎
@file: workspace_user_resource_permission.py
@date:2025/4/28 17:17
@desc:
"""
import json
import os

from django.core.cache import cache
from django.db.models import QuerySet
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers

from common.constants.cache_version import Cache_Version
from common.constants.permission_constants import get_default_workspace_user_role_mapping_list, RoleConstants, \
ResourcePermissionGroup, ResourcePermissionRole, ResourceAuthType
from common.database_model_manage.database_model_manage import DatabaseModelManage
from common.db.search import native_search
from common.db.sql_execute import select_list
from common.exception.app_exception import AppApiException
from common.utils.common import get_file_content
from common.utils.split_model import group_by
from knowledge.models import Knowledge
from maxkb.conf import PROJECT_DIR
from system_manage.models import WorkspaceUserResourcePermission, AuthTargetType


class PermissionSerializer(serializers.Serializer):
VIEW = serializers.BooleanField(required=True, label="可读")
MANAGE = serializers.BooleanField(required=True, label="管理")
ROLE = serializers.BooleanField(required=True, label="跟随角色")


class UserResourcePermissionItemResponse(serializers.Serializer):
id = serializers.UUIDField(required=True, label="主键id")
name = serializers.CharField(required=True, label="资源名称")
auth_target_type = serializers.ChoiceField(required=True, choices=AuthTargetType.choices, label="授权资源")
user_id = serializers.UUIDField(required=True, label="用户id")
auth_type = serializers.ChoiceField(required=True, choices=ResourceAuthType.choices, label="授权类型")
permission = PermissionSerializer()


class UserResourcePermissionResponse(serializers.Serializer):
KNOWLEDGE = UserResourcePermissionItemResponse(many=True)


class UpdateTeamMemberItemPermissionSerializer(serializers.Serializer):
auth_target_type = serializers.ChoiceField(required=True, choices=AuthTargetType.choices, label="授权资源")
target_id = serializers.CharField(required=True, label=_('target id'))
auth_type = serializers.ChoiceField(required=True, choices=ResourceAuthType.choices, label="授权类型")
permission = PermissionSerializer(required=True, many=False)


class UpdateUserResourcePermissionRequest(serializers.Serializer):
user_resource_permission_list = UpdateTeamMemberItemPermissionSerializer(required=True, many=True)

def is_valid(self, *, workspace_id=None, raise_exception=False):
super().is_valid(raise_exception=True)
user_resource_permission_list = self.data.get("user_resource_permission_list")
illegal_target_id_list = select_list(
get_file_content(
os.path.join(PROJECT_DIR, "apps", "system_manage", 'sql', 'check_member_permission_target_exists.sql')),
[json.dumps(user_resource_permission_list), workspace_id])
if illegal_target_id_list is not None and len(illegal_target_id_list) > 0:
raise AppApiException(500,
_('Non-existent application|knowledge base id[') + str(illegal_target_id_list) + ']')


class UserResourcePermissionSerializer(serializers.Serializer):
workspace_id = serializers.CharField(required=True, label=_('workspace id'))

def get_queryset(self):
return {
"knowledge_query_set": QuerySet(Knowledge)
.filter(workspace_id=self.data.get('workspace_id')),
'workspace_user_resource_permission_query_set': QuerySet(WorkspaceUserResourcePermission).filter(
workspace_id=self.data.get('workspace_id'))
}

def list(self, user, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
workspace_id = self.data.get("workspace_id")
# 用户权限列表
user_resource_permission_list = native_search(self.get_queryset(), get_file_content(
os.path.join(PROJECT_DIR, "apps", "system_manage", 'sql', 'get_user_resource_permission.sql')))
workspace_user_role_mapping_model = DatabaseModelManage.get_model("workspace_user_role_mapping")
workspace_model = DatabaseModelManage.get_model("workspace_model")
if workspace_user_role_mapping_model and workspace_model:
workspace_user_role_mapping_list = QuerySet(workspace_user_role_mapping_model).filter(user_id=user.id,
workspace_id=workspace_id)
else:
workspace_user_role_mapping_list = get_default_workspace_user_role_mapping_list([user.role])
is_workspace_manage = any(
[workspace_user_role_mapping for workspace_user_role_mapping in workspace_user_role_mapping_list if
workspace_user_role_mapping.role_id == RoleConstants.WORKSPACE_MANAGE.value])
# 如果当前用户是当前工作空间管理员那么就拥有所有权限
if is_workspace_manage:
user_resource_permission_list = list(
map(lambda row: {**row,
'permission': {ResourcePermissionGroup.VIEW.value: True,
ResourcePermissionGroup.MANAGE.value: True,
ResourcePermissionRole.ROLE.value: True}},
user_resource_permission_list))
return group_by([{**user_resource_permission, 'permission': {
permission: True if user_resource_permission.get('permission_list').__contains__(permission) else False for
permission in
[ResourcePermissionGroup.VIEW.value, ResourcePermissionGroup.MANAGE.value,
ResourcePermissionRole.ROLE.value]}}
for user_resource_permission in user_resource_permission_list],
key=lambda item: item.get('auth_target_type'))

def edit(self, instance, user, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
UpdateUserResourcePermissionRequest(data=instance).is_valid(raise_exception=True,
workspace_id=self.data.get('workspace_id'))
workspace_id = self.data.get("workspace_id")
update_list = []
save_list = []
user_resource_permission_list = instance.get('user_resource_permission_list')
workspace_user_resource_permission_exist_list = QuerySet(WorkspaceUserResourcePermission).filter(
workspace_id=workspace_id)
for user_resource_permission in user_resource_permission_list:
exist_list = [user_resource_permission_exist for user_resource_permission_exist in
workspace_user_resource_permission_exist_list if
user_resource_permission.get('target_id') == str(user_resource_permission_exist.target)]
if len(exist_list) > 0:
exist_list[0].permission_list = [key for key in user_resource_permission.get('permission').keys() if
user_resource_permission.get('permission').get(key)]
update_list.append(exist_list[0])
else:
save_list.append(WorkspaceUserResourcePermission(target=user_resource_permission.get('target_id'),
auth_target_type=user_resource_permission.get(
'auth_target_type'),
permission_list=[key for key in
user_resource_permission.get(
'permission').keys() if
user_resource_permission.get(
'permission').get(key)],
workspace_id=workspace_id,
user_id=user.id,
auth_type=user_resource_permission.get('auth_type')))
# 批量更新
QuerySet(WorkspaceUserResourcePermission).bulk_update(update_list, ['permission_list']) if len(
update_list) > 0 else None
# 批量插入
QuerySet(WorkspaceUserResourcePermission).bulk_create(save_list) if len(save_list) > 0 else None
version = Cache_Version.PERMISSION_LIST.get_version()
key = Cache_Version.PERMISSION_LIST.get_key(user_id=str(user.id))
cache.delete(key, version=version)
return True
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are several areas of concern and opportunities for improvement in this code:


Potential Issues/Corrections:

  1. Missing Imports: Some imported classes or methods might be missing from the project environment.

  2. Database Model Existence Check: The SQL queries used for checking whether target IDs exist seem fragile if models change. Consider using ORM calls instead for better reliability.

  3. Cache Key Logic: The use of custom cache keys like Cache_Version.PERMISSION_LIST.get_key(str(user.id)) may need to adjust based on context.

  4. Code Readability: Certain sections can be made more readable by adding comments where appropriate.

  5. Null Checks: Ensure that all data fields fetched from the database are checked for null values before using them, especially when dealing with optional parameters.

  6. Exception Handling: More robust exception handling could enhance error management in critical parts of the code.

  7. Security Concerns: Be cautious about exposing sensitive information such as file paths directly in the codebase. Perhaps consider using an environmental variable for these settings.

  8. Performance Optimizations: For large datasets, consider optimizations such as using batch processing or optimizing DB queries.


16 changes: 16 additions & 0 deletions apps/system_manage/sql/check_member_permission_target_exists.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
SELECT
static_temp."target_id"::text
FROM
(SELECT * FROM json_to_recordset(
%s
) AS x(target_id uuid,auth_target_type text)) static_temp
LEFT JOIN (
SELECT
"id",
'KNOWLEDGE' AS "auth_target_type"
FROM
knowledge
WHERE workspace_id= %s
) "app_and_knowledge_temp"
ON "app_and_knowledge_temp"."id" = static_temp."target_id" and app_and_knowledge_temp."auth_target_type"=static_temp."auth_target_type"
WHERE app_and_knowledge_temp.id is NULL ;
16 changes: 16 additions & 0 deletions apps/system_manage/sql/get_user_resource_permission.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
SELECT app_or_knowledge.*,
COALESCE(workspace_user_resource_permission.permission_list,'{}')::varchar[] as permission_list,
COALESCE(workspace_user_resource_permission.auth_type,'ROLE') as auth_type
FROM (SELECT "id",
"name",
'KNOWLEDGE' AS "auth_target_type",
user_id,
workspace_id,
"type" AS "icon"
FROM knowledge
${knowledge_query_set}
) app_or_knowledge
LEFT JOIN (SELECT *
FROM workspace_user_resource_permission
${workspace_user_resource_permission_query_set}) workspace_user_resource_permission
ON workspace_user_resource_permission.target = app_or_knowledge."id";
8 changes: 8 additions & 0 deletions apps/system_manage/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.urls import path

from . import views

app_name = "system_manage"
urlpatterns = [
path('workspace/<str:workspace_id>/user_resource_permission', views.WorkSpaceUserResourcePermissionView.as_view())
]
1 change: 1 addition & 0 deletions apps/system_manage/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
@date:2025/4/16 19:07
@desc:
"""
from .user_resource_permission import *
53 changes: 53 additions & 0 deletions apps/system_manage/views/user_resource_permission.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# coding=utf-8
"""
@project: MaxKB
@Author:虎虎
@file: workspace_user_resource_permission.py
@date:2025/4/28 16:38
@desc:
"""

from django.utils.translation import gettext_lazy as _
from drf_spectacular.utils import extend_schema
from rest_framework.request import Request
from rest_framework.views import APIView

from common import result
from common.auth import TokenAuth
from common.auth.authentication import has_permissions
from common.constants.permission_constants import PermissionConstants
from common.result import DefaultResultSerializer
from system_manage.api.user_resource_permission import UserResourcePermissionAPI, EditUserResourcePermissionAPI
from system_manage.serializers.user_resource_permission import UserResourcePermissionSerializer


class WorkSpaceUserResourcePermissionView(APIView):
authentication_classes = [TokenAuth]

@extend_schema(
methods=['GET'],
description=_('Obtain resource authorization list'),
operation_id=_('Obtain resource authorization list'),
parameters=UserResourcePermissionAPI.get_parameters(),
responses=UserResourcePermissionAPI.get_response(),
tags=[_('Resources authorization')]
)
@has_permissions(PermissionConstants.WORKSPACE_USER_RESOURCE_PERMISSION_READ.get_workspace_permission())
def get(self, request: Request, workspace_id: str):
return result.success(UserResourcePermissionSerializer(
data={'workspace_id': workspace_id}
).list(request.user))

@extend_schema(
methods=['PUT'],
description=_('Modify the resource authorization list'),
operation_id=_('Modify the resource authorization list'),
parameters=UserResourcePermissionAPI.get_parameters(),
request=EditUserResourcePermissionAPI.get_request(),
responses=DefaultResultSerializer(),
tags=[_('Resources authorization')]
)
def put(self, request: Request, workspace_id: str):
return result.success(UserResourcePermissionSerializer(
data={'workspace_id': workspace_id}
).edit(request.data, request.user))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are some suggestions to improve the code:

  1. Functionality Duplication: The get and put methods have nearly identical logic, with only minor differences such as using different serializers (one from EditUserResourcePermissionAPI). This can be optimized by abstracting the shared functionality into a single method that takes additional arguments based on the HTTP method.

  2. Code Formatting: Ensure consistent formatting throughout the file. PEP 8 is a widely accepted style guide for Python code. Consider applying it to improve readability.

  3. Comments: Some comments are redundant or unclear. Remove unnecessary comments and clarify others to enhance maintainability.

  4. Variable Naming Consistency: Use descriptive variable names across the codebase to make it easier to understand the purpose of each piece of code.

Here's an updated version of the class with these improvements:

# coding=utf-8
"""
    @project: MaxKB
    @Author:虎虎
    @file: workspace_user_resource_permission.py
    @date:2025/4/28 16:38
    @desc:
"""
from django.utils.translation import gettext_lazy as _
from drf_spectacular.utils import extend_schema
from rest_framework.request import Request
from rest_framework.views import APIView

from common import result
from common.auth import TokenAuth
from common.auth.authentication import has_permissions
from common.constants.permission_constants import PermissionConstants
from common.result import DefaultResultSerializer
from system_manage.api.user_resource_permission import UserResourcePermissionAPI, EditUserResourcePermissionAPI
from system_manage.serializers.user_resource_permission import UserResourcePermissionSerializer


class WorkSpaceUserResourcePermissionView(APIView):
    authentication_classes = [TokenAuth]

    def _handle_request(self, request, serializer_class, user_func_name):
        # Retrieve necessary data from request and context
        params = self._extract_params(request)
        return getattr(serializer_clas, user_func_name).to_representation(data=params)

    def _extract_params(self, request):
        # Extract relevant parameters from the request
        workspace_id = request.GET.get('workspace_id') if 'GET' == request.method.lower() else None
        return {
            'workspace_id': workspace_id,
            # Add other required parameters here
        }

    @extend_schema(
        methods=['GET'],
        description=_('Obtain resource authorization list'),
        operation_id=_('Obtain resource authorization list'),
        parameters=UserResourcePermissionAPI.get_parameters(),
        responses=UserResourcePermissionAPI.get_response(),
        tags=[_('Resources authorization')]
    )
    @has_permissions(PermissionConstants.WORKSPACE_USER_RESOURCE_PERMISSION_READ.get_workspace_permission())
    def get(self, request: Request):
        params = self._extract_params(request)
        serialized_data = self._handle_request(request=request, serializer_class=UserResourcePermissionSerializer, user_func_name='list')
        return result.success(serialized_data)

    @extend_schema(
        methods=['PUT'],
        description=_('Modify the resource authorization list'),
        operation_id=_('Modify the resource authorization list'),
        parameters=UserResourcePermissionAPI.get_parameters(),
        request=EditUserResourcePermissionAPI.get_request(),
        responses=DefaultResultSerializer(),
        tags=[_('Resources authorization')]
    )
    def put(self, request: Request):
        params = self._extract_params(request)
        serialized_data = self._handle_request(request=request, serializer_class=EditUserResourcePermissionSerializer, user_func_name='edit')
        return result.success(serialized_data if not params['error'] else '', error=params['message'])

With these changes, the code becomes more modular and less repetitive while maintaining its original structure and functionality.

Loading