Skip to content

Commit ed40556

Browse files
use field
reorder simplify nit nit add assert nit
1 parent 08877c5 commit ed40556

File tree

11 files changed

+77
-216
lines changed

11 files changed

+77
-216
lines changed

api/controllers/console/app/app.py

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
from fields.workflow_fields import workflow_partial_fields as _workflow_partial_fields_dict
3232
from libs.helper import AppIconUrlField, TimestampField
3333
from libs.login import current_account_with_tenant, login_required
34-
from libs.validators import validate_description_length
3534
from models import App, Workflow
3635
from services.app_dsl_service import AppDslService, ImportMode
3736
from services.app_service import AppService
@@ -76,51 +75,30 @@ def validate_tag_ids(cls, value: str | list[str] | None) -> list[str] | None:
7675

7776
class CreateAppPayload(BaseModel):
7877
name: str = Field(..., min_length=1, description="App name")
79-
description: str | None = Field(default=None, description="App description (max 400 chars)")
78+
description: str | None = Field(default=None, description="App description (max 400 chars)", max_length=400)
8079
mode: Literal["chat", "agent-chat", "advanced-chat", "workflow", "completion"] = Field(..., description="App mode")
8180
icon_type: str | None = Field(default=None, description="Icon type")
8281
icon: str | None = Field(default=None, description="Icon")
8382
icon_background: str | None = Field(default=None, description="Icon background color")
8483

85-
@field_validator("description")
86-
@classmethod
87-
def validate_description(cls, value: str | None) -> str | None:
88-
if value is None:
89-
return value
90-
return validate_description_length(value)
91-
9284

9385
class UpdateAppPayload(BaseModel):
9486
name: str = Field(..., min_length=1, description="App name")
95-
description: str | None = Field(default=None, description="App description (max 400 chars)")
87+
description: str | None = Field(default=None, description="App description (max 400 chars)", max_length=400)
9688
icon_type: str | None = Field(default=None, description="Icon type")
9789
icon: str | None = Field(default=None, description="Icon")
9890
icon_background: str | None = Field(default=None, description="Icon background color")
9991
use_icon_as_answer_icon: bool | None = Field(default=None, description="Use icon as answer icon")
10092
max_active_requests: int | None = Field(default=None, description="Maximum active requests")
10193

102-
@field_validator("description")
103-
@classmethod
104-
def validate_description(cls, value: str | None) -> str | None:
105-
if value is None:
106-
return value
107-
return validate_description_length(value)
108-
10994

11095
class CopyAppPayload(BaseModel):
11196
name: str | None = Field(default=None, description="Name for the copied app")
112-
description: str | None = Field(default=None, description="Description for the copied app")
97+
description: str | None = Field(default=None, description="Description for the copied app", max_length=400)
11398
icon_type: str | None = Field(default=None, description="Icon type")
11499
icon: str | None = Field(default=None, description="Icon")
115100
icon_background: str | None = Field(default=None, description="Icon background color")
116101

117-
@field_validator("description")
118-
@classmethod
119-
def validate_description(cls, value: str | None) -> str | None:
120-
if value is None:
121-
return value
122-
return validate_description_length(value)
123-
124102

125103
class AppExportQuery(BaseModel):
126104
include_secret: bool = Field(default=False, description="Include secrets in export")

api/controllers/console/datasets/datasets.py

Lines changed: 13 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from flask import request
44
from flask_restx import Resource, fields, marshal, marshal_with
5-
from pydantic import BaseModel, field_validator
5+
from pydantic import BaseModel, Field, field_validator
66
from sqlalchemy import select
77
from werkzeug.exceptions import Forbidden, NotFound
88

@@ -50,7 +50,6 @@
5050
)
5151
from fields.document_fields import document_status_fields
5252
from libs.login import current_account_with_tenant, login_required
53-
from libs.validators import validate_description_length
5453
from models import ApiToken, Dataset, Document, DocumentSegment, UploadFile
5554
from models.dataset import DatasetPermissionEnum
5655
from models.provider_ids import ModelProviderID
@@ -109,12 +108,6 @@ def _get_or_create_model(model_name: str, field_def):
109108
related_app_list_model = _get_or_create_model("RelatedAppList", related_app_list_copy)
110109

