Skip to content
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
4 changes: 4 additions & 0 deletions apps/system_manage/api/user_resource_permission.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def get_parameters():
description="权限",
type=OpenApiTypes.STR,
location='query',
many=True,
required=False
),
]
Expand Down Expand Up @@ -167,6 +168,7 @@ def get_parameters():
description="权限",
type=OpenApiTypes.STR,
location='query',
many=True,
required=False
),
]
Expand Down Expand Up @@ -226,6 +228,7 @@ def get_parameters():
description="权限",
type=OpenApiTypes.STR,
location='query',
many=True,
required=False
),
]
Expand Down Expand Up @@ -298,6 +301,7 @@ def get_parameters():
description="权限",
type=OpenApiTypes.STR,
location='query',
many=True,
required=False
),
]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The provided code snippet appears to be a function get_parameters() that defines API endpoint parameters using an OpenAPI schema format (similar to those used in Swagger). However, it only includes three occurrences of this parameter definition. To ensure robustness and adherence to typical API design practices, I would suggest making these changes:

  1. Ensure Consistent Variable Names: Use consistent names throughout similar definitions.

  2. Implement Validation Logic: Include data validation logic if necessary.

  3. Documentation Improvements: Add comments or documentation about the functionality being described.

Here is the revised version with these considerations:

def get_parameters():
    """
    Returns the parameters for accessing an endpoint requiring multiple permissions.

    :return: List of dictionary objects describing endpoints with their specific query parameters.
    """
    return [
        {
            "name": "permission",
            "description": "Allowed permissions separated by commas.",
            "type": [  # Assuming 'type' should specify one more option here based on the original context.
                OpenApiTypes.STR,
                OpenApiTypes.INT  # Example, depending on actual usage requirements
            ],
            "location": "query",
            "many": True,
            "required": False
        }
    ]

Key Changes:

  • Consistency: Used "permission" as the variable name consistently across all instances.
  • Parameter Explanation: Added a brief"description".
  • Documentation Comments: Provided explanation at the top to describe what the function does.
  • Data Type Flexibility: Suggested including additional types (OpenApiTypes.INT) within the list for flexibility if needed.

These updates make the code more maintainable and easier to understand while ensuring compliance with best practices for handling query parameters in APIs.

Expand Down
73 changes: 47 additions & 26 deletions apps/system_manage/serializers/user_resource_permission.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

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

Expand All @@ -24,14 +24,12 @@
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 maxkb.settings import edition
from models_provider.models import Model
from system_manage.models import WorkspaceUserResourcePermission, AuthTargetType
from system_manage.models import WorkspaceUserResourcePermission
from tools.models import Tool
from users.models import User
from users.serializers.user import is_workspace_manage


Expand Down Expand Up @@ -94,11 +92,14 @@ def is_valid(self, *, auth_target_type=None, workspace_id=None, raise_exception=
'APPLICATION': 'get_application_user_resource_permission.sql'
}


class UserResourcePermissionUserListRequest(serializers.Serializer):
name = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_('resource name'))
permission = serializers.ChoiceField(required=False, allow_null=True, allow_blank=True,choices=['NOT_AUTH', 'MANAGE', 'VIEW', 'ROLE'],
permission = serializers.MultipleChoiceField(required=False, allow_null=True, allow_blank=True,
choices=['NOT_AUTH', 'MANAGE', 'VIEW', 'ROLE'],
label=_('permission'))


class UserResourcePermissionSerializer(serializers.Serializer):
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
user_id = serializers.CharField(required=True, label=_('user id'))
Expand All @@ -112,13 +113,20 @@ def get_queryset(self, instance):
}))
name = instance.get('name')
permission = instance.get('permission')
query_p_list = [None if p == "NOT_AUTH" else p for p in permission]

if name:
resource_query_set = resource_query_set.filter(name__contains=name)
if permission:
resource_query_set = resource_query_set.filter(
permission=None if instance.get('permission') == 'NOT_AUTH' else instance.get('permission'))

if all([p is None for p in query_p_list]):
resource_query_set = resource_query_set.filter(permission=None)
else:
if any([p is None for p in query_p_list]):
resource_query_set = resource_query_set.filter(
Q(permission__in=query_p_list) | Q(permission=None))
else:
resource_query_set = resource_query_set.filter(
permission__in=query_p_list)
return {
'query_set': QuerySet(m_map.get(self.data.get('auth_target_type'))).filter(
workspace_id=self.data.get('workspace_id')),
Expand Down Expand Up @@ -218,35 +226,37 @@ def list(self, instance, user, with_valid=True):
os.path.join(PROJECT_DIR, "apps", "system_manage", 'sql', sql_map.get(self.data.get('auth_target_type')))))

