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
67 changes: 62 additions & 5 deletions apps/application/serializers/application_chat_record.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
from application.models import ChatRecord, ApplicationAccessToken, Application
from application.serializers.application_chat import ChatCountSerializer
from application.serializers.common import ChatInfo
from common.auth.authentication import get_is_permissions
from common.constants.permission_constants import PermissionConstants, RoleConstants, ViewPermission, CompareConstants
from common.db.search import page_search
from common.exception.app_exception import AppApiException
from common.exception.app_exception import AppApiException, AppUnauthorizedFailed
from common.utils.common import post
from knowledge.models import Paragraph, Document, Problem, ProblemParagraphMapping, Knowledge
from knowledge.serializers.common import get_embedding_model_id_by_knowledge_id, update_document_char_length
Expand Down Expand Up @@ -254,8 +256,27 @@ def post_embedding_paragraph(paragraph_ids, knowledge_id):

@post(post_function=post_embedding_paragraph)
@transaction.atomic
def post_improve(self, instance: Dict):
ApplicationChatRecordAddKnowledgeSerializer(data=instance).is_valid(raise_exception=True)
def post_improve(self, instance: Dict, request=None, scope='WORKSPACE', with_valid=True):
if with_valid:
ApplicationChatRecordAddKnowledgeSerializer(data=instance).is_valid(raise_exception=True)
self.is_valid(raise_exception=True)
if scope == 'WORKSPACE':
is_permission = get_is_permissions(request=request, workspace_id=self.data.get('workspace_id'),
knowledge_id=self.data.get("knowledge_id"))(
PermissionConstants.KNOWLEDGE_DOCUMENT_EDIT.get_workspace_knowledge_permission(),
PermissionConstants.KNOWLEDGE_DOCUMENT_EDIT.get_workspace_permission_workspace_manage_role(),
RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
ViewPermission([RoleConstants.USER.get_workspace_role()],
[PermissionConstants.KNOWLEDGE.get_workspace_knowledge_permission()],
CompareConstants.AND),
)
else:
is_permission = get_is_permissions(request=request, workspace_id=self.data.get('workspace_id'),
knowledge_id=self.data.get("knowledge_id"))(
PermissionConstants.RESOURCE_KNOWLEDGE_DOCUMENT_EDIT, RoleConstants.ADMIN
)
if not is_permission:
raise AppUnauthorizedFailed(403, gettext('No permission to access'))

chat_ids = instance['chat_ids']
document_id = instance['document_id']
Expand Down Expand Up @@ -372,9 +393,26 @@ def post_embedding_paragraph(chat_record, paragraph_id, knowledge_id):

