Skip to content

Commit 57752a7

Browse files
authored
Merge branch 'main' into password_lib_issue
2 parents b54197e + 751ce4e commit 57752a7

40 files changed

+1283
-319
lines changed

api/controllers/console/apikey.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@
2424

2525
api_key_list = {"data": fields.List(fields.Nested(api_key_fields), attribute="items")}
2626

27+
api_key_item_model = console_ns.model("ApiKeyItem", api_key_fields)
28+
29+
api_key_list_model = console_ns.model(
30+
"ApiKeyList", {"data": fields.List(fields.Nested(api_key_item_model), attribute="items")}
31+
)
32+
2733

2834
def _get_resource(resource_id, tenant_id, resource_model):
2935
if resource_model == App:
@@ -52,7 +58,7 @@ class BaseApiKeyListResource(Resource):
5258
token_prefix: str | None = None
5359
max_keys = 10
5460

55-
@marshal_with(api_key_list)
61+
@marshal_with(api_key_list_model)
5662
def get(self, resource_id):
5763
assert self.resource_id_field is not None, "resource_id_field must be set"
5864
resource_id = str(resource_id)
@@ -66,7 +72,7 @@ def get(self, resource_id):
6672
).all()
6773
return {"items": keys}
6874

69-
@marshal_with(api_key_fields)
75+
@marshal_with(api_key_item_model)
7076
@edit_permission_required
7177
def post(self, resource_id):
7278
assert self.resource_id_field is not None, "resource_id_field must be set"
@@ -136,15 +142,15 @@ class AppApiKeyListResource(BaseApiKeyListResource):
136142
@console_ns.doc("get_app_api_keys")
137143
@console_ns.doc(description="Get all API keys for an app")
138144
@console_ns.doc(params={"resource_id": "App ID"})
139-
@console_ns.response(200, "Success", api_key_list)
145+
@console_ns.response(200, "Success", api_key_list_model)
140146
def get(self, resource_id): # type: ignore
141147
"""Get all API keys for an app"""
142148
return super().get(resource_id)
143149

144150
@console_ns.doc("create_app_api_key")
145151
@console_ns.doc(description="Create a new API key for an app")
146152
@console_ns.doc(params={"resource_id": "App ID"})
147-
@console_ns.response(201, "API key created successfully", api_key_fields)
153+
@console_ns.response(201, "API key created successfully", api_key_item_model)
148154
@console_ns.response(400, "Maximum keys exceeded")
149155
def post(self, resource_id): # type: ignore
150156
"""Create a new API key for an app"""
@@ -176,15 +182,15 @@ class DatasetApiKeyListResource(BaseApiKeyListResource):
176182
@console_ns.doc("get_dataset_api_keys")
177183
@console_ns.doc(description="Get all API keys for a dataset")
178184
@console_ns.doc(params={"resource_id": "Dataset ID"})
179-
@console_ns.response(200, "Success", api_key_list)
185+
@console_ns.response(200, "Success", api_key_list_model)
180186
def get(self, resource_id): # type: ignore
181187
"""Get all API keys for a dataset"""
182188
return super().get(resource_id)
183189

184190
@console_ns.doc("create_dataset_api_key")
185191
@console_ns.doc(description="Create a new API key for a dataset")
186192
@console_ns.doc(params={"resource_id": "Dataset ID"})
187-
@console_ns.response(201, "API key created successfully", api_key_fields)
193+
@console_ns.response(201, "API key created successfully", api_key_item_model)
188194
@console_ns.response(400, "Maximum keys exceeded")
189195
def post(self, resource_id): # type: ignore
190196
"""Create a new API key for a dataset"""

