feat: application list (#3160)

This commit is contained in:
shaohuzhang1 2025-05-28 18:57:09 +08:00 committed by GitHub
parent 743b04aebf
commit 345e588ef6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 273 additions and 8 deletions

View File

@ -11,9 +11,10 @@ from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter from drf_spectacular.utils import OpenApiParameter
from rest_framework import serializers from rest_framework import serializers
from application.serializers.application import ApplicationCreateSerializer from application.serializers.application import ApplicationCreateSerializer, ApplicationListResponse, \
ApplicationQueryRequest
from common.mixins.api_mixin import APIMixin from common.mixins.api_mixin import APIMixin
from common.result import ResultSerializer from common.result import ResultSerializer, ResultPageSerializer
class ApplicationCreateRequest(ApplicationCreateSerializer.SimplateRequest): class ApplicationCreateRequest(ApplicationCreateSerializer.SimplateRequest):
@ -25,6 +26,80 @@ class ApplicationCreateResponse(ResultSerializer):
return ApplicationCreateSerializer.ApplicationResponse() return ApplicationCreateSerializer.ApplicationResponse()
class ApplicationListResult(ResultSerializer):
def get_data(self):
return ApplicationListResponse(many=True)
class ApplicationPageResult(ResultPageSerializer):
def get_data(self):
return ApplicationListResponse(many=True)
class ApplicationQueryAPI(APIMixin):
@staticmethod
def get_parameters():
return [
OpenApiParameter(
name="workspace_id",
description="工作空间id",
type=OpenApiTypes.STR,
location='path',
required=True,
),
OpenApiParameter(
name="current_page",
description=_("Current page"),
type=OpenApiTypes.INT,
location='path',
required=True,
),
OpenApiParameter(
name="page_size",
description=_("Page size"),
type=OpenApiTypes.INT,
location='path',
required=True,
),
OpenApiParameter(
name="folder_id",
description=_("folder id"),
type=OpenApiTypes.STR,
location='query',
required=False,
),
OpenApiParameter(
name="name",
description=_("Application Name"),
type=OpenApiTypes.STR,
location='query',
required=False,
),
OpenApiParameter(
name="desc",
description=_("Application Description"),
type=OpenApiTypes.STR,
location='query',
required=False,
),
OpenApiParameter(
name="user_id",
description=_("User ID"),
type=OpenApiTypes.STR,
location='query',
required=False,
)
]
@staticmethod
def get_response():
return ApplicationListResult
@staticmethod
def get_page_response():
return ApplicationPageResult
class ApplicationCreateAPI(APIMixin): class ApplicationCreateAPI(APIMixin):
@staticmethod @staticmethod
def get_parameters(): def get_parameters():

View File

@ -7,6 +7,7 @@
@desc: @desc:
""" """
import hashlib import hashlib
import os
import re import re
from typing import Dict from typing import Dict
@ -17,10 +18,15 @@ from django.db.models import QuerySet
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from application.models.application import Application, ApplicationTypeChoices, ApplicationKnowledgeMapping from application.models.application import Application, ApplicationTypeChoices, ApplicationKnowledgeMapping, \
ApplicationFolder
from application.models.application_access_token import ApplicationAccessToken from application.models.application_access_token import ApplicationAccessToken
from common.database_model_manage.database_model_manage import DatabaseModelManage
from common.db.search import native_search, native_page_search
from common.exception.app_exception import AppApiException from common.exception.app_exception import AppApiException
from common.utils.common import get_file_content
from knowledge.models import Knowledge from knowledge.models import Knowledge
from maxkb.conf import PROJECT_DIR
from models_provider.models import Model from models_provider.models import Model
@ -227,11 +233,85 @@ class ApplicationCreateSerializer(serializers.Serializer):
) )
class ApplicationQueryRequest(serializers.Serializer):
folder_id = serializers.CharField(required=False, label=_("folder id"))
name = serializers.CharField(required=False, label=_('Application Name'))
desc = serializers.CharField(required=False, label=_("Application Description"))
user_id = serializers.UUIDField(required=False, label=_("User ID"))
class ApplicationListResponse(serializers.Serializer):
id = serializers.CharField(required=True, label=_("Primary key id"), help_text=_("Primary key id"))
name = serializers.CharField(required=True, label=_("Application Name"), help_text=_("Application Name"))
desc = serializers.CharField(required=True, label=_("Application Description"),
help_text=_("Application Description"))
is_publish = serializers.BooleanField(required=True, label=_("Model id"), help_text=_("Model id"))
type = serializers.CharField(required=True, label=_("Application type"), help_text=_("Application type"))
resource_type = serializers.CharField(required=True, label=_("Resource type"), help_text=_("Resource type"))
user_id = serializers.CharField(required=True, label=_('Affiliation user'), help_text=_("Affiliation user"))
create_time = serializers.CharField(required=True, label=_('Creation time'), help_text=_("Creation time"))
update_time = serializers.CharField(required=True, label=_('Modification time'), help_text=_("Modification time"))
class Query(serializers.Serializer):
workspace_id = serializers.CharField(required=False, label=_('workspace id'))
def get_query_set(self, instance: Dict):
folder_query_set = QuerySet(ApplicationFolder)
application_query_set = QuerySet(Application)
workspace_id = self.data.get('workspace_id')
user_id = instance.get('user_id')
desc = instance.get('desc')
name = instance.get('name')
if workspace_id is not None:
folder_query_set = folder_query_set.filter(workspace_id=workspace_id)
application_query_set = application_query_set.filter(workspace_id=workspace_id)
if user_id is not None:
folder_query_set = folder_query_set.filter(user_id=user_id)
application_query_set = application_query_set.filter(user_id=user_id)
folder_id = instance.get('folder_id')
if folder_id is not None:
folder_query_set = folder_query_set.filter(parent=folder_id)
application_query_set = application_query_set.filter(folder_id=folder_id)
if name is not None:
folder_query_set = folder_query_set.filter(name__contains=name)
application_query_set = application_query_set.filter(name__contains=name)
if desc is not None:
folder_query_set = folder_query_set.filter(desc__contains=desc)
application_query_set = application_query_set.filter(desc__contains=desc)
application_query_set = application_query_set.order_by("-update_time")
return {
'folder_query_set': folder_query_set,
'application_query_set': application_query_set
}
@staticmethod
def is_x_pack_ee():
workspace_user_role_mapping_model = DatabaseModelManage.get_model("workspace_user_role_mapping")
role_permission_mapping_model = DatabaseModelManage.get_model("role_permission_mapping_model")
return workspace_user_role_mapping_model is not None and role_permission_mapping_model is not None
def list(self, instance: Dict):
self.is_valid(raise_exception=True)
ApplicationQueryRequest(data=instance).is_valid(raise_exception=True)
return native_search(self.get_query_set(instance), select_string=get_file_content(
os.path.join(PROJECT_DIR, "apps", "application", 'sql',
'list_application_ee.sql' if self.is_x_pack_ee() else 'list_application.sql')))
def page(self, current_page: int, page_size: int, instance: Dict):
self.is_valid(raise_exception=True)
ApplicationQueryRequest(data=instance).is_valid(raise_exception=True)
return native_page_search(current_page, page_size, self.get_query_set(instance), get_file_content(
os.path.join(PROJECT_DIR, "apps", "application", 'sql',
'list_application_ee.sql' if self.is_x_pack_ee() else 'list_application.sql')),
)
class ApplicationSerializer(serializers.Serializer): class ApplicationSerializer(serializers.Serializer):
workspace_id = serializers.CharField(required=True, label=_('workspace id')) workspace_id = serializers.CharField(required=True, label=_('workspace id'))
user_id = serializers.UUIDField(required=True, label=_("User ID")) user_id = serializers.UUIDField(required=True, label=_("User ID"))
def insert(self, instance: Dict, with_valid=True): def insert(self, instance: Dict):
application_type = instance.get('type') application_type = instance.get('type')
if 'WORK_FLOW' == application_type: if 'WORK_FLOW' == application_type:
return self.insert_workflow(instance) return self.insert_workflow(instance)

