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
3 changes: 3 additions & 0 deletions apps/locales/en_US/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -9602,3 +9602,6 @@ msgstr "Set chat user quota"

msgid "The token quota for the current period has been exhausted. Please contact the administrator."
msgstr ""

msgid "Get portal historical conversation by page"
msgstr ""
3 changes: 3 additions & 0 deletions apps/locales/zh_CN/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -9742,6 +9742,9 @@ msgstr "设置对话用户配额"
msgid "The token quota for the current period has been exhausted. Please contact the administrator."
msgstr "当前周期 Tokens 配额已用尽,请联系管理员。"

msgid "Get portal historical conversation by page"
msgstr "分页获取门户历史会话"

#: apps/xpack/views/system_chat_user.py:101
msgid "Batch set chat user quota"
msgstr "批量设置对话用户配额"
5 changes: 4 additions & 1 deletion apps/locales/zh_Hant/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -9740,4 +9740,7 @@ msgid "Set chat user quota"
msgstr "設置對話用戶配額"

msgid "The token quota for the current period has been exhausted. Please contact the administrator."
msgstr "當前週期 Tokens 配額已用盡,請聯繫管理員。"
msgstr "當前週期 Tokens 配額已用盡,請聯繫管理員。"

msgid "Get portal historical conversation by page"
msgstr "分頁獲取門戶歷史會話"
31 changes: 31 additions & 0 deletions apps/portal/api/portal.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,34 @@ class Logout(APIMixin):
@staticmethod
def get_response():
return DefaultResultSerializer

class Conversation(APIMixin):
@staticmethod
def get_parameters():
return [
OpenApiParameter(
name='current_page',
description='当前页码',
type=OpenApiTypes.INT,
location='path',
required=True,
),
OpenApiParameter(
name='page_size',
description='每页数量',
type=OpenApiTypes.INT,
location='path',
required=True,
),
OpenApiParameter(
name='name',
description='应用名称搜索',
type=OpenApiTypes.STR,
location='query',
required=False,
),
]

@staticmethod
def get_response():
return DefaultResultSerializer
126 changes: 86 additions & 40 deletions apps/portal/serializers/portal.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
import uuid_utils.compat as uuid
from django.core import signing
from django.core.cache import cache
from django.db.models import Exists, OuterRef, QuerySet
from django.db.models import Exists, OuterRef
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers

from application.models import Application
from application.models import Application, Chat
from application.models.application_access_token import ApplicationAccessToken
from common.auth.common import FileToken
from common.constants.authentication_type import AuthenticationType
Expand Down Expand Up @@ -80,7 +80,7 @@ def _handle_file_field(self, portal, field_name, value):
old_url = getattr(portal, field_name)
if old_url:
old_file_id = old_url.split("/")[-1]
QuerySet(File).filter(id=old_file_id).delete()
File.objects.filter(id=old_file_id).delete()
new_url = self._upload_file(value)
setattr(portal, field_name, new_url)
else:
Expand All @@ -103,6 +103,42 @@ def edit(self, instance, with_valid=True):
return PortalSerializer.Model(portal).data


class PortalApplicationAuthMixin:
"""门户应用授权过滤公共逻辑"""

@staticmethod
def get_authorized_application_queryset(user_id):
public_apps = ApplicationAccessToken.objects.filter(
application_id=OuterRef('id'),
authentication=False
)
if not ChatUser.objects.filter(id=user_id).exists():
return Application.objects.filter(Exists(public_apps))
authed_token_exists = ApplicationAccessToken.objects.filter(
application_id=OuterRef('id'),
authentication=True
)
direct_auth = ResourceChatUserAuthorize.objects.filter(
resource_id=OuterRef('id'),
resource_type=ResourceType.APPLICATION.value,
is_auth=True,
user_id=user_id
)
user_groups = UserGroupRelation.objects.filter(
user_id=user_id
).values_list('group_id', flat=True)
group_auth = ResourceChatUserGroupAuthorize.objects.filter(
resource_id=OuterRef('id'),
resource_type=ResourceType.APPLICATION.value,
is_auth=True,
user_group_id__in=user_groups
)
return Application.objects.filter(
Exists(public_apps) |
(Exists(authed_token_exists) & (Exists(direct_auth) | Exists(group_auth)))
)


class ApplicationResponseSerializer(serializers.Serializer):
id = serializers.CharField(required=True)
name = serializers.CharField(required=True)
Expand All @@ -116,62 +152,72 @@ class ApplicationResponseSerializer(serializers.Serializer):

class PortalApplicationSerializer(serializers.Serializer):

class Query(serializers.Serializer):
class Query(PortalApplicationAuthMixin, serializers.Serializer):
name = serializers.CharField(required=False, allow_blank=True, label=_('Application Name'),
help_text=_('Application name'))

def get_query_set(self):
queryset = Application.objects.filter(is_publish=True).only(
'id', 'name', 'desc', 'icon', 'type',
'dialogue_number', 'prologue', 'is_publish', 'create_time'
)
queryset = Application.objects.filter(is_publish=True)
name = self.data.get('name')
if name:
queryset = queryset.filter(name__icontains=name)
return queryset.order_by('-create_time')