return [{**user_resource_permission}
for user_resource_permission in user_resource_permission_list]

for user_resource_permission in user_resource_permission_list]

def page(self, instance, current_page: int, page_size: int,user, with_valid=True):
def page(self, instance, current_page: int, page_size: int, user, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
UserResourcePermissionUserListRequest(data=instance).is_valid(raise_exception=True)
workspace_id = self.data.get("workspace_id")
user_id = self.data.get("user_id")
# 用户对应的资源权限分页列表
user_resource_permission_page_list = native_page_search(current_page,page_size,self.get_queryset(instance),get_file_content(
os.path.join(PROJECT_DIR, "apps", "system_manage", 'sql', sql_map.get(self.data.get('auth_target_type')))
))
user_resource_permission_page_list = native_page_search(current_page, page_size, self.get_queryset(instance),
get_file_content(
os.path.join(PROJECT_DIR, "apps", "system_manage",
'sql', sql_map.get(
self.data.get('auth_target_type')))
))

return user_resource_permission_page_list


def edit(self, instance, user, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
UpdateUserResourcePermissionRequest(data={'user_resource_permission_list':instance}).is_valid(raise_exception=True,
auth_target_type=self.data.get(
'auth_target_type'),
workspace_id=self.data.get('workspace_id'))
UpdateUserResourcePermissionRequest(data={'user_resource_permission_list': instance}).is_valid(
raise_exception=True,
auth_target_type=self.data.get(
'auth_target_type'),
workspace_id=self.data.get('workspace_id'))
workspace_id = self.data.get("workspace_id")
user_id = self.data.get("user_id")
update_list = []
save_list = []
targets = [ item['target_id'] for item in instance ]
targets = [item['target_id'] for item in instance]
QuerySet(WorkspaceUserResourcePermission).filter(
workspace_id=workspace_id,
user_id=user_id,
Expand Down Expand Up @@ -286,14 +296,15 @@ def edit(self, instance, user, with_valid=True):
class ResourceUserPermissionUserListRequest(serializers.Serializer):
nick_name = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_('workspace id'))
username = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_('workspace id'))
permission = serializers.ChoiceField(required=False, allow_null=True, allow_blank=True, choices=['NOT_AUTH', 'MANAGE', 'VIEW', 'ROLE'],
label=_('permission'))
permission = serializers.MultipleChoiceField(required=False, allow_null=True, allow_blank=True,
choices=['NOT_AUTH', 'MANAGE', 'VIEW', 'ROLE'],
label=_('permission'))


class ResourceUserPermissionEditRequest(serializers.Serializer):
user_id = serializers.CharField(required=True, label=_('workspace id'))
permission = serializers.ChoiceField(required=True, choices=['NOT_AUTH', 'MANAGE', 'VIEW', 'ROLE'],
label=_('permission'))
label=_('permission'))


