-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat: Batch delete and move applications #4963
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,12 +15,14 @@ | |
| from rest_framework.views import APIView | ||
|
|
||
| from application.api.application_api import ApplicationCreateAPI, ApplicationQueryAPI, ApplicationImportAPI, \ | ||
| ApplicationExportAPI, ApplicationOperateAPI, ApplicationEditAPI, TextToSpeechAPI, SpeechToTextAPI, PlayDemoTextAPI | ||
| ApplicationExportAPI, ApplicationOperateAPI, ApplicationEditAPI, TextToSpeechAPI, SpeechToTextAPI, PlayDemoTextAPI, \ | ||
| ApplicationBatchOperateAPI | ||
| from application.models import Application | ||
| from application.serializers.application import ApplicationSerializer, Query, ApplicationOperateSerializer | ||
| from application.serializers.application import ApplicationSerializer, Query, ApplicationOperateSerializer, \ | ||
| ApplicationBatchOperateSerializer | ||
| from common import result | ||
| from common.auth import TokenAuth | ||
| from common.auth.authentication import has_permissions, get_is_permissions | ||
| from common.auth.authentication import has_permissions, get_is_permissions, check_batch_permissions | ||
| from common.constants.permission_constants import PermissionConstants, RoleConstants, ViewPermission, CompareConstants | ||
| from common.log.log import log | ||
| from tools.api.tool import GetInternalToolAPI | ||
|
|
@@ -35,6 +37,16 @@ def get_application_operation_object(application_id): | |
| return {} | ||
|
|
||
|
|
||
| def get_application_operation_object_batch(application_id_list): | ||
| application_model_list = QuerySet(model=Application).filter(id__in=application_id_list) | ||
| if application_model_list is not None: | ||
| return { | ||
| "name": f'[{",".join([app.name for app in application_model_list])}]', | ||
| 'application_list': [{'name': app.name} for app in application_model_list] | ||
| } | ||
| return {} | ||
|
|
||
|
|
||
| class ApplicationAPI(APIView): | ||
| authentication_classes = [TokenAuth] | ||
|
|
||
|
|
@@ -296,6 +308,81 @@ def get(self, request: Request): | |
| 'name': request.query_params.get('name', ''), | ||
| }).get_appstore_templates()) | ||
|
|
||
| class BatchDelete(APIView): | ||
| authentication_classes = [TokenAuth] | ||
|
|
||
| @extend_schema( | ||
| methods=['PUT'], | ||
| description=_("Batch delete applications"), | ||
| summary=_("Batch delete applications"), | ||
| operation_id=_("Batch delete applications"), | ||
| parameters=ApplicationBatchOperateAPI.get_parameters(), | ||
| request=ApplicationBatchOperateAPI.get_request(), | ||
| responses=result.DefaultResultSerializer, | ||
| tags=[_('Application')] | ||
| ) | ||
| @has_permissions(PermissionConstants.APPLICATION_BATCH_DELETE.get_workspace_permission(), | ||
| RoleConstants.USER.get_workspace_role(), | ||
| RoleConstants.WORKSPACE_MANAGE.get_workspace_role() | ||
| ) | ||
| def put(self, request: Request, workspace_id: str): | ||
| id_list = request.data.get('id_list', []) | ||
| permitted_ids = check_batch_permissions( | ||
| request, id_list, 'application_id', | ||
| (PermissionConstants.APPLICATION_DELETE.get_workspace_application_permission(), | ||
| PermissionConstants.APPLICATION_DELETE.get_workspace_permission_workspace_manage_role(), | ||
| ViewPermission([RoleConstants.USER.get_workspace_role()], | ||
| [PermissionConstants.APPLICATION.get_workspace_application_permission()], | ||
| CompareConstants.AND), | ||
| RoleConstants.WORKSPACE_MANAGE.get_workspace_role()), workspace_id=workspace_id | ||
| ) | ||
| @log(menu='Application', operate='Batch delete applications', | ||
| get_operation_object=lambda r, k: get_application_operation_object_batch(permitted_ids)) | ||
| def inner(view,r, **kwargs): | ||
| return ApplicationBatchOperateSerializer( | ||
| data={'workspace_id': workspace_id, 'user_id': request.user.id} | ||
| ).batch_delete({'id_list': permitted_ids}) | ||
|
|
||
| return result.success(inner(self,request, workspace_id=workspace_id)) | ||
|
|
||
| class BatchMove(APIView): | ||
| authentication_classes = [TokenAuth] | ||
|
|
||
| @extend_schema( | ||
| methods=['PUT'], | ||
| description=_("Batch move applications"), | ||
| summary=_("Batch move applications"), | ||
| operation_id=_("Batch move applications"), | ||
| parameters=ApplicationBatchOperateAPI.get_parameters(), | ||
| request=ApplicationBatchOperateAPI.get_move_request(), | ||
| responses=result.DefaultResultSerializer, | ||
| tags=[_('Application')] | ||
| ) | ||
| @has_permissions(PermissionConstants.APPLICATION_BATCH_MOVE.get_workspace_permission(), | ||
| RoleConstants.USER.get_workspace_role(), | ||
| RoleConstants.WORKSPACE_MANAGE.get_workspace_role() | ||
| ) | ||
| def put(self, request: Request, workspace_id: str): | ||
| id_list = request.data.get('id_list', []) | ||
| permitted_ids = check_batch_permissions( | ||
| request, id_list, 'application_id', | ||
| (PermissionConstants.APPLICATION_EDIT.get_workspace_application_permission(), | ||
| PermissionConstants.APPLICATION_EDIT.get_workspace_permission_workspace_manage_role(), | ||
| ViewPermission([RoleConstants.USER.get_workspace_role()], | ||
| [PermissionConstants.APPLICATION.get_workspace_application_permission()], | ||
| CompareConstants.AND), | ||
| RoleConstants.WORKSPACE_MANAGE.get_workspace_role()), | ||
| workspace_id=workspace_id | ||
| ) | ||
|
|
||
| @log(menu='Application', operate='Batch move applications', | ||
| get_operation_object=lambda r, k: get_application_operation_object_batch(permitted_ids)) | ||
| def inner(view,r, **kwargs): | ||
| return ApplicationBatchOperateSerializer( | ||
| data={'workspace_id': workspace_id, 'user_id': request.user.id} | ||
| ).batch_move({'id_list': permitted_ids, 'folder_id': request.data.get('folder_id')}) | ||
|
|
||
| return result.success(inner(self,request, workspace_id=workspace_id)) | ||
|
|
||
| class McpServers(APIView): | ||
| authentication_classes = [TokenAuth] | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are a few optimizations and corrections that can be made to the provided code. Here's a summary of the changes: Corrections
Here's the updated version of the relevant parts: def get_application_operation_object_batch(application_id_list):
# Assuming query_set is imported correctly here
application_queryset = QuerySet(Application).filter(id__in=application_id_list)
if application queryset.exists():
return {
"name": f"([{','.join(app.name for app in application_queryset)})]",
'application_list': [{'name': app.name} for app in application_queryset]
}
return {}
# ... other unchanged methods ...
class BatchDelete(APIView):
authentication_classes = [TokenAuth]
@extend_schema(
methods=['PUT'],
description="Batch delete applications",
summary="Batch delete applications",
operation_id="Batch delete applications",
parameters=ApplicationBatchOperateAPI.get_parameters(),
request=ApplicationBatchOperateAPI.get_request(),
responses=result.DefaultResultSerializer,
tags=[_("Application")]
)
@has_permissions(
PermissionConstants.APPLICATION_BATCH_DELETE.get_workspace_permission(),
RoleConstants.USER.get_workspace_role(),
RoleConstants.WORKSPACE_MANAGE.get_workspace_role()
)
def put(self, request: Request, workspace_id: str):
id_list = request.data.get('id_list', [])
# Simplify permission check
permitted_ids = list(filter(lambda x: x.is_valid(workspace_id), id_list))
@log(menu='Application', operate='Batch delete applications')
def inner(view, r, **kwargs):
try:
serializer = ApplicationBatchOperateSerializer(data={"workspace_id": workspace_id, "user_id": request.user.id})
response_data = serializer.batch_delete({"id_list": permitted_ids})
return result.success(response_data)
except Exception as e:
return result.fail(str(e))
return inner(self, request)
class BatchMove(APIView):
authentication_classes = [TokenAuth]
@extend_schema(
methods=['PUT'],
description="Batch move applications",
summary="Batch move applications",
operation_id="Batch move applications",
parameters=ApplicationBatchOperateAPI.get_parameters(),
request=ApplicationBatchOperateAPI.get_move_request(),
responses=result.DefaultResultSerializer,
tags=[_("Application")]
)
@has_permissions(
PermissionConstants.APPLICATION_BATCH_MOVE.get_workspace_permission(),
RoleConstants.USER.get_workspace_role(),
RoleConstants.WORKSPACE_MANAGE.get_workspace_role()
)
def put(self, request: Request, workspace_id: str):
id_list = request.data.get('id_list', [])
# Simplify permission check
permitted_ids = list(filter(lambda x: x.is_valid(workspace_id), id_list))
folder_id = request.data.get('folder_id')
@log(menu='Application', operate='Batch move applications')
def inner(view, r, **kwargs):
try:
serializer = ApplicationBatchOperateSerializer(data={"workspace_id": workspace_id, "user_id": request.user.id})
response_data = serializer.batch_move({"id_list": permitted_ids, "folder_id": folder_id})
return result.success(response_data)
except Exception as e:
return result.fail(str(e))
return inner(self, request)Additional Suggestions
By making these corrections, the code should be more robust, efficient, and easier to maintain. |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -191,6 +191,8 @@ class Operate(Enum): | |
| TRIGGER_EDIT = "READ+TRIGGER_EDIT" | ||
| TRIGGER_CREATE = "READ+TRIGGER_CREATE" | ||
| TRIGGER_DELETE = "READ+TRIGGER_DELETE" | ||
| BATCH_DELETE = "READ+BATCH_DELETE" | ||
| BATCH_MOVE = "READ+BATCH_MOVE" | ||
|
|
||
|
|
||
| class RoleGroup(Enum): | ||
|
|
@@ -571,7 +573,16 @@ class PermissionConstants(Enum): | |
| parent_group=[WorkspaceGroup.TOOL, UserGroup.TOOL], | ||
| resource_permission_group_list=[ResourcePermissionConst.TOOL_MANGE] | ||
| ) | ||
|
|
||
| TOOL_BATCH_MOVE = Permission( | ||
| group=Group.TOOL, operate=Operate.BATCH_MOVE, role_list=[RoleConstants.ADMIN, RoleConstants.USER], | ||
| parent_group=[WorkspaceGroup.TOOL, UserGroup.TOOL], | ||
| resource_permission_group_list=[ResourcePermissionConst.TOOL_MANGE] | ||
| ) | ||
| TOOL_BATCH_DELETE = Permission( | ||
| group=Group.TOOL, operate=Operate.BATCH_DELETE, role_list=[RoleConstants.ADMIN, RoleConstants.USER], | ||
| parent_group=[WorkspaceGroup.TOOL, UserGroup.TOOL], | ||
| resource_permission_group_list=[ResourcePermissionConst.TOOL_MANGE] | ||
| ) | ||
| TOOL_EDIT = Permission( | ||
| group=Group.TOOL, operate=Operate.EDIT, role_list=[RoleConstants.ADMIN, RoleConstants.USER], | ||
| parent_group=[WorkspaceGroup.TOOL, UserGroup.TOOL], | ||
|
|
@@ -694,6 +705,16 @@ class PermissionConstants(Enum): | |
| resource_permission_group_list=[ResourcePermissionConst.KNOWLEDGE_MANGE], | ||
| parent_group=[WorkspaceGroup.KNOWLEDGE, UserGroup.KNOWLEDGE] | ||
| ) | ||
| KNOWLEDGE_BATCH_DELETE = Permission(group=Group.KNOWLEDGE, operate=Operate.BATCH_DELETE, | ||
| role_list=[RoleConstants.ADMIN, RoleConstants.USER], | ||
| resource_permission_group_list=[ResourcePermissionConst.KNOWLEDGE_MANGE], | ||
| parent_group=[WorkspaceGroup.KNOWLEDGE, UserGroup.KNOWLEDGE], | ||
| ) | ||
| KNOWLEDGE_BATCH_MOVE = Permission(group=Group.KNOWLEDGE, operate=Operate.BATCH_MOVE, | ||
| role_list=[RoleConstants.ADMIN, RoleConstants.USER], | ||
| resource_permission_group_list=[ResourcePermissionConst.KNOWLEDGE_MANGE], | ||
| parent_group=[WorkspaceGroup.KNOWLEDGE, UserGroup.KNOWLEDGE], | ||
| ) | ||
| KNOWLEDGE_RESOURCE_AUTHORIZATION = Permission( | ||
| group=Group.KNOWLEDGE, operate=Operate.AUTH, role_list=[RoleConstants.ADMIN, RoleConstants.USER], | ||
| resource_permission_group_list=[ResourcePermissionConst.KNOWLEDGE_MANGE], | ||
|
|
@@ -1031,6 +1052,16 @@ class PermissionConstants(Enum): | |
| resource_permission_group_list=[ResourcePermissionConst.APPLICATION_MANGE], | ||
| parent_group=[WorkspaceGroup.APPLICATION, UserGroup.APPLICATION], | ||
| ) | ||
| APPLICATION_BATCH_DELETE = Permission(group=Group.APPLICATION, operate=Operate.BATCH_DELETE, | ||
| role_list=[RoleConstants.ADMIN, RoleConstants.USER], | ||
| resource_permission_group_list=[ResourcePermissionConst.APPLICATION_MANGE], | ||
| parent_group=[WorkspaceGroup.APPLICATION, UserGroup.APPLICATION], | ||
| ) | ||
| APPLICATION_BATCH_MOVE = Permission(group=Group.APPLICATION, operate=Operate.BATCH_MOVE, | ||
| role_list=[RoleConstants.ADMIN, RoleConstants.USER], | ||
| resource_permission_group_list=[ResourcePermissionConst.APPLICATION_MANGE], | ||
| parent_group=[WorkspaceGroup.APPLICATION, UserGroup.APPLICATION], | ||
| ) | ||
| APPLICATION_RESOURCE_AUTHORIZATION = Permission(group=Group.APPLICATION, operate=Operate.AUTH, | ||
| role_list=[RoleConstants.ADMIN, RoleConstants.USER], | ||
| parent_group=[WorkspaceGroup.APPLICATION, UserGroup.APPLICATION], | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are no apparent irregularities, but here are a few minor optimizations and improvements:
Here's an optimized version of the code including brief descriptions: class Operation(Enum):
READ = "READ"
EDIT = "EDIT"
CREATE = "CREATE"
DELETE = "DELETE"
BATCH_DELETE = "BATCH_DELETE"
BATCH_MOVE = "BATCH_MOVE"
class Group(Enum):
TOOL = "TOOL"
KNOWLEDGE = "KNOWLEDGE"
APPLICATION = "APPLICATION"
def get_role_group(role_name: str) -> RoleGroup:
roles_dict = {
RoleConstants.ADMIN.value: RoleGroup.ADMIN,
RoleConstants.USER.value: RoleGroup.USER
}
return roles_dict.get(role_name.upper())
# Base Permission class
class PermissionBase(Enum):
def __init__(self, group: Group, operate: Operation, role_list: list):
self.group = group
self.operate = operate
self.role_list = role_list
class Permission(PermissionBase):
def __new__(cls, *args, **kwargs):
obj = super().__new__(cls)
# Add additional logic if needed, e.g., default resource_permission_group_list
kwargs.update({"resource_permission_group_list": []})
obj.__dict__.update(kwargs)
return obj
class ToolPermissionsEnum:
@staticmethod
def batch_permissions():
return [
Permission(group=Group.TOOL, operate=Operation.BATCH_DELETE,
role_list=[get_role_group("ADMIN"), get_role_group("USER")]),
Permission(group=Group.TOOL, operate=Operation.BATCH_MOVE,
role_list=[get_role_group("ADMIN"), get_role_group("USER")])
]
class KnowledgePermissionsEnum:
@staticmethod
def batch_permissions():
return [
Permission(group=Group.KNOWLEDGE, operate=Operation.BATCH_DELETE,
role_list=[get_role_group("ADMIN"), get_role_group("USER")]),
Permission(group=Group.KNOWLEDGE, operate=Operation.BATCH_MOVE,
role_list=[get_role_group("ADMIN"), get_role_group("USER")])
]
class ApplicationPermissionsEnum:
@staticmethod
def batch_permissions():
return [
Permission(group=Group.APPLICATION, operate=Operation.BATCH_DELETE,
role_list=[get_role_group("ADMIN"), get_role_group("USER")]),
Permission(group=Group.APPLICATION, operate=Operation.BATCH_MOVE,
role_list=[get_role_group("ADMIN"), get_role_group("USER")])
]This refactoring improves readability and reusability by creating separate enums for different types (e.g., tool permissions), which can be iterated upon easily using static methods. |
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The provided code snippet contains several potential issues that need to be addressed:
Duplicated Code: The
play_demo_textmethod exists in bothApplicationModelViewSetandApplicationViewSet. This redundancy can lead to maintenance problems and unnecessary function calls.Transaction Management: There is no transaction management applied on the delete methods (
batch_delete). A transaction should be used around database operations to ensure atomicity and consistency.Code Duplication: Similar logic exists between the
batch_deleteandbatch_movemethods. This duplication can be refactored into a single method if possible for better maintainability.Error Handling: In some scenarios, exceptions are raised directly without handling them properly, which could lead to unanticipated behavior during production use.
Validation Logic: The validation logic in
batch_deleteandbatch_moveis complex and repetitive. Consider modularizing this logic further using mixins or custom validator classes.Here's an optimized version of the code with suggested improvements:
This revised approach improves organization and reduces redundancy by encapsulating the business logic in a reusable
save_batchmethod. Additionally, appropriate error logging is added within each operation to help diagnose failures and monitor application performance.