def _apply_auth_filter(self, queryset, user_id):
chat_user_exists = ChatUser.objects.filter(id=user_id).exists()
public_apps = ApplicationAccessToken.objects.filter(
application_id=OuterRef('id'),
authentication=False
)
if not chat_user_exists:
return queryset.filter(Exists(public_apps))
authed_token_exists = ApplicationAccessToken.objects.filter(
application_id=OuterRef('id'),
authentication=True
)
direct_auth = ResourceChatUserAuthorize.objects.filter(
resource_id=OuterRef('id'),
resource_type=ResourceType.APPLICATION.value,
is_auth=True,
user_id=user_id
def page(self, current_page, page_size, user_id, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
queryset = self.get_query_set()
queryset = queryset.filter(
id__in=self.get_authorized_application_queryset(user_id).values('id')
)
user_groups = UserGroupRelation.objects.filter(
user_id=user_id
).values_list('group_id', flat=True)
group_auth = ResourceChatUserGroupAuthorize.objects.filter(
resource_id=OuterRef('id'),
resource_type=ResourceType.APPLICATION.value,
is_auth=True,
user_group_id__in=user_groups
return page_search(
current_page,
page_size,
queryset,
post_records_handler=lambda app: ApplicationResponseSerializer(app).data,
)
return queryset.filter(
Exists(public_apps) |
(Exists(authed_token_exists) & (Exists(direct_auth) | Exists(group_auth)))


class PortalHistoricalConversationResponseSerializer(serializers.Serializer):
id = serializers.CharField(required=True)
abstract = serializers.CharField(required=True)
create_time = serializers.CharField(required=True)
update_time = serializers.CharField(required=True)
application = serializers.SerializerMethodField()

def get_application(self, chat):
return {
'id': str(chat.application_id),
'name': chat.application.name,
'icon': chat.application.icon,
}


class PortalHistoricalConversationSerializer(serializers.Serializer):

class Query(PortalApplicationAuthMixin, serializers.Serializer):
name = serializers.CharField(required=False, allow_blank=True, label=_('Application Name'),
help_text=_('Application name'))

def get_query_set(self, user_id):
queryset = Chat.objects.filter(
chat_user_id=user_id,
is_deleted=False,
application_id__in=self.get_authorized_application_queryset(user_id).values('id')
)
name = self.data.get('name')
if name:
queryset = queryset.filter(application__name__icontains=name)
return queryset.select_related('application').order_by('-update_time', 'id')

def page(self, current_page, page_size, user_id, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
queryset = self.get_query_set()
queryset = self._apply_auth_filter(queryset, user_id)
return page_search(
current_page,
page_size,
queryset,
post_records_handler=lambda app: ApplicationResponseSerializer(app).data,
self.get_query_set(user_id),
post_records_handler=lambda chat: PortalHistoricalConversationResponseSerializer(chat).data,
)


Expand Down
16 changes: 10 additions & 6 deletions apps/portal/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@

from . import views

app_name = 'portal'
app_name = "portal"

urlpatterns = [
path('portal', views.PortalView.as_view()),
path('portal/info', views.PortalInfoView.as_view()),
path('portal/login', views.PortalLoginView.as_view()),
path('portal/logout', views.PortalLogoutView.as_view()),
path('portal/application/<int:current_page>/<int:page_size>', views.PortalApplicationView.as_view()),
path("portal", views.PortalView.as_view()),
path("portal/info", views.PortalInfoView.as_view()),
path("portal/login", views.PortalLoginView.as_view()),
path("portal/logout", views.PortalLogoutView.as_view()),
path("portal/application/<int:current_page>/<int:page_size>", views.PortalApplicationView.as_view()),
path(
"portal/historical_conversation/<int:current_page>/<int:page_size>",
views.PortalHistoricalConversationView.as_view(),
),
]
21 changes: 20 additions & 1 deletion apps/portal/views/portal.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
from common.utils.common import query_params_to_single_dict
from django.core.cache import cache
from portal.api.portal import PortalAPI
from portal.serializers.portal import PortalSerializer, PortalApplicationSerializer, PortalLoginSerializer
from portal.serializers.portal import PortalSerializer, PortalApplicationSerializer, PortalLoginSerializer, \
PortalHistoricalConversationSerializer


class PortalView(APIView):
Expand Down Expand Up @@ -77,6 +78,24 @@ def get(self, request: Request, current_page: int, page_size: int):
).page(current_page, page_size, str(request.user.id)))


class PortalHistoricalConversationView(APIView):
authentication_classes = [TokenAuth]

@extend_schema(
methods=['GET'],
description=_('Get portal historical conversation by page'),
summary=_('Get portal historical conversation by page'),
operation_id=_('Get portal historical conversation by page'),
parameters=PortalAPI.Conversation.get_parameters(),
responses=PortalAPI.Conversation.get_response(),
tags=[_('Portal')]
)
def get(self, request: Request, current_page: int, page_size: int):
return result.success(PortalHistoricalConversationSerializer.Query(
data={**query_params_to_single_dict(request.query_params)}
).page(current_page, page_size, str(request.user.id)))


class PortalLoginView(APIView):

@extend_schema(
Expand Down
Loading