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
22 changes: 22 additions & 0 deletions apps/application/api/application_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
ApplicationImportRequest, ApplicationEditSerializer, TextToSpeechRequest, SpeechToTextRequest, PlayDemoTextRequest
from common.mixins.api_mixin import APIMixin
from common.result import ResultSerializer, ResultPageSerializer, DefaultResultSerializer
from knowledge.serializers.common import BatchSerializer, BatchMoveSerializer


class ApplicationCreateRequest(ApplicationCreateSerializer.SimplateRequest):
Expand Down Expand Up @@ -160,6 +161,27 @@ def get_parameters():
]


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

@staticmethod
def get_move_request():
return BatchMoveSerializer


class ApplicationExportAPI(APIMixin):
@staticmethod
def get_parameters():
Expand Down
50 changes: 50 additions & 0 deletions apps/application/serializers/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
from common.utils.logger import maxkb_logger
from common.utils.tool_code import ToolExecutor
from knowledge.models import Knowledge, KnowledgeScope, File, FileSourceType
from knowledge.serializers.common import BatchSerializer, BatchMoveSerializer
from knowledge.serializers.knowledge import KnowledgeSerializer, KnowledgeModelSerializer
from maxkb.conf import PROJECT_DIR
from models_provider.models import Model
Expand Down Expand Up @@ -1314,3 +1315,52 @@ def play_demo_text(self, instance, with_valid=True):
tts_model_id = instance.pop('tts_model_id')
model = get_model_instance_by_model_workspace_id(tts_model_id, self.data.get('workspace_id'), **instance)
return model.text_to_speech(text)


class ApplicationBatchOperateSerializer(serializers.Serializer):
workspace_id = serializers.CharField(required=True, label=_("Workspace ID"))

def is_valid(self, *, raise_exception=False):
super().is_valid(raise_exception=True)

@transaction.atomic
def batch_delete(self, instance: Dict, with_valid=True):
from trigger.handler.simple_tools import deploy
from trigger.serializers.trigger import TriggerModelSerializer

if with_valid:
BatchSerializer(data=instance).is_valid(model=Application,raise_exception=True)
self.is_valid(raise_exception=True)
id_list = instance.get("id_list")
workspace_id = self.data.get('workspace_id')

QuerySet(ApplicationVersion).filter(application_id__in=id_list).delete()
QuerySet(ResourceMapping).filter(
Q(target_id__in=id_list) | Q(source_id__in=id_list)
).delete()

QuerySet(Application).filter(id__in=id_list, workspace_id=workspace_id).delete()

trigger_ids = list(
QuerySet(TriggerTask).filter(
source_type="APPLICATION", source_id__in=id_list
).values('trigger_id').distinct()
)
QuerySet(TriggerTask).filter(source_type="APPLICATION", source_id__in=id_list).delete()

for trigger_id in trigger_ids:
trigger = Trigger.objects.filter(id=trigger_id['trigger_id']).first()
if trigger and trigger.is_active:
deploy(TriggerModelSerializer(trigger).data, **{})
return True

def batch_move(self, instance: Dict, with_valid=True):
if with_valid:
BatchMoveSerializer(data=instance).is_valid(model=Application, raise_exception=True)
self.is_valid(raise_exception=True)
id_list = instance.get("id_list")
folder_id = instance.get("folder_id")
workspace_id = self.data.get('workspace_id')

QuerySet(Application).filter(id__in=id_list, workspace_id=workspace_id).update(folder_id=folder_id)
return True
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 contains several potential issues that need to be addressed:

  1. Duplicated Code: The play_demo_text method exists in both ApplicationModelViewSet and ApplicationViewSet. This redundancy can lead to maintenance problems and unnecessary function calls.

  2. 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.

  3. Code Duplication: Similar logic exists between the batch_delete and batch_move methods. This duplication can be refactored into a single method if possible for better maintainability.

  4. Error Handling: In some scenarios, exceptions are raised directly without handling them properly, which could lead to unanticipated behavior during production use.

  5. Validation Logic: The validation logic in batch_delete and batch_move is 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:

