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
51 changes: 41 additions & 10 deletions apps/application/api/application_api_key.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter

from application.serializers.application_access_token import ApiKeyEnableEditSerializer
from application.serializers.application_api_key import EditApplicationKeySerializer, ApplicationKeySerializerModel
from common.mixins.api_mixin import APIMixin
from common.result import ResultSerializer
Expand All @@ -16,6 +17,11 @@ def get_data(self):
return ApplicationKeySerializerModel()


class ApiKeyEnableResult(ResultSerializer):
def get_data(self):
return ApiKeyEnableEditSerializer()


class ApplicationKeyAPI(APIMixin):
@staticmethod
def get_parameters():
Expand All @@ -24,16 +30,16 @@ def get_parameters():
name="workspace_id",
description="工作空间id",
type=OpenApiTypes.STR,
location='path',
location="path",
required=True,
),
OpenApiParameter(
name="application_id",
description="application ID",
type=OpenApiTypes.STR,
location='path',
location="path",
required=True,
)
),
]

@staticmethod
Expand All @@ -48,14 +54,39 @@ def get_response():
class Operate(APIMixin):
@staticmethod
def get_parameters():
return [*ApplicationKeyAPI.get_parameters(), OpenApiParameter(
name="api_key_id",
description="ApiKeyId",
type=OpenApiTypes.STR,
location='path',
required=True,
)]
return [
*ApplicationKeyAPI.get_parameters(),
OpenApiParameter(
name="api_key_id",
description="ApiKeyId",
type=OpenApiTypes.STR,
location="path",
required=True,
),
]

@staticmethod
def get_request():
return EditApplicationKeySerializer

class Enable(APIMixin):
@staticmethod
def get_parameters():
return [
*ApplicationKeyAPI.get_parameters(),
OpenApiParameter(
name="enable_api_key",
description="是否启用 api key 访问应用",
type=OpenApiTypes.BOOL,
location="query",
required=True,
),
]

@staticmethod
def get_request():
return None

@staticmethod
def get_response():
return ApiKeyEnableResult
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 6.1.2 on 2026-10-28 10:06

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("application", "0016_v3_upgrade"),
]

operations = [
migrations.AddField(
model_name="applicationaccesstoken",
name="enable_api_key",
field=models.BooleanField(default=False, verbose_name="是否启用api key访问应用"),
),
]
20 changes: 11 additions & 9 deletions apps/application/models/application_access_token.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# coding=utf-8
"""
@project: MaxKB
@Author:虎虎
@file: application_access_token.py
@date:2025/5/27 9:55
@desc:
@project: MaxKB
@Author:虎虎
@file: application_access_token.py
@date:2025/5/27 9:55
@desc:
"""

from django.contrib.postgres.fields import ArrayField
from django.db import models

Expand All @@ -17,19 +18,20 @@ class ApplicationAccessToken(AppModelMixin):
"""
应用认证token
"""

application = models.OneToOneField(Application, primary_key=True, on_delete=models.CASCADE, verbose_name="应用id")
access_token = models.CharField(max_length=128, verbose_name="用户公开访问 认证token", unique=True)
is_active = models.BooleanField(default=True, verbose_name="是否开启公开访问")
access_num = models.IntegerField(default=100, verbose_name="访问次数")
white_active = models.BooleanField(default=False, verbose_name="是否开启白名单")
white_list = ArrayField(verbose_name="白名单列表",
base_field=models.CharField(max_length=128, blank=True)
, default=list)
white_list = ArrayField(
verbose_name="白名单列表", base_field=models.CharField(max_length=128, blank=True), default=list
)
show_source = models.BooleanField(default=False, verbose_name="是否显示知识来源")
show_exec = models.BooleanField(default=False, verbose_name="是否显示执行详情")
authentication = models.BooleanField(default=False, verbose_name="是否需要认证")
authentication_value = models.JSONField(verbose_name="认证的值", default=dict)

enable_api_key = models.BooleanField(default=False, verbose_name="是否启用api key访问应用")
language = models.CharField(max_length=10, verbose_name="语言", default=None, null=True)

class Meta:
Expand Down
45 changes: 45 additions & 0 deletions apps/application/serializers/application_access_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class AccessTokenEditSerializer(serializers.Serializer):
show_source = serializers.BooleanField(required=False, label=_("Whether to display knowledge sources"))
show_exec = serializers.BooleanField(required=False, label=_("Display execution details"))
language = serializers.CharField(required=False, allow_blank=True, allow_null=True, label=_("language"))
enable_api_key = serializers.BooleanField(required=False, label=_("Enable API key"))
authentication = serializers.BooleanField(default=False, label="Do you need authentication")

authentication_value = serializers.JSONField(required=False, label="Certified value", default=dict)
Expand Down Expand Up @@ -73,6 +74,8 @@ def edit(self, instance):
application_access_token.language = instance.get("language")
if "language" not in instance or instance.get("language") is None:
application_access_token.language = None
if "enable_api_key" in instance and instance.get("enable_api_key") is not None:
application_access_token.enable_api_key = instance.get("enable_api_key")
if "authentication" in instance and instance.get("authentication") is not None:
application_access_token.authentication = instance.get("authentication")
application_access_token.authentication_value = {
Expand Down Expand Up @@ -128,5 +131,47 @@ def one(self, with_valid=True):
"show_source": application_access_token.show_source,
"show_exec": application_access_token.show_exec,
"language": application_access_token.language,
"enable_api_key": application_access_token.enable_api_key,
**other,
}


class ApiKeyEnableEditSerializer(serializers.Serializer):
application_id = serializers.UUIDField(required=True, label=_("Application ID"))
enable_api_key = serializers.BooleanField(required=True, label=_("Enable API key"))


class ApiKeyEnableSerializer(serializers.Serializer):
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
application_id = serializers.UUIDField(required=True, label=_("Application ID"))

def is_valid(self, *, raise_exception=False):
super().is_valid(raise_exception=True)
workspace_id = self.data.get("workspace_id")
query_set = QuerySet(Application).filter(id=self.data.get("application_id"))
if workspace_id:
query_set = query_set.filter(workspace_id=workspace_id)
if not query_set.exists():
raise AppApiException(500, _("Application id does not exist"))

def edit(self, instance):
self.is_valid(raise_exception=True)
enable_api_key_serializer = ApiKeyEnableEditSerializer(
data={**instance, "application_id": self.data.get("application_id")}
)
enable_api_key_serializer.is_valid(raise_exception=True)
application_access_token = (
QuerySet(ApplicationAccessToken).filter(application_id=self.data.get("application_id")).first()
)
if application_access_token is None:
application_access_token = ApplicationAccessToken(
application_id=self.data.get("application_id"),
access_token=hashlib.md5(str(uuid.uuid7()).encode()).hexdigest()[8:24],
is_active=True,
)
application_access_token.enable_api_key = enable_api_key_serializer.validated_data.get("enable_api_key")
application_access_token.save()
return {
"application_id": application_access_token.application_id,
"enable_api_key": application_access_token.enable_api_key,
}
1 change: 1 addition & 0 deletions apps/application/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
path('workspace/<str:workspace_id>/application/<str:application_id>/chat_record/aggregation', views.ApplicationStats.ChatRecordAggregation.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/application_key/<str:api_key_id>', views.ApplicationKey.Operate.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/application_key/<int:current_page>/<int:page_size>', views.ApplicationKey.Page.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/enable_api_key', views.ApplicationApiKeyEnable.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/export', views.ApplicationAPI.Export.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/application_version', views.ApplicationVersionView.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/access_token', views.AccessToken.as_view()),
Expand Down
Loading
Loading