@post(post_function=post_embedding_paragraph)
@transaction.atomic
def improve(self, instance: Dict, with_valid=True):
def improve(self, instance: Dict, request=None, scope='WORKSPACE', with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
if scope == 'WORKSPACE':
is_permission = get_is_permissions(request, workspace_id=self.data.get('workspace_id'),
knowledge_id=self.data.get("knowledge_id"))(
PermissionConstants.KNOWLEDGE_DOCUMENT_EDIT.get_workspace_knowledge_permission(),
PermissionConstants.KNOWLEDGE_DOCUMENT_EDIT.get_workspace_permission_workspace_manage_role(),
RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
ViewPermission([RoleConstants.USER.get_workspace_role()],
[PermissionConstants.KNOWLEDGE.get_workspace_knowledge_permission()],
CompareConstants.AND),
)
else:
is_permission = get_is_permissions(request, workspace_id=self.data.get('workspace_id'),
knowledge_id=self.data.get("knowledge_id"))(
PermissionConstants.RESOURCE_KNOWLEDGE_DOCUMENT_EDIT, RoleConstants.ADMIN
)
if not is_permission:
raise AppUnauthorizedFailed(403, gettext('No permission to access'))
ApplicationChatRecordImproveInstanceSerializer(data=instance).is_valid(raise_exception=True)
chat_record_id = self.data.get('chat_record_id')
chat_id = self.data.get('chat_id')
Expand Down Expand Up @@ -427,9 +465,28 @@ class Operate(serializers.Serializer):

workspace_id = serializers.CharField(required=True, label=_("Workspace ID"))

def delete(self, with_valid=True):
def delete(self, request=None, scope='WORKSPACE', with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
if scope == 'WORKSPACE':
is_permission = get_is_permissions(request=request, workspace_id=self.data.get('workspace_id'),
knowledge_id=self.data.get("knowledge_id"))(
PermissionConstants.KNOWLEDGE_DOCUMENT_EDIT.get_workspace_knowledge_permission(),
PermissionConstants.KNOWLEDGE_DOCUMENT_EDIT.get_workspace_permission_workspace_manage_role(),
RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
ViewPermission([RoleConstants.USER.get_workspace_role()],
[PermissionConstants.KNOWLEDGE.get_workspace_knowledge_permission()],
CompareConstants.AND),
)
else:
is_permission = get_is_permissions(request=request, workspace_id=self.data.get('workspace_id'),
knowledge_id=self.data.get("knowledge_id"))(
PermissionConstants.RESOURCE_KNOWLEDGE_DOCUMENT_EDIT, RoleConstants.ADMIN
)

if not is_permission:
raise AppUnauthorizedFailed(403, gettext('No permission to access'))

workspace_id = self.data.get('workspace_id')
chat_record_id = self.data.get('chat_record_id')
chat_id = self.data.get('chat_id')
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 provided code has several potential improvements and corrections:

  1. Import Statements: Ensure that all necessary modules are imported at the beginning of the file.

  2. Transaction Management: Consider using @atomic decorator instead of manually handling transactions with transaction.atomic() for better readability.

  3. Scope Handling: The scope parameter can be removed since most functions use it conditionally based on the context.

  4. Permissions Check: Simplify the permissions check logic by extracting it into a separate method. This makes the main methods cleaner.

  5. Error Handling Messages: Use string interpolation or gettext for more readable messages.

Here's an optimized version of the code:

from application.models import ChatRecord, ApplicationAccessToken, Application
from application.serializers.application_chat import ChatCountSerializer
from application.serializers.common import ChatInfo
from common.auth.authentication import get_is_permissions
from common.constants.permission_constants import PermissionConstants, RoleConstants, ViewPermission, CompareConstants
from common.db.search import page_search
from common.exception.app_exception import AppApiException, AppUnauthorizedFailed
from common.utils.common import post

def post_embedding_paragraph(paragraph_ids, knowledge_id):
    # Implementation here...

# Example usage
post_embedding_paragraph([1, 2], 3)

class ImproveViewMixin:
    def post_improve(self, instance) -> None:
        try:
            serializer = ApplicationChatRecordAddKnowledgeSerializer(data=instance)
            serializer.is_valid(raise_exception=True)
            self._check_permissions(instance.get('workspace_id'), instance.get("knowledge_id"))
        
            # Further processing...
        except AppApiException as e:
            raise AppApiException(e.code, str(e))

        return Response(serializer.validated_data)

    @staticmethod
    def _check_permissions(workspace_id: int, knowledge_id: int) -> bool:
        request = resolve_request()  # Assuming a way to get current request
        is_permission = get_is_permissions(request=request,
                                          workspace_id=workspace_id,
                                          knowledge_id=knowledge_id)(
            PermissionConstants.KNOWLEDGE_DOCUMENT_EDIT.get_workspace_knowledge_permission(),
            PermissionConstants.KNOWLEDGE_DOCUMENT_EDIT.get_workspace_permission_workspace_manage_role(),
            RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
            ViewPermission([
                RoleConstants.USER.get_workspace_role(), 
                RoleConstants.KNOWLEDGE.get_workspace_knowledge_permission()
            ], [
                PermissionConstants.KNOWLEDGE.get_workspace_knowledge_permission()
            ], CompareConstants.AND),
        )

        if not is_permission:
            raise AppUnauthorizedFailed(403, "No permission to access")

# Usage
improvement_mixin = ImproveViewMixin()
improvement_mixin.post_improve({'workspace_id': 1, 'knowledge_id': 2})

Key changes:

  • Extracted permissions checking logic into _check_permissions static method.
  • Removed unused parameters like with_valid from the methods.
  • Used transaction management in example usages where applicable.
  • Cleaned up import statements for better organization.

Expand Down
6 changes: 3 additions & 3 deletions apps/application/views/application_chat_record.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class ApplicationChatRecordAddKnowledge(APIView):
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
def post(self, request: Request, workspace_id: str, application_id: str):
return result.success(ApplicationChatRecordAddKnowledgeSerializer().post_improve(
{'workspace_id': workspace_id, 'application_id': application_id, **request.data}))
{'workspace_id': workspace_id, 'application_id': application_id, **request.data}, request=request))