from rest_framework import viewsets, serializers, status
from django.db import transaction
from models_provider.models import Model
from knowledge.models import (
    Application,
    ApplicationVersion,
    ResourceMapping,
    TriggerTask,
    Trigger
)
from knowledge.serializers.common import BatchSerializer, BatchMoveSerializer
from knowledge.serializers.knowledge import ApplicationSerializer
from maxkb.conf import PROJECT_DIR

class ApplicationModelViewSet(viewsets.ModelViewSet):
    queryset = Application.objects.all()
    serializer_class = ApplicationSerializer

    def play_demo_text(self, instance):
        tts_model_id = instance.pop('tts_model_id')
        model = get_model_instance_by_model_workspace_id(tts_model_id, self.data.get('workspace_id'), **instance)
        return model.text_to_speech(instance['text'])

    class ApplicationBatchOperateSerializer(serializers.Serializer):
        workspace_id = serializers.CharField(required=True)

        def save_batch(self, action, data: List[Dict], **kwargs) -> bool:
            with transaction.atomic():
                if action == 'DELETE':
                    result = self.batch_delete(data, **kwargs)
                elif action == 'MOVE':
                    result = self.batch_move(data, **kwargs)
                else:
                    raise NotImplementedError(f"Action '{action}' not supported.")
                return result

        @transaction.atomic
        def batch_delete(self, ids: List[int], with_valid=True) -> bool:
            # Validate input before processing
            instance = {'id_list': ids}
            if with_valid:
                BatchSerializer(data=instance, many=True).is_valid(raise_exception=True)
                self.is_valid(raise_exception=True)
            
            try:
                QuerySet(ApplicationVersion).filter(application_id__in=ids).delete()
                QuerySet(ResourceMapping).filter(
                    Q(target_id__in=ids) | Q(source_id__in=ids)
                ).delete()

                QuerySet(Application).filter(id__in=ids).delete()

                trigger_ids = list(QuerySet(TriggerTask).filter(
                    source_type="APPLICATION", source_id__in=ids
                ).values('trigger_id').distinct())

                QuerySet(TriggerTask).filter(source_type="APPLICATION", source_id__in=ids).delete()

                for trigger_id in trigger_ids:
                    trigger = Trigger.objects.filter(id=trigger_id['trigger_id'}).first()
                    if trigger and trigger.is_active:
                        deploy(TriggerModelSerializer(trigger).data, **{})

                return True
            except Exception as e:
                maxkb_logger.error(f"Failed to perform batch {action}", exc_info=e)
                return False

        @transaction.atomic
        def batch_move(self, new_folder_id: int, ids: List[int], **kwargs) -> bool:
            # Validate input before processing
            instance = {'id_list': ids, 'folder_id': new_folder_id}
            if kwargs.get('with_valid', True):
                BatchMoveSerializer(data=instance, many=True).is_valid(raise_exception=True)
                self.is_valid(raise_exception=True)

            try:
                QuerySet(Application).filter(id__in=ids).update(folder_id=new_folder_id)
                return True
            except Exception as e:
                maxkb_logger.error(f"Failed to move batch applications", exc_info=e)
                return False

This revised approach improves organization and reduces redundancy by encapsulating the business logic in a reusable save_batch method. Additionally, appropriate error logging is added within each operation to help diagnose failures and monitor application performance.

2 changes: 2 additions & 0 deletions apps/application/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
path('workspace/<str:workspace_id>/application', views.ApplicationAPI.as_view(), name='application'),
path('workspace/<str:workspace_id>/application/folder/<str:folder_id>/import', views.ApplicationAPI.Import.as_view()),
path('workspace/<str:workspace_id>/application/<int:current_page>/<int:page_size>', views.ApplicationAPI.Page.as_view(), name='application_page'),
path('workspace/<str:workspace_id>/application/batch_delete', views.ApplicationAPI.BatchDelete.as_view()),
path('workspace/<str:workspace_id>/application/batch_move', views.ApplicationAPI.BatchMove.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>', views.ApplicationAPI.Operate.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/publish', views.ApplicationAPI.Publish.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/move/<str:folder_id>', views.ApplicationAPI.Move.as_view()),
Expand Down
93 changes: 90 additions & 3 deletions apps/application/views/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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]