View File

@ -0,0 +1,31 @@
select *
from (select "id"::text,
"name",
"desc",
"is_publish",
"type",
'application' as "resource_type",
"workspace_id",
"folder_id",
"user_id",
"create_time",
"update_time"
from application
where id in (select target
from workspace_user_resource_permission
where auth_target_type = 'APPLICATION'
and 'VIEW' = any (permission_list))
UNION
select "id",
"name",
"desc",
true as "is_publish",
'folder' as "type",
'folder' as "resource_type",
"workspace_id",
"parent_id" as "folder_id",
"user_id",
"create_time",
"update_time"
from application_folder ${folder_query_set}) temp
${application_query_set}

View File

@ -0,0 +1,39 @@
select *
from (select "id"::text,
"name",
"desc",
"is_publish",
"type",
'application' as "resource_type",
"workspace_id",
"folder_id",
"user_id",
"create_time",
"update_time"
from application
where id in (select target
from workspace_user_resource_permission
where auth_target_type = 'APPLICATION'
and case
when auth_type = 'ROLE' then
'APPLICATION_READ' in (select permission_id
from role_permission
where role_id in (select role_id
from user_role_relation))
else
'VIEW' = any (permission_list)
end)
UNION
select "id",
"name",
"desc",
true as "is_publish",
'folder' as "type",
'folder' as "resource_type",
"workspace_id",
"parent_id" as "folder_id",
"user_id",
"create_time",
"update_time"
from application_folder ${folder_query_set}) temp
${application_query_set}