111110

112-
def _validate_name(name: str) -> str:
113-
if not name or len(name) < 1 or len(name) > 40:
114-
raise ValueError("Name must be between 1 to 40 characters.")
115-
return name
116-
117-
118111
def _validate_indexing_technique(value: str | None) -> str | None:
119112
if value is None:
120113
return value
@@ -124,24 +117,14 @@ def _validate_indexing_technique(value: str | None) -> str | None:
124117

125118

126119
class DatasetCreatePayload(BaseModel):
127-
name: str
128-
description: str = ""
120+
name: str = Field(..., min_length=1, max_length=40)
121+
description: str = Field("", max_length=400)
129122
indexing_technique: str | None = None
130123
permission: DatasetPermissionEnum | None = DatasetPermissionEnum.ONLY_ME
131124
provider: str = "vendor"
132125
external_knowledge_api_id: str | None = None
133126
external_knowledge_id: str | None = None
134127

135-
@field_validator("name")
136-
@classmethod
137-
def validate_name(cls, value: str) -> str:
138-
return _validate_name(value)
139-
140-
@field_validator("description", mode="before")
141-
@classmethod
142-
def validate_description(cls, value: Any) -> str:
143-
return validate_description_length(value or "")
144-
145128
@field_validator("indexing_technique")
146129
@classmethod
147130
def validate_indexing(cls, value: str | None) -> str | None:
@@ -156,8 +139,8 @@ def validate_provider(cls, value: str) -> str:
156139

157140

158141
class DatasetUpdatePayload(BaseModel):
159-
name: str | None = None
160-
description: str | None = None
142+
name: str | None = Field(None, min_length=1, max_length=40)
143+
description: str | None = Field(None, max_length=400)
161144
permission: DatasetPermissionEnum | None = None
162145
indexing_technique: str | None = None
163146
embedding_model: str | None = None
@@ -169,18 +152,6 @@ class DatasetUpdatePayload(BaseModel):
169152
external_knowledge_api_id: str | None = None
170153
icon_info: dict[str, Any] | None = None
171154

172-
@field_validator("name")
173-
@classmethod
174-
def validate_name(cls, value: str | None) -> str | None:
175-
return _validate_name(value) if value is not None else value
176-
177-
@field_validator("description", mode="before")
178-
@classmethod
179-
def validate_description(cls, value: Any) -> Any:
180-
if value is None:
181-
return value
182-
return validate_description_length(value)
183-
184155
@field_validator("indexing_technique")
185156
@classmethod
186157
def validate_indexing(cls, value: str | None) -> str | None:
@@ -451,22 +422,21 @@ def patch(self, dataset_id):
451422

452423
payload = DatasetUpdatePayload.model_validate(console_ns.payload or {})
453424
payload_data = payload.model_dump(exclude_unset=True)
454-
payload_raw = console_ns.payload or {}
455425
current_user, current_tenant_id = current_account_with_tenant()
456426

457427
# check embedding model setting
458428
if (
459-
payload_raw.get("indexing_technique") == "high_quality"
460-
and payload_raw.get("embedding_model_provider") is not None
461-
and payload_raw.get("embedding_model") is not None
429+
payload.indexing_technique == "high_quality"
430+
and payload.embedding_model_provider is not None
431+
and payload.embedding_model is not None
462432
):
463433
DatasetService.check_embedding_model_setting(
464-
dataset.tenant_id, payload_raw.get("embedding_model_provider"), payload_raw.get("embedding_model")
434+
dataset.tenant_id, payload.embedding_model_provider, payload.embedding_model
465435
)
466436

467437
# The role of the current user in the ta table must be admin, owner, editor, or dataset_operator
468438
DatasetPermissionService.check_permission(
469-
current_user, dataset, payload_data.get("permission"), payload_data.get("partial_member_list")
439+
current_user, dataset, payload.permission, payload.partial_member_list
470440
)
471441