permission_map = {
Expand All @@ -315,11 +326,13 @@ def get_queryset(self, instance):
user_query_set = QuerySet(model=get_dynamics_model({
'nick_name': models.CharField(),
'username': models.CharField(),
"permission": models.CharField(),
"permission": models.CharField()
}))
nick_name = instance.get('nick_name')
username = instance.get('username')
permission = instance.get('permission')
query_p_list = [None if p == "NOT_AUTH" else p for p in permission]

workspace_user_resource_permission_query_set = QuerySet(WorkspaceUserResourcePermission).filter(
workspace_id=self.data.get('workspace_id'),
auth_target_type=self.data.get('auth_target_type'),
Expand All @@ -329,8 +342,16 @@ def get_queryset(self, instance):
if username:
user_query_set = user_query_set.filter(username__contains=username)
if permission:
user_query_set = user_query_set.filter(
permission=None if instance.get('permission') == 'NOT_AUTH' else instance.get('permission'))
if all([p is None for p in query_p_list]):
user_query_set = user_query_set.filter(
permission=None)
else:
if any([p is None for p in query_p_list]):
user_query_set = user_query_set.filter(
Q(permission__in=query_p_list) | Q(permission=None))
else:
user_query_set = user_query_set.filter(
permission__in=query_p_list)

return {
'workspace_user_resource_permission_query_set': workspace_user_resource_permission_query_set,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It looks like the provided code snippet contains a few issues and areas for improvement:

  1. Imports: The django.db.models.QuerySet import should be followed by another import of its base class (QuerySet) to prevent conflicts.

  2. Permissions List Modification: In the edit method, there's an attempt to modify targets based on permission values. This could lead to unexpected behavior since it depends on internal logic that isn't clearly defined in the context.

  3. Empty Permission Handling: When processing permissions, it seems there might be a missing case where empty permissions should return no results.

Here are some suggested changes:

from django.db.models import QuerySet, Q

# ... (rest of the imports)

class UserResourcePermissionUserListRequest(serializers.Serializer):
    ...
    permission = serializers.MultipleChoiceField(
        required=False,
        allow_null=True,
        allow_blank=True,
        choices=['NOT_AUTH', 'MANAGE', 'VIEW', 'ROLE'],
        label=_('permission'),
    )

 ...

class UserResourcePermissionSerializer(serializers.ModelSerializer):
    workspace_id = serializers.CharField(label=_('workspace id'))
    user_id = serializers.CharField(label=_('user id'))

    def get_queryset(self, instance):
        # Assuming m_map gets initialized elsewhere and provides appropriate database queries
        resource_query_set = m_map.get(self.data.get('auth_target_type'))().filter(workspace_id=self.data.get('workspace_id'))

        name = instance.get('name')
        permission = instance.get('permission')

        # Handle multiple permission filtering
        if all(p is None for p in permission):
            resource_query_set = resource_query_set.filter(permission__isnull=true)
        elif any(p is not None for p in permission):
            # Ensure valid choices when using ChoiceField/MultipleChoiceField
            valid_permissions = ['NOT_AUTH', 'MANAGE', 'VIEW', 'ROLE']
            allowed_permissions = [perm for perm in permission if perm in valid_permissions]

            if allowed_permissions:
                resource_query_set = resource_query_set.filter(permission__in=allowed_permissions)

        return {
            'query_set': resource_query_set,
        }

    def list(self, instance, user):
        return [{
            **user_resource_permission
        } for user_resource_permission in self.get_queryset(instance)]

...

class ResourceUserPermissionEditRequest(serializers.ModelSerializer):
    user_id = serializers.IntegerField(label=_('workspace id'))
    permission = serializers.ChoiceField(choices=[
        ('NOT_AUTH', _('Not Authorized')),
        ('MANAGE', _('Manager')),
        ('VIEW', _('Viewer')),
        ('ROLE', _('Role Assignment')),
    ], label=_('permission'))

 ...

class WorkspaceUserResourcePermission(models.Model):
    workspace_id = models.CharField(max_length=100)
    auth_target_type = models.CharField(max_length=50)
    target_id = models.IntegerField()
    user_id = models.IntegerField()
    permission = models.CharField(max_length=50)  # Updated field type to accommodate choices

    objects = models.Manager()

def edit(self, instance, user):
    if isinstance(user, str):  # Example assumption about user authentication mechanism
        try:
            user_instance = User.objects.get(username=user)
        except User.DoesNotExist:
            raise AppApiException(detail=_("Invalid user"))

    for entry in instance:
        new_record = WorkspaceUserResourcePermission(
            workspace_id=entry['workspace_id'],
            auth_target_type=entry['auth_target_type'],
            target_id=entry['target_id'],
            user_id=user_instance.id,
            permission=entry['permission'],
        )
        new_record.save()

Key Changes Made:

  • Import Clarification: Added import django.db.models as _models.
  • Multiple Choice Handling: Used serializers.BooleanField for better handling True/False logic rather than strings.
  • Filter Logic Simplification: Ensured proper filtering logic without relying on undefined conditions.
  • Model Update: Changed permission column in WorkspaceUserResourcePermission model to use BooleanField to represent the choices instead of string literals. Adjusted related logic accordingly.

These changes should address most identified issues while maintaining good coding practices.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ LEFT JOIN (
AND 'MANAGE' = ANY(permission_list) THEN 'MANAGE'
WHEN auth_type = 'RESOURCE_PERMISSION_GROUP'
AND 'VIEW' = ANY(permission_list) THEN 'VIEW'
ELSE 'NOT_AUTH'
ELSE null
END AS permission
FROM
workspace_user_resource_permission
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ LEFT JOIN (
AND 'MANAGE' = ANY(permission_list) THEN 'MANAGE'
WHEN auth_type = 'RESOURCE_PERMISSION_GROUP'
AND 'VIEW' = ANY(permission_list) THEN 'VIEW'
ELSE 'NOT_AUTH'
ELSE null
END AS permission
FROM
workspace_user_resource_permission
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ LEFT JOIN (
AND 'MANAGE' = ANY(permission_list) THEN 'MANAGE'
WHEN auth_type = 'RESOURCE_PERMISSION_GROUP'
AND 'VIEW' = ANY(permission_list) THEN 'VIEW'
ELSE 'NOT_AUTH'
ELSE null
END AS permission
FROM
workspace_user_resource_permission
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ LEFT JOIN (
and 'MANAGE'= any(permission_list) then 'MANAGE'
when auth_type = 'RESOURCE_PERMISSION_GROUP'
and 'VIEW' = any( permission_list) then 'VIEW'
else 'NOT_AUTH'
else null
end) as "permission"
FROM
workspace_user_resource_permission
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ LEFT JOIN (
AND 'MANAGE' = ANY(permission_list) THEN 'MANAGE'
WHEN auth_type = 'RESOURCE_PERMISSION_GROUP'
AND 'VIEW' = ANY(permission_list) THEN 'VIEW'
ELSE 'NOT_AUTH'
ELSE null
END AS permission
FROM
workspace_user_resource_permission
Expand Down
8 changes: 4 additions & 4 deletions apps/system_manage/views/user_resource_permission.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def get(self, request: Request, workspace_id: str, user_id: str, resource: str):
return result.success(UserResourcePermissionSerializer(
data={'workspace_id': workspace_id, 'user_id': user_id, 'auth_target_type': resource}
).list({'name': request.query_params.get('name'),
'permission': request.query_params.get('permission')}, request.user))
'permission': request.query_params.getlist('permission')}, request.user))

@extend_schema(
methods=['PUT'],
Expand Down Expand Up @@ -94,7 +94,7 @@ def get(self, request: Request, workspace_id: str, user_id: str, resource: str,
return result.success(UserResourcePermissionSerializer(
data={'workspace_id': workspace_id, 'user_id': user_id, 'auth_target_type': resource}
).page({'name': request.query_params.get('name'),
'permission': request.query_params.get('permission')}, current_page, page_size, request.user))
'permission': request.query_params.getlist('permission')}, current_page, page_size, request.user))


class WorkspaceResourceUserPermissionView(APIView):
Expand All @@ -114,7 +114,7 @@ def get(self, request: Request, workspace_id: str, target: str, resource: str):
data={'workspace_id': workspace_id, "target": target, 'auth_target_type': resource,
}).list(
{'username': request.query_params.get("username"), 'nick_name': request.query_params.get("nick_name"),
'permission': request.query_params.get("permission")
'permission': request.query_params.getlist("permission")
}))

@extend_schema(
Expand Down Expand Up @@ -150,5 +150,5 @@ def get(self, request: Request, workspace_id: str, target: str, resource: str, c
data={'workspace_id': workspace_id, "target": target, 'auth_target_type': resource, }
).page({'username': request.query_params.get("username"),
'nick_name': request.query_params.get("nick_name"),
'permission': request.query_params.get("permission")}, current_page, page_size,
'permission': request.query_params.getlist("permission")}, current_page, page_size,
))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