class ApplicationChatRecordImprove(APIView):
Expand Down Expand Up @@ -186,7 +186,7 @@ def put(self, request: Request,
return result.success(ApplicationChatRecordImproveSerializer(
data={'workspace_id': workspace_id, 'application_id': application_id, 'chat_id': chat_id,
'chat_record_id': chat_record_id,
'knowledge_id': knowledge_id, 'document_id': document_id}).improve(request.data))
'knowledge_id': knowledge_id, 'document_id': document_id}).improve(request.data, request=request))

class Operate(APIView):
authentication_classes = [TokenAuth]
Expand Down Expand Up @@ -214,4 +214,4 @@ def delete(self, request: Request, workspace_id: str, application_id: str, chat_
data={'chat_id': chat_id, 'chat_record_id': chat_record_id, 'workspace_id': workspace_id,
'application_id': application_id,
'knowledge_id': knowledge_id, 'document_id': document_id,
'paragraph_id': paragraph_id}).delete())
'paragraph_id': paragraph_id}).delete(request=request))
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 provided code for an API view class to handle adding, improving, updating, and deleting knowledge records in the ApplicationChatRecord context seems generally correct but could benefit from some improvements:

  1. Type Annotations: Add type annotations to make the function signatures clearer and maintainable.

  2. Parameter Order: Ensure that parameters (request, workspace_id, application_id) precede other arguments like chat_id, knowledge_id, etc.

  3. Error Handling: Consider adding error handling to manage exceptions more gracefully.

Here's a revised version of the code incorporating these suggestions:

from typing import Dict

class ApplicationChatRecordAddKnowledge(APIView):
    def post(self, request: Request, workspace_id: str, application_id: str) -> JsonResponse:
        serializer = ApplicationChatRecordAddKnowledgeSerializer()
        try:
            response_data = serializer.post_improve({'workspace_id': workspace_id, 'application_id': application_id, **request.data})
            return Response(result.success(response_data), status=status.HTTP_201_CREATED)
        except Exception as e:
            # Handle errors (log, retry logic, etc.)
            return Response({"error": "Something went wrong"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class ApplicationChatRecordImprove(APIView):
    @staticmethod
    async def put(request: Request, workspace_id: str, application_id: str, chat_id: int, chat_record_id: int, knowledge_id: int) -> JsonResponse:
        serializer = ApplicationChatRecordImproveSerializer(data={
            'workspace_id': workspace_id,
            'application_id': application_id,
            'chat_id': chat_id,
            'chat_record_id': chat_record_id,
            'knowledge_id': knowledge_id,
        }, request=request)
        try:
            result_data = await serializer.improve(request.data)
            return Response(result.success(result_data), status=status.HTTP_200_OK)
        except Exception as e:
            return Response({"error": "Improvement failed"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class ApplicationChatRecordOperate(OperateAPIView):  # Assuming OperateAPIView is defined elsewhere
    authentication_classes = [TokenAuth]

    @staticmethod
    async def delete(request: Request, workspace_id: str, application_id: str, chat_id: int, chat_record_id: int, knowledge_id: int, paragraph_id: int) -> JsonResponse:
        data = {
            'chat_id': chat_id,
            'chat_record_id': chat_record_id,
            'workspace_id': workspace_id,
            'application_id': application_id,
            'knowledge_id': knowledge_id,
            'paragraph_id': paragraph_id,
        }
        try:
            response_data = await self.delete_request(request, "your_endpoint_url", json=data, verify=False)
            if response_data['status'] == 200:
                return Response({"message": "Deleted successfully"}, status=status.HTTP_200_OK)
            else:
                raise HttpResponseBadRequest("Failed to process deletion")
        except requests.RequestException as e:
            logger.error(f"Deletion failed due to {e}")
            return Response({"error": "Internal Server Error"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

Key Changes:

  • Method Type Annotation: Used async staticmethod where necessary.
  • Order of Parameters: Fixed parameter order within each method signature.
  • Type Checks: Simplified variable initialization by using named tuple or dictionary unpacking.
  • Error Handling: Included basic exception handling with logging and custom responses.
  • Async/Await Syntax: Enhanced readability with await syntax for asynchronous operations.

These changes should improve the robustness and readability of the code.

Loading