api/controllers/console/app/annotation.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from fields.annotation_fields import (
1616
annotation_fields,
1717
annotation_hit_history_fields,
18+
build_annotation_model,
1819
)
1920
from libs.helper import uuid_value
2021
from libs.login import login_required
@@ -184,7 +185,7 @@ def get(self, app_id):
184185
},
185186
)
186187
)
187-
@console_ns.response(201, "Annotation created successfully", annotation_fields)
188+
@console_ns.response(201, "Annotation created successfully", build_annotation_model(console_ns))
188189
@console_ns.response(403, "Insufficient permissions")
189190
@setup_required
190191
@login_required
@@ -238,7 +239,11 @@ class AnnotationExportApi(Resource):
238239
@console_ns.doc("export_annotations")
239240
@console_ns.doc(description="Export all annotations for an app")
240241
@console_ns.doc(params={"app_id": "Application ID"})
241-
@console_ns.response(200, "Annotations exported successfully", fields.List(fields.Nested(annotation_fields)))
242+
@console_ns.response(
243+
200,
244+
"Annotations exported successfully",
245+
console_ns.model("AnnotationList", {"data": fields.List(fields.Nested(build_annotation_model(console_ns)))}),
246+
)
242247
@console_ns.response(403, "Insufficient permissions")
243248
@setup_required
244249
@login_required
@@ -263,7 +268,7 @@ class AnnotationUpdateDeleteApi(Resource):
263268
@console_ns.doc("update_delete_annotation")
264269
@console_ns.doc(description="Update or delete an annotation")
265270
@console_ns.doc(params={"app_id": "Application ID", "annotation_id": "Annotation ID"})
266-
@console_ns.response(200, "Annotation updated successfully", annotation_fields)
271+
@console_ns.response(200, "Annotation updated successfully", build_annotation_model(console_ns))
267272
@console_ns.response(204, "Annotation deleted successfully")
268273
@console_ns.response(403, "Insufficient permissions")
269274
@console_ns.expect(parser)
@@ -359,7 +364,16 @@ class AnnotationHitHistoryListApi(Resource):
359364
.add_argument("limit", type=int, location="args", default=20, help="Page size")
360365
)
361366
@console_ns.response(
362-
200, "Hit histories retrieved successfully", fields.List(fields.Nested(annotation_hit_history_fields))
367+
200,
368+
"Hit histories retrieved successfully",
369+
console_ns.model(
370+
"AnnotationHitHistoryList",
371+
{
372+
"data": fields.List(
373+
fields.Nested(console_ns.model("AnnotationHitHistoryItem", annotation_hit_history_fields))
374+
)
375+
},
376+
),
363377
)
364378
@console_ns.response(403, "Insufficient permissions")
365379
@setup_required

api/controllers/console/app/app.py

Lines changed: 130 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@
1818
from core.ops.ops_trace_manager import OpsTraceManager
1919
from core.workflow.enums import NodeType
2020
from extensions.ext_database import db
21-
from fields.app_fields import app_detail_fields, app_detail_fields_with_site, app_pagination_fields
21+
from fields.app_fields import (
22+
deleted_tool_fields,
23+
model_config_fields,
24+
model_config_partial_fields,
25+
site_fields,
26+
tag_fields,
27+
)
28+
from fields.workflow_fields import workflow_partial_fields as _workflow_partial_fields_dict
29+
from libs.helper import AppIconUrlField, TimestampField
2230
from libs.login import current_account_with_tenant, login_required
2331
from libs.validators import validate_description_length
2432
from models import App, Workflow
@@ -29,6 +37,111 @@
2937

3038
ALLOW_CREATE_APP_MODES = ["chat", "agent-chat", "advanced-chat", "workflow", "completion"]
3139