Expand Down Expand Up @@ -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]
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 optimizations and corrections that can be made to the provided code. Here's a summary of the changes:

Corrections

  1. Import Statement: In get_application_operation_object, replace:

    from application.objects.object import QuerySet

    with:

    from django.db.models.base import ModelBase
  2. Batch Move Parameter Definition: Remove duplicate parameter definitions in put method.

  3. Logging Functionality: Ensure that the logging function (get_operation_object) returns the correct structure based on the input parameters.

  4. Function Name Consistency: Rename functions where necessary to make them more descriptive.

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

  • Type Hinting and Documentation: Add type hints where appropriate and ensure comprehensive documentation.

By making these corrections, the code should be more robust, efficient, and easier to maintain.

Expand Down
13 changes: 13 additions & 0 deletions apps/common/auth/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from typing import List

from django.utils.translation import gettext_lazy as _
from rest_framework.request import Request

from common.constants.permission_constants import PermissionConstants, RoleConstants, ViewPermission, CompareConstants, \
Permission, Role
Expand Down Expand Up @@ -92,6 +93,18 @@ def is_permissions(*permission, compare=CompareConstants.OR):

return is_permissions

def check_batch_permissions(request: Request, id_list: List[str], id_key: str, permissions: tuple,
compare=CompareConstants.OR, **kwargs) -> List[str]:
result_list = []
for resource_id in id_list:
kwargs[id_key] = resource_id
exit_list = list(
map(lambda p: exist(request.auth.role_list, request.auth.permission_list, p, request, **kwargs),
permissions)
)
if any(exit_list) if compare == CompareConstants.OR else all(exit_list):
result_list.append(resource_id)
return result_list

def has_permissions(*permission, compare=CompareConstants.OR):
"""
Expand Down
33 changes: 32 additions & 1 deletion apps/common/constants/permission_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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],
Expand Down Expand Up @@ -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],
Expand Down Expand Up @@ -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],
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 no apparent irregularities, but here are a few minor optimizations and improvements:

  1. Consistent Formatting: The file is well-formatted with consistent indentation.
  2. Clear Documentation: Each enumeration value should have comments explaining its usage clearly. The current implementation does not include explanations for each operation.
  3. Code Reusability: Combine repeated permission definitions where possible. For example, you can create a base PermissionBase class that includes common fields and then subclass it for specific permissions.

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.

Expand Down
2 changes: 2 additions & 0 deletions apps/knowledge/serializers/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ def is_valid(self, *, model=None, raise_exception=False):
raise AppApiException(500, _('The following id does not exist: {error_id_list}').format(
error_id_list=error_id_list))

class BatchMoveSerializer(BatchSerializer):
folder_id = serializers.CharField(required=True, label=_('folder id'))

class ProblemParagraphObject:
def __init__(self, knowledge_id: str, document_id: str, paragraph_id: str, problem_content: str):
Expand Down
8 changes: 7 additions & 1 deletion apps/locales/en_US/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -9168,4 +9168,10 @@ msgid "Document does not belong to current knowledge"
msgstr "Document does not belong to current knowledge"

msgid "Move an application"
msgstr "Move an application"
msgstr "Move an application"

msgid "Batch delete applications"
msgstr "Batch delete applications"

msgid "Batch move applications"
msgstr "Batch move applications"
8 changes: 7 additions & 1 deletion apps/locales/zh_CN/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -9291,4 +9291,10 @@ msgid "Document does not belong to current knowledge"
msgstr "文档不属于当前知识库"

msgid "Move an application"
msgstr "移动应用程序"
msgstr "移动应用程序"

msgid "Batch delete applications"
msgstr "批量删除应用"

msgid "Batch move applications"
msgstr "批量移动应用"
8 changes: 7 additions & 1 deletion apps/locales/zh_Hant/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -9288,4 +9288,10 @@ msgid "Document does not belong to current knowledge"
msgstr "文件不屬於當前知識庫"

msgid "Move an application"
msgstr "移動應用程序"
msgstr "移動應用程序"

msgid "Batch delete applications"
msgstr "批量刪除應用"

msgid "Batch move applications"
msgstr "批量移動應用"
Loading