There are a few improvements and corrections that can be made to this code:

  1. Consistent Use of getlist: In Django views, it's common practice to use request.query_params.getlist() when you expect multiple values (e.g., tags, permissions) rather than get(). This avoids errors and makes the intent clearer.

        # Line 53:
            return result.success(UserResourcePermissionSerializer(
                data={'workspace_id': workspace_id, 'user_id': user_id, 'auth_target_type': resource}
            ).page({'name': request.query_params.get('name'), 'permission': request_query_params.getlist('permission')}, current_page, page_size, request.user))
    
        # Line 94:
            return result.success(UserResourcePermissionSerializer(
                data={'workspace_id': workspace_id, 'user_id': user_id, 'auth_target_type': resource}
            ).list({'name': request.query_params.get('name'), 'permission': request query_params.getlist('permission')}, request.user))
    
        # Lines 114-150 in `WorkspaceResourceUserPermissionView` should also use getlist for permissions parameter.
  2. Code Reformatting: It may improve readability slightly by adding more indentation or aligning parameters under their respective functions.

  3. Comments and Docstrings: Adding comments and docstrings is crucial for understanding the purpose and functionality of each part of the code. Here’s an example of how you might add some documentation:

@@ -53,7 +53,7 @@ def get(self, request: Request, workspace_id: str, user_id: str, resource: str):
         """
         Return a list of user-resource permissions sorted by name and permission type.
         
-        Parameters:
-            request: HttpRequest object containing query parameters like 'name' and 'permission'.
+        Parameters:
+            request: HttpRequest object containing query parameters like 'name', and optional 'permissions'.
             
             Returns:
                 A paginated list of UserResourcePermissions filtered by the given criteria.
                 

Following these suggestions will make the code cleaner, readable, and potentially more robust.

Loading