40+
# Register models for flask_restx to avoid dict type issues in Swagger
41+
# Register base models first
42+
tag_model = console_ns.model("Tag", tag_fields)
43+
44+
workflow_partial_model = console_ns.model("WorkflowPartial", _workflow_partial_fields_dict)
45+
46+
model_config_model = console_ns.model("ModelConfig", model_config_fields)
47+
48+
model_config_partial_model = console_ns.model("ModelConfigPartial", model_config_partial_fields)
49+
50+
deleted_tool_model = console_ns.model("DeletedTool", deleted_tool_fields)
51+
52+
site_model = console_ns.model("Site", site_fields)
53+
54+
app_partial_model = console_ns.model(
55+
"AppPartial",
56+
{
57+
"id": fields.String,
58+
"name": fields.String,
59+
"max_active_requests": fields.Raw(),
60+
"description": fields.String(attribute="desc_or_prompt"),
61+
"mode": fields.String(attribute="mode_compatible_with_agent"),
62+
"icon_type": fields.String,
63+
"icon": fields.String,
64+
"icon_background": fields.String,
65+
"icon_url": AppIconUrlField,
66+
"model_config": fields.Nested(model_config_partial_model, attribute="app_model_config", allow_null=True),
67+
"workflow": fields.Nested(workflow_partial_model, allow_null=True),
68+
"use_icon_as_answer_icon": fields.Boolean,
69+
"created_by": fields.String,
70+
"created_at": TimestampField,
71+
"updated_by": fields.String,
72+
"updated_at": TimestampField,
73+
"tags": fields.List(fields.Nested(tag_model)),
74+
"access_mode": fields.String,
75+
"create_user_name": fields.String,
76+
"author_name": fields.String,
77+
"has_draft_trigger": fields.Boolean,
78+
},
79+
)
80+
81+
app_detail_model = console_ns.model(
82+
"AppDetail",
83+
{
84+
"id": fields.String,
85+
"name": fields.String,
86+
"description": fields.String,
87+
"mode": fields.String(attribute="mode_compatible_with_agent"),
88+
"icon": fields.String,
89+
"icon_background": fields.String,
90+
"enable_site": fields.Boolean,
91+
"enable_api": fields.Boolean,
92+
"model_config": fields.Nested(model_config_model, attribute="app_model_config", allow_null=True),
93+
"workflow": fields.Nested(workflow_partial_model, allow_null=True),
94+
"tracing": fields.Raw,
95+
"use_icon_as_answer_icon": fields.Boolean,
96+
"created_by": fields.String,
97+
"created_at": TimestampField,
98+
"updated_by": fields.String,
99+
"updated_at": TimestampField,
100+
"access_mode": fields.String,
101+
"tags": fields.List(fields.Nested(tag_model)),
102+
},
103+
)
104+
105+
app_detail_with_site_model = console_ns.model(
106+
"AppDetailWithSite",
107+
{
108+
"id": fields.String,
109+
"name": fields.String,
110+
"description": fields.String,
111+
"mode": fields.String(attribute="mode_compatible_with_agent"),
112+
"icon_type": fields.String,
113+
"icon": fields.String,
114+
"icon_background": fields.String,
115+
"icon_url": AppIconUrlField,
116+
"enable_site": fields.Boolean,
117+
"enable_api": fields.Boolean,
118+
"model_config": fields.Nested(model_config_model, attribute="app_model_config", allow_null=True),
119+
"workflow": fields.Nested(workflow_partial_model, allow_null=True),
120+
"api_base_url": fields.String,
121+
"use_icon_as_answer_icon": fields.Boolean,
122+
"max_active_requests": fields.Integer,
123+
"created_by": fields.String,
124+
"created_at": TimestampField,
125+
"updated_by": fields.String,
126+
"updated_at": TimestampField,
127+
"deleted_tools": fields.List(fields.Nested(deleted_tool_model)),
128+
"access_mode": fields.String,
129+
"tags": fields.List(fields.Nested(tag_model)),
130+
"site": fields.Nested(site_model),
131+
},
132+
)
133+
134+
app_pagination_model = console_ns.model(
135+
"AppPagination",
136+
{
137+
"page": fields.Integer,
138+
"limit": fields.Integer(attribute="per_page"),
139+
"total": fields.Integer,
140+
"has_more": fields.Boolean(attribute="has_next"),
141+
"data": fields.List(fields.Nested(app_partial_model), attribute="items"),
142+
},
143+
)
144+
32145

33146
@console_ns.route("/apps")
34147
class AppListApi(Resource):
@@ -50,7 +163,7 @@ class AppListApi(Resource):
50163
.add_argument("tag_ids", type=str, location="args", help="Comma-separated tag IDs")
51164
.add_argument("is_created_by_me", type=bool, location="args", help="Filter by creator")
52165
)
53-
@console_ns.response(200, "Success", app_pagination_fields)
166+
@console_ns.response(200, "Success", app_pagination_model)
54167
@setup_required
55168
@login_required
56169
@account_initialization_required
@@ -137,7 +250,7 @@ def uuid_list(value):
137250
for app in app_pagination.items:
138251
app.has_draft_trigger = str(app.id) in draft_trigger_app_ids
139252

140-
return marshal(app_pagination, app_pagination_fields), 200
253+
return marshal(app_pagination, app_pagination_model), 200
141254