472442
dataset = DatasetService.update_dataset(dataset_id_str, payload_data, current_user)
@@ -477,15 +447,10 @@ def patch(self, dataset_id):
477447
result_data = cast(dict[str, Any], marshal(dataset, dataset_detail_fields))
478448
tenant_id = current_tenant_id
479449

480-
if (
481-
payload_data.get("partial_member_list")
482-
and payload_data.get("permission") == DatasetPermissionEnum.PARTIAL_TEAM
483-
):
484-
DatasetPermissionService.update_partial_member_list(
485-
tenant_id, dataset_id_str, payload_data.get("partial_member_list")
486-
)
450+
if payload.partial_member_list is not None and payload.permission == DatasetPermissionEnum.PARTIAL_TEAM:
451+
DatasetPermissionService.update_partial_member_list(tenant_id, dataset_id_str, payload.partial_member_list)
487452
# clear partial member list when permission is only_me or all_team_members
488-
elif payload_data.get("permission") in {DatasetPermissionEnum.ONLY_ME, DatasetPermissionEnum.ALL_TEAM}:
453+
elif payload.permission in {DatasetPermissionEnum.ONLY_ME, DatasetPermissionEnum.ALL_TEAM}:
489454
DatasetPermissionService.clear_partial_member_list(dataset_id_str)
490455

491456
partial_member_list = DatasetPermissionService.get_dataset_partial_member_list(dataset_id_str)

api/controllers/console/datasets/external.py

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from flask import request
22
from flask_restx import Resource, fields, marshal
3-
from pydantic import BaseModel, field_validator
3+
from pydantic import BaseModel, Field
44
from werkzeug.exceptions import Forbidden, InternalServerError, NotFound
55

66
import services
@@ -73,34 +73,18 @@ def _build_dataset_detail_model():
7373
dataset_detail_model = _build_dataset_detail_model()
7474

7575

76-
def _validate_name(name: str) -> str:
77-
if not name or len(name) < 1 or len(name) > 100:
78-
raise ValueError("Name must be between 1 to 100 characters.")
79-
return name
80-
81-
8276
class ExternalKnowledgeApiPayload(BaseModel):
83-
name: str
77+
name: str = Field(..., min_length=1, max_length=40)
8478
settings: dict[str, object]
8579

86-
@field_validator("name")
87-
@classmethod
88-
def validate_name(cls, value: str) -> str:
89-
return _validate_name(value)
90-
9180

9281
class ExternalDatasetCreatePayload(BaseModel):
9382
external_knowledge_api_id: str
9483
external_knowledge_id: str
95-
name: str
96-
description: str | None = None
84+
name: str = Field(..., min_length=1, max_length=40)
85+
description: str | None = Field(None, max_length=400)
9786
external_retrieval_model: dict[str, object] | None = None
9887

99-
@field_validator("name")
100-
@classmethod
101-
def validate_dataset_name(cls, value: str) -> str:
102-
return _validate_name(value)
103-
10488

10589
class ExternalHitTestingPayload(BaseModel):
10690
query: str
@@ -312,6 +296,8 @@ def post(self, dataset_id):
312296
HitTestingService.hit_testing_args_check(payload.model_dump())
313297

