From 9bb3b1fa9891daffdaf3b69a16f9ea7ad4a71e95 Mon Sep 17 00:00:00 2001 From: chariri Date: Thu, 9 Jul 2026 13:21:27 +0900 Subject: [PATCH] refactor(api): migrate snippet workspace endpoints to BaseModel (#37956) Co-authored-by: Asuka Minato --- api/controllers/console/snippets/payloads.py | 2 + api/controllers/console/workspace/snippets.py | 83 ++----------------- api/openapi/markdown/console-openapi.md | 14 +--- api/services/snippet_service.py | 6 +- .../generated/api/console/apps/types.gen.ts | 2 + .../generated/api/console/apps/zod.gen.ts | 2 + .../api/console/snippets/types.gen.ts | 2 + .../generated/api/console/snippets/zod.gen.ts | 2 + .../api/console/workspaces/types.gen.ts | 6 +- .../api/console/workspaces/zod.gen.ts | 8 +- 10 files changed, 28 insertions(+), 99 deletions(-) diff --git a/api/controllers/console/snippets/payloads.py b/api/controllers/console/snippets/payloads.py index a3c90626d30..de4115b6576 100644 --- a/api/controllers/console/snippets/payloads.py +++ b/api/controllers/console/snippets/payloads.py @@ -148,6 +148,8 @@ class PublishWorkflowPayload(BaseModel): """Payload for publishing snippet workflow.""" knowledge_base_setting: dict[str, Any] | None = Field(default=None) + marked_name: str | None = Field(default=None, max_length=20) + marked_comment: str | None = Field(default=None, max_length=100) class SnippetImportPayload(BaseModel): diff --git a/api/controllers/console/workspace/snippets.py b/api/controllers/console/workspace/snippets.py index 18407b62d52..75ba9b64fd9 100644 --- a/api/controllers/console/workspace/snippets.py +++ b/api/controllers/console/workspace/snippets.py @@ -1,12 +1,9 @@ import logging -from datetime import datetime -from typing import Any from urllib.parse import quote +from uuid import UUID from flask import Response, request from flask_restx import Resource -from pydantic import Field as PydanticField -from pydantic import field_validator from sqlalchemy.orm import Session, sessionmaker from werkzeug.exceptions import NotFound @@ -37,7 +34,8 @@ from controllers.console.wraps import ( from core.plugin.entities.plugin import PluginDependency from extensions.ext_database import db from fields.base import ResponseModel -from libs.helper import dump_response, to_timestamp +from fields.snippet_fields import SnippetListItemResponse, SnippetPaginationResponse, SnippetResponse +from libs.helper import dump_response from libs.login import login_required from models import Account from models.snippet import SnippetType @@ -65,77 +63,6 @@ class SnippetUseCountResponse(ResponseModel): use_count: int -class SnippetTagResponse(ResponseModel): - id: str - name: str - type: str - - -class SnippetAccountResponse(ResponseModel): - id: str - name: str - email: str - - -class SnippetListItemResponse(ResponseModel): - id: str - name: str - description: str | None - type: SnippetType - version: int - use_count: int - is_published: bool - icon_info: dict[str, Any] | None - tags: list[SnippetTagResponse] - created_by: str | None - author_name: str | None - created_at: int - updated_by: str | None - updated_at: int - - @field_validator("created_at", "updated_at", mode="before") - @classmethod - def _normalize_timestamp(cls, value: datetime | int | None) -> int: - timestamp = to_timestamp(value) - if timestamp is None: - raise ValueError("timestamp is required") - return timestamp - - -class SnippetResponse(ResponseModel): - id: str - name: str - description: str | None - type: SnippetType - version: int - use_count: int - is_published: bool - icon_info: dict[str, Any] | None - graph: dict[str, Any] = PydanticField(validation_alias="graph_dict") - input_fields: list[dict[str, Any]] = PydanticField(validation_alias="input_fields_list") - tags: list[SnippetTagResponse] - created_by: SnippetAccountResponse | None = PydanticField(validation_alias="created_by_account") - created_at: int - updated_by: SnippetAccountResponse | None = PydanticField(validation_alias="updated_by_account") - updated_at: int - - @field_validator("created_at", "updated_at", mode="before") - @classmethod - def _normalize_timestamp(cls, value: datetime | int | None) -> int: - timestamp = to_timestamp(value) - if timestamp is None: - raise ValueError("timestamp is required") - return timestamp - - -class SnippetPaginationResponse(ResponseModel): - data: list[SnippetListItemResponse] - page: int - limit: int - total: int - has_more: bool - - def _snippet_service() -> SnippetService: return SnippetService(sessionmaker(bind=db.engine, expire_on_commit=False)) @@ -259,7 +186,7 @@ class CustomizedSnippetDetailApi(Resource): @login_required @account_initialization_required @with_current_tenant_id - def get(self, current_tenant_id: str, snippet_id: str): + def get(self, current_tenant_id: str, snippet_id: UUID): """Get customized snippet details.""" snippet_service = _snippet_service() snippet = snippet_service.get_snippet_by_id( @@ -535,4 +462,4 @@ class CustomizedSnippetUseCountIncrementApi(Resource): session.commit() session.refresh(snippet) - return SnippetUseCountResponse(result="success", use_count=snippet.use_count).model_dump(mode="json"), 200 + return {"result": "success", "use_count": snippet.use_count}, 200 diff --git a/api/openapi/markdown/console-openapi.md b/api/openapi/markdown/console-openapi.md index bc9e7a626eb..76912376340 100644 --- a/api/openapi/markdown/console-openapi.md +++ b/api/openapi/markdown/console-openapi.md @@ -20493,6 +20493,8 @@ Payload for publishing snippet workflow. | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | | knowledge_base_setting | object | | No | +| marked_comment | string | | No | +| marked_name | string | | No | #### PublishedWorkflowRunPayload @@ -21270,14 +21272,6 @@ Validated metadata extracted from a Skill package. | inferable | boolean | | Yes | | reason | string | | No | -#### SnippetAccountResponse - -| Name | Type | Description | Required | -| ---- | ---- | ----------- | -------- | -| email | string | | Yes | -| id | string | | Yes | -| name | string | | Yes | - #### SnippetDependencyCheckResponse | Name | Type | Description | Required | @@ -21407,7 +21401,7 @@ Payload for running a loop node in snippet draft workflow. | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | | created_at | integer | | Yes | -| created_by | [SnippetAccountResponse](#snippetaccountresponse) | | Yes | +| created_by | [SimpleAccountResponse](#simpleaccountresponse) | | Yes | | description | string | | Yes | | graph | object | | Yes | | icon_info | object | | Yes | @@ -21418,7 +21412,7 @@ Payload for running a loop node in snippet draft workflow. | tags | [ [SnippetTagResponse](#snippettagresponse) ] | | Yes | | type | [SnippetType](#snippettype) | | Yes | | updated_at | integer | | Yes | -| updated_by | [SnippetAccountResponse](#snippetaccountresponse) | | Yes | +| updated_by | [SimpleAccountResponse](#simpleaccountresponse) | | Yes | | use_count | integer | | Yes | | version | integer | | Yes | diff --git a/api/services/snippet_service.py b/api/services/snippet_service.py index 64c1ec12370..fb4d3bbc00e 100644 --- a/api/services/snippet_service.py +++ b/api/services/snippet_service.py @@ -1,6 +1,6 @@ import json import logging -from collections.abc import Iterator, Mapping, Sequence +from collections.abc import Generator, Mapping, Sequence from contextlib import contextmanager from datetime import UTC, datetime from typing import Any @@ -68,7 +68,7 @@ class SnippetService: self._workflow_run_repo = DifyAPIRepositoryFactory.create_api_workflow_run_repository(session_maker) @contextmanager - def _session_scope(self) -> Iterator[Session]: + def _session_scope(self) -> Generator[Session, None, None]: current_session = getattr(self, "_session", None) if current_session is not None: yield current_session @@ -625,8 +625,6 @@ class SnippetService: conversation_variables=[], rag_pipeline_variables=draft_workflow.rag_pipeline_variables, kind=WorkflowKind.SNIPPET.value, - marked_name="", - marked_comment="", ) session.add(workflow) diff --git a/packages/contracts/generated/api/console/apps/types.gen.ts b/packages/contracts/generated/api/console/apps/types.gen.ts index f18eec3f8b9..7bf3531d1ac 100644 --- a/packages/contracts/generated/api/console/apps/types.gen.ts +++ b/packages/contracts/generated/api/console/apps/types.gen.ts @@ -1240,6 +1240,8 @@ export type PublishWorkflowPayload = { knowledge_base_setting?: { [key: string]: unknown } | null + marked_comment?: string | null + marked_name?: string | null } export type WorkflowPublishResponse = { diff --git a/packages/contracts/generated/api/console/apps/zod.gen.ts b/packages/contracts/generated/api/console/apps/zod.gen.ts index 91d6f6bd01e..8e05a59f700 100644 --- a/packages/contracts/generated/api/console/apps/zod.gen.ts +++ b/packages/contracts/generated/api/console/apps/zod.gen.ts @@ -767,6 +767,8 @@ export const zWorkflowDraftVariableUpdatePayload = z.object({ */ export const zPublishWorkflowPayload = z.object({ knowledge_base_setting: z.record(z.string(), z.unknown()).nullish(), + marked_comment: z.string().max(100).nullish(), + marked_name: z.string().max(20).nullish(), }) /** diff --git a/packages/contracts/generated/api/console/snippets/types.gen.ts b/packages/contracts/generated/api/console/snippets/types.gen.ts index 4bc9db22ee9..cb26047a07e 100644 --- a/packages/contracts/generated/api/console/snippets/types.gen.ts +++ b/packages/contracts/generated/api/console/snippets/types.gen.ts @@ -201,6 +201,8 @@ export type PublishWorkflowPayload = { knowledge_base_setting?: { [key: string]: unknown } | null + marked_comment?: string | null + marked_name?: string | null } export type WorkflowPublishResponse = { diff --git a/packages/contracts/generated/api/console/snippets/zod.gen.ts b/packages/contracts/generated/api/console/snippets/zod.gen.ts index 5909bc5f332..f98b2d9c889 100644 --- a/packages/contracts/generated/api/console/snippets/zod.gen.ts +++ b/packages/contracts/generated/api/console/snippets/zod.gen.ts @@ -123,6 +123,8 @@ export const zWorkflowDraftVariableUpdatePayload = z.object({ */ export const zPublishWorkflowPayload = z.object({ knowledge_base_setting: z.record(z.string(), z.unknown()).nullish(), + marked_comment: z.string().max(100).nullish(), + marked_name: z.string().max(20).nullish(), }) /** diff --git a/packages/contracts/generated/api/console/workspaces/types.gen.ts b/packages/contracts/generated/api/console/workspaces/types.gen.ts index 540c2993105..55792eccc56 100644 --- a/packages/contracts/generated/api/console/workspaces/types.gen.ts +++ b/packages/contracts/generated/api/console/workspaces/types.gen.ts @@ -52,7 +52,7 @@ export type CreateSnippetPayload = { export type SnippetResponse = { created_at: number - created_by: SnippetAccountResponse | null + created_by: SimpleAccountResponse | null description: string | null graph: { [key: string]: unknown @@ -69,7 +69,7 @@ export type SnippetResponse = { tags: Array type: SnippetType updated_at: number - updated_by: SnippetAccountResponse | null + updated_by: SimpleAccountResponse | null use_count: number version: number } @@ -1060,7 +1060,7 @@ export type InputFieldDefinition = { type?: string | null } -export type SnippetAccountResponse = { +export type SimpleAccountResponse = { email: string id: string name: string diff --git a/packages/contracts/generated/api/console/workspaces/zod.gen.ts b/packages/contracts/generated/api/console/workspaces/zod.gen.ts index 5a8a15faccf..51fbbf5a6c9 100644 --- a/packages/contracts/generated/api/console/workspaces/zod.gen.ts +++ b/packages/contracts/generated/api/console/workspaces/zod.gen.ts @@ -697,9 +697,9 @@ export const zCreateSnippetPayload = z.object({ }) /** - * SnippetAccountResponse + * SimpleAccountResponse */ -export const zSnippetAccountResponse = z.object({ +export const zSimpleAccountResponse = z.object({ email: z.string(), id: z.string(), name: z.string(), @@ -726,7 +726,7 @@ export const zSnippetType = z.enum(['group', 'node']) */ export const zSnippetResponse = z.object({ created_at: z.int(), - created_by: zSnippetAccountResponse.nullable(), + created_by: zSimpleAccountResponse.nullable(), description: z.string().nullable(), graph: z.record(z.string(), z.unknown()), icon_info: z.record(z.string(), z.unknown()).nullable(), @@ -737,7 +737,7 @@ export const zSnippetResponse = z.object({ tags: z.array(zSnippetTagResponse), type: zSnippetType, updated_at: z.int(), - updated_by: zSnippetAccountResponse.nullable(), + updated_by: zSimpleAccountResponse.nullable(), use_count: z.int(), version: z.int(), })