refactor: simplify inner API to creator_email lookup, remove redundant workspace validation

This commit is contained in:
zhangx1n
2026-03-25 01:22:14 +08:00
parent 0ba464e820
commit e57ee4bcbe

View File

@ -1,11 +1,11 @@
"""Inner API endpoints for app DSL import/export. """Inner API endpoints for app DSL import/export.
Called by the Go admin-api service (dify-enterprise) to import and export Called by the enterprise admin-api service to import and export
app definitions as YAML DSL files. These endpoints delegate to app definitions as YAML DSL files. These endpoints delegate to
:class:`~services.app_dsl_service.AppDslService` for the actual work. :class:`~services.app_dsl_service.AppDslService` for the actual work.
Import requires an ``account_email`` identifying the workspace member who Import requires a ``creator_email`` identifying the workspace member who
will own the imported app. The caller (admin-api) is responsible for will create the imported app. The caller (admin-api) is responsible for
deciding which user to attribute the operation to. deciding which user to attribute the operation to.
""" """
@ -19,13 +19,12 @@ from controllers.inner_api import inner_api_ns
from controllers.inner_api.wraps import enterprise_inner_api_only from controllers.inner_api.wraps import enterprise_inner_api_only
from extensions.ext_database import db from extensions.ext_database import db
from models import Account, App from models import Account, App
from models.account import TenantAccountJoin
from services.app_dsl_service import AppDslService, ImportMode, ImportStatus from services.app_dsl_service import AppDslService, ImportMode, ImportStatus
class InnerAppDSLImportPayload(BaseModel): class InnerAppDSLImportPayload(BaseModel):
yaml_content: str yaml_content: str
account_email: str creator_email: str
name: str | None = None name: str | None = None
description: str | None = None description: str | None = None
@ -35,21 +34,20 @@ class EnterpriseAppDSLImport(Resource):
@setup_required @setup_required
@enterprise_inner_api_only @enterprise_inner_api_only
def post(self, workspace_id: str): def post(self, workspace_id: str):
"""Import a DSL into a workspace on behalf of a specified account. """Import a DSL into a workspace on behalf of a specified creator.
Requires ``account_email`` to identify the workspace member who will Requires ``creator_email`` to identify the account that will own the
own the imported app. The account must be active and belong to the imported app. The account must be active. Workspace existence and
target workspace. Returns 202 when a DSL version mismatch requires membership are validated by the Go admin-api caller.
confirmation, 400 on business failure, and 200 on success.
Returns 200 on success, 202 when a DSL version mismatch requires
confirmation, and 400 on business failure.
""" """
args = InnerAppDSLImportPayload.model_validate(inner_api_ns.payload or {}) args = InnerAppDSLImportPayload.model_validate(inner_api_ns.payload or {})
account = _resolve_workspace_account(workspace_id, args.account_email) account = _get_active_account(args.creator_email)
if account is None: if account is None:
return { return {"message": f"account '{args.creator_email}' not found or inactive"}, 404
"message": f"account '{args.account_email}' not found, inactive, "
f"or not a member of workspace '{workspace_id}'"
}, 404
account.set_tenant_id(workspace_id) account.set_tenant_id(workspace_id)
@ -64,11 +62,11 @@ class EnterpriseAppDSLImport(Resource):
) )
session.commit() session.commit()
if result.status == ImportStatus.FAILED: status_code_map = {
return result.model_dump(mode="json"), 400 ImportStatus.FAILED: 400,
elif result.status == ImportStatus.PENDING: ImportStatus.PENDING: 202,
return result.model_dump(mode="json"), 202 }
return result.model_dump(mode="json"), 200 return result.model_dump(mode="json"), status_code_map.get(result.status, 200)
@inner_api_ns.route("/enterprise/apps/<string:app_id>/dsl") @inner_api_ns.route("/enterprise/apps/<string:app_id>/dsl")
@ -95,22 +93,13 @@ class EnterpriseAppDSLExport(Resource):
return {"data": data}, 200 return {"data": data}, 200
def _resolve_workspace_account(workspace_id: str, email: str) -> Account | None: def _get_active_account(email: str) -> Account | None:
"""Look up an active account by email and verify it belongs to the workspace. """Look up an active account by email.
Returns the account with its tenant set, or None if the account doesn't Workspace membership is already validated by the Go admin-api caller;
exist, is inactive, or is not a member of the given workspace. this function only needs to retrieve the Account object for AppDslService.
""" """
account = db.session.query(Account).filter_by(email=email).first() account = db.session.query(Account).filter_by(email=email).first()
if account is None or account.status != "active": if account is None or account.status != "active":
return None return None
membership = (
db.session.query(TenantAccountJoin)
.filter_by(tenant_id=workspace_id, account_id=account.id)
.first()
)
if membership is None:
return None
return account return account