314298
try:
299+
assert payload.external_retrieval_model is not None
300+
assert payload.metadata_filtering_conditions is not None
315301
response = HitTestingService.external_retrieve(
316302
dataset=dataset,
317303
query=payload.query,

api/controllers/console/datasets/rag_pipeline/rag_pipeline.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,6 @@
2222
logger = logging.getLogger(__name__)
2323

2424

25-
def _validate_name(name: str) -> str:
26-
if not name or len(name) < 1 or len(name) > 40:
27-
raise ValueError("Name must be between 1 to 40 characters.")
28-
return name
29-
30-
31-
def _validate_description_length(description: str) -> str:
32-
if len(description) > 400:
33-
raise ValueError("Description cannot exceed 400 characters.")
34-
return description
35-
36-
3725
@console_ns.route("/rag/pipeline/templates")
3826
class PipelineTemplateListApi(Resource):
3927
@setup_required
@@ -62,8 +50,8 @@ def get(self, template_id: str):
6250

6351

6452
class Payload(BaseModel):
65-
name: str = Field(min_length=1, max_length=40)
66-
description: str = Field(default="")
53+
name: str = Field(..., min_length=1, max_length=40)
54+
description: str = Field(default="", max_length=400)
6755
icon_info: dict[str, object] | None = None
6856

6957

api/controllers/console/datasets/rag_pipeline/rag_pipeline_import.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ def post(self):
5050
# Check user role first
5151
current_user, _ = current_account_with_tenant()
5252
payload = RagPipelineImportPayload.model_validate(console_ns.payload or {})
53-
args = payload.model_dump()
5453

5554
# Create service with session
5655
with Session(db.engine) as session:

api/controllers/console/datasets/rag_pipeline/rag_pipeline_workflow.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -671,14 +671,8 @@ def get(self, pipeline: Pipeline):
671671
"""
672672
current_user, _ = current_account_with_tenant()
673673

674-
query = WorkflowListQuery.model_validate(
675-
{
676-
"page": request.args.get("page", type=int, default=1),
677-
"limit": request.args.get("limit", type=int, default=10),
678-
"user_id": request.args.get("user_id"),
679-
"named_only": request.args.get("named_only"),
680-
}
681-
)
674+
query = WorkflowListQuery.model_validate(request.args.to_dict())
675+
682676
page = query.page
683677
limit = query.limit
684678
user_id = query.user_id
@@ -687,7 +681,6 @@ def get(self, pipeline: Pipeline):
687681
if user_id:
688682
if user_id != current_user.id:
689683
raise Forbidden()
690-
user_id = cast(str, user_id)
691684

692685
rag_pipeline_service = RagPipelineService()
693686
with Session(db.engine) as session:

api/controllers/console/explore/saved_message.py

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@
1515
from services.errors.message import MessageNotExistsError
1616
from services.saved_message_service import SavedMessageService
1717

18+
19+
class SavedMessageListQuery(BaseModel):
20+
last_id: UUID | None = None
21+
limit: int = Field(default=20, ge=1, le=100)
22+
23+
24+
class SavedMessageCreatePayload(BaseModel):
25+
message_id: UUID
26+
27+
28+
register_schema_models(console_ns, SavedMessageListQuery, SavedMessageCreatePayload)
29+
30+
1831
feedback_fields = {"rating": fields.String}
1932

2033
message_fields = {
@@ -44,12 +57,7 @@ def get(self, installed_app):
4457
if app_model.mode != "completion":
4558
raise NotCompletionAppError()
4659

47-
args = SavedMessageListQuery.model_validate(
48-
{
49-
"last_id": request.args.get("last_id"),
50-
"limit": request.args.get("limit", default=20, type=int),
51-
}
52-
)
60+
args = SavedMessageListQuery.model_validate(request.args.to_dict())
5361

5462
return SavedMessageService.pagination_by_last_id(
5563
app_model,
@@ -91,15 +99,3 @@ def delete(self, installed_app, message_id):
9199
SavedMessageService.delete(app_model, current_user, message_id)
92100

93101
return {"result": "success"}, 204
94-
95-
96-
class SavedMessageListQuery(BaseModel):
97-
last_id: UUID | None = None
98-
limit: int = Field(default=20, ge=1, le=100)
99-
100-
101-
class SavedMessageCreatePayload(BaseModel):
102-
message_id: UUID
103-
104-
105-
register_schema_models(console_ns, SavedMessageListQuery, SavedMessageCreatePayload)

api/controllers/inner_api/mail.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ class BaseMail(Resource):
2828
@inner_api_ns.expect(inner_api_ns.models[InnerMailPayload.__name__])
2929
def post(self):
3030
args = InnerMailPayload.model_validate(inner_api_ns.payload or {})
31-
send_inner_email_task.delay( # type: ignore
31+
send_inner_email_task.delay(
3232
to=args.to,
3333
subject=args.subject,
3434
body=args.body,
35-
substitutions=args.substitutions,
35+
substitutions=args.substitutions, # type: ignore
3636
)
3737
return {"message": "success"}, 200
3838

0 commit comments

Comments
 (0)