View File

@ -6,5 +6,7 @@ app_name = 'application'
urlpatterns = [ urlpatterns = [
path('workspace/<str:workspace_id>/application', views.Application.as_view(), name='application'), path('workspace/<str:workspace_id>/application', views.Application.as_view(), name='application'),
path('workspace/<str:workspace_id>/application/<int:current_page>/<int:page_size>',
views.Application.Page.as_view(), name='application_page'),
path('workspace/<str:workspace_id>/application/<str:application_id>/application_key', path('workspace/<str:workspace_id>/application/<str:application_id>/application_key',
views.ApplicationKey.as_view())] views.ApplicationKey.as_view())]

View File

@ -11,10 +11,12 @@ from drf_spectacular.utils import extend_schema
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.views import APIView from rest_framework.views import APIView
from application.api.application_api import ApplicationCreateAPI from application.api.application_api import ApplicationCreateAPI, ApplicationQueryAPI
from application.serializers.application import ApplicationSerializer from application.serializers.application import ApplicationSerializer, Query
from common import result from common import result
from common.auth import TokenAuth from common.auth import TokenAuth
from common.auth.authentication import has_permissions
from common.constants.permission_constants import PermissionConstants
class Application(APIView): class Application(APIView):
@ -30,6 +32,38 @@ class Application(APIView):
responses=ApplicationCreateAPI.get_response(), responses=ApplicationCreateAPI.get_response(),
tags=[_('Application')] # type: ignore tags=[_('Application')] # type: ignore
) )
@has_permissions(PermissionConstants.APPLICATION_READ.get_workspace_permission())
def post(self, request: Request, workspace_id: str): def post(self, request: Request, workspace_id: str):
return result.success( return result.success(
ApplicationSerializer(data={'workspace_id': workspace_id, 'user_id': request.user.id}).insert(request.data)) ApplicationSerializer(data={'workspace_id': workspace_id, 'user_id': request.user.id}).insert(request.data))
@extend_schema(
methods=['GET'],
description=_('Get the application list'),
summary=_('Get the application list'),
operation_id=_('Get the application list'), # type: ignore
parameters=ApplicationQueryAPI.get_parameters(),
responses=ApplicationQueryAPI.get_response(),
tags=[_('Application')] # type: ignore
)
@has_permissions(PermissionConstants.APPLICATION_READ.get_workspace_permission())
def get(self, request: Request, workspace_id: str):
return result.success(Query(data={'workspace_id': workspace_id, 'user_id': request.user.id}).list(request.data))
class Page(APIView):
authentication_classes = [TokenAuth]
@extend_schema(
methods=['GET'],
description=_('Get the application list by page'),
summary=_('Get the application list by page'),
operation_id=_('Get the application list by page'), # type: ignore
parameters=ApplicationQueryAPI.get_parameters(),
responses=ApplicationQueryAPI.get_page_response(),
tags=[_('Application')] # type: ignore
)
@has_permissions(PermissionConstants.APPLICATION_READ.get_workspace_permission())
def get(self, request: Request, workspace_id: str, current_page: int, page_size: int):
return result.success(
Query(data={'workspace_id': workspace_id, 'user_id': request.user.id}).page(current_page, page_size,
request.query_params))

View File

@ -58,6 +58,7 @@ class SystemGroup(Enum):
SYSTEM_SETTING = "SYSTEM_SETTING" SYSTEM_SETTING = "SYSTEM_SETTING"
OPERATION_LOG = "OPERATION_LOG" OPERATION_LOG = "OPERATION_LOG"
OTHER = "OTHER" OTHER = "OTHER"
APPLICATION = "APPLICATION"
class WorkspaceGroup(Enum): class WorkspaceGroup(Enum):
@ -514,8 +515,11 @@ class PermissionConstants(Enum):
group=Group.LOGIN_AUTH, operate=Operate.EDIT, role_list=[RoleConstants.ADMIN], group=Group.LOGIN_AUTH, operate=Operate.EDIT, role_list=[RoleConstants.ADMIN],
parent_group=[SystemGroup.SYSTEM_SETTING] parent_group=[SystemGroup.SYSTEM_SETTING]
) )
APPLICATION_READ = Permission(group=Group.APPLICATION, operate=Operate.READ,
role_list=[RoleConstants.ADMIN, RoleConstants.USER],
parent_group=[SystemGroup.APPLICATION],
resource_permission_group_list=[ResourcePermissionGroup.VIEW],
)
def get_workspace_application_permission(self): def get_workspace_application_permission(self):
return lambda r, kwargs: Permission(group=self.value.group, operate=self.value.operate, return lambda r, kwargs: Permission(group=self.value.group, operate=self.value.operate,