142255
@console_ns.doc("create_app")
143256
@console_ns.doc(description="Create a new application")
@@ -154,13 +267,13 @@ def uuid_list(value):
154267
},
155268
)
156269
)
157-
@console_ns.response(201, "App created successfully", app_detail_fields)
270+
@console_ns.response(201, "App created successfully", app_detail_model)
158271
@console_ns.response(403, "Insufficient permissions")
159272
@console_ns.response(400, "Invalid request parameters")
160273
@setup_required
161274
@login_required
162275
@account_initialization_required
163-
@marshal_with(app_detail_fields)
276+
@marshal_with(app_detail_model)
164277
@cloud_edition_billing_resource_check("apps")
165278
@edit_permission_required
166279
def post(self):
@@ -191,13 +304,13 @@ class AppApi(Resource):
191304
@console_ns.doc("get_app_detail")
192305
@console_ns.doc(description="Get application details")
193306
@console_ns.doc(params={"app_id": "Application ID"})
194-
@console_ns.response(200, "Success", app_detail_fields_with_site)
307+
@console_ns.response(200, "Success", app_detail_with_site_model)
195308
@setup_required
196309
@login_required
197310
@account_initialization_required
198311
@enterprise_license_required
199312
@get_app_model
200-
@marshal_with(app_detail_fields_with_site)
313+
@marshal_with(app_detail_with_site_model)
201314
def get(self, app_model):
202315
"""Get app detail"""
203316
app_service = AppService()
@@ -227,15 +340,15 @@ def get(self, app_model):
227340
},
228341
)
229342
)
230-
@console_ns.response(200, "App updated successfully", app_detail_fields_with_site)
343+
@console_ns.response(200, "App updated successfully", app_detail_with_site_model)
231344
@console_ns.response(403, "Insufficient permissions")
232345
@console_ns.response(400, "Invalid request parameters")
233346
@setup_required
234347
@login_required
235348
@account_initialization_required
236349
@get_app_model
237350
@edit_permission_required
238-
@marshal_with(app_detail_fields_with_site)
351+
@marshal_with(app_detail_with_site_model)
239352
def put(self, app_model):
240353
"""Update app"""
241354
parser = (
@@ -300,14 +413,14 @@ class AppCopyApi(Resource):
300413
},
301414
)
302415
)
303-
@console_ns.response(201, "App copied successfully", app_detail_fields_with_site)
416+
@console_ns.response(201, "App copied successfully", app_detail_with_site_model)
304417
@console_ns.response(403, "Insufficient permissions")
305418
@setup_required
306419
@login_required
307420
@account_initialization_required
308421
@get_app_model
309422
@edit_permission_required
310-
@marshal_with(app_detail_fields_with_site)
423+
@marshal_with(app_detail_with_site_model)
311424
def post(self, app_model):
312425
"""Copy app"""
313426
# The role of the current user in the ta table must be admin, owner, or editor
@@ -396,7 +509,7 @@ class AppNameApi(Resource):
396509
@login_required
397510
@account_initialization_required
398511
@get_app_model
399-
@marshal_with(app_detail_fields)
512+
@marshal_with(app_detail_model)
400513
@edit_permission_required
401514
def post(self, app_model):
402515
args = parser.parse_args()
@@ -428,7 +541,7 @@ class AppIconApi(Resource):
428541
@login_required
429542
@account_initialization_required
430543
@get_app_model
431-
@marshal_with(app_detail_fields)
544+
@marshal_with(app_detail_model)
432545
@edit_permission_required
433546
def post(self, app_model):
434547
parser = (
@@ -454,13 +567,13 @@ class AppSiteStatus(Resource):
454567
"AppSiteStatusRequest", {"enable_site": fields.Boolean(required=True, description="Enable or disable site")}
455568
)
456569
)
457-
@console_ns.response(200, "Site status updated successfully", app_detail_fields)
570+
@console_ns.response(200, "Site status updated successfully", app_detail_model)
458571
@console_ns.response(403, "Insufficient permissions")
459572
@setup_required
460573
@login_required
461574
@account_initialization_required
462575
@get_app_model
463-
@marshal_with(app_detail_fields)
576+
@marshal_with(app_detail_model)
464577
@edit_permission_required
465578
def post(self, app_model):
466579
parser = reqparse.RequestParser().add_argument("enable_site", type=bool, required=True, location="json")
@@ -482,14 +595,14 @@ class AppApiStatus(Resource):
482595
"AppApiStatusRequest", {"enable_api": fields.Boolean(required=True, description="Enable or disable API")}
483596
)
484597
)
485-
@console_ns.response(200, "API status updated successfully", app_detail_fields)
598+
@console_ns.response(200, "API status updated successfully", app_detail_model)
486599
@console_ns.response(403, "Insufficient permissions")
487600
@setup_required
488601
@login_required
489602
@is_admin_or_owner_required
490603
@account_initialization_required
491604
@get_app_model
492-
@marshal_with(app_detail_fields)
605+
@marshal_with(app_detail_model)
493606
def post(self, app_model):
494607
parser = reqparse.RequestParser().add_argument("enable_api", type=bool, required=True, location="json")
495608
args = parser.parse_args()

0 commit comments

Comments
 (0)