mirror of
https://github.com/langgenius/dify.git
synced 2026-11-11 13:51:25 +08:00
121 lines
5.3 KiB
Python
121 lines
5.3 KiB
Python
"""Authenticated Console Workspace policy and actor/App availability APIs."""
|
|
|
|
from flask import request
|
|
from flask_restx import Resource
|
|
from pydantic import ValidationError
|
|
from werkzeug.exceptions import BadRequest, Forbidden, NotFound
|
|
|
|
from configs import dify_config
|
|
from controllers.common.schema import register_response_schema_models, register_schema_models
|
|
from controllers.console import console_ns
|
|
from controllers.console.flask_admission import console_account_admission
|
|
from core.dify_builder.models import Actor
|
|
from extensions.application_services.dify_builder_cognition_policy import (
|
|
build_cognition_policy_service,
|
|
policy_projection,
|
|
)
|
|
from libs.exception import BaseHTTPException
|
|
from libs.external_api import error_responses
|
|
from libs.helper import dump_response
|
|
from machinery.context import RequestContext
|
|
from services.dify_builder.application.cognition_policy import CognitionPolicyDeniedError
|
|
from services.dify_builder.service import AppAccess
|
|
from services.dify_builder.wiring import _authorize_app
|
|
|
|
from .dify_builder_fields import DifyBuilderFeatureUnavailableResponse
|
|
from .dify_builder_policy_fields import (
|
|
DifyBuilderAvailabilityResponse,
|
|
DifyBuilderPolicyPayload,
|
|
DifyBuilderPolicyResponse,
|
|
)
|
|
|
|
|
|
class BuilderPolicyConflictError(BaseHTTPException):
|
|
error_code = "builder_policy_conflict"
|
|
code = 409
|
|
description = "Workspace Builder policy changed; reload before saving."
|
|
|
|
|
|
register_schema_models(console_ns, DifyBuilderPolicyPayload)
|
|
register_response_schema_models(
|
|
console_ns, DifyBuilderPolicyResponse, DifyBuilderAvailabilityResponse, DifyBuilderFeatureUnavailableResponse
|
|
)
|
|
|
|
|
|
def _actor(context: RequestContext) -> Actor:
|
|
return Actor(tenant_id=context.active_workspace_id, account_id=context.account_id)
|
|
|
|
|
|
def _raise_policy_error(error: CognitionPolicyDeniedError):
|
|
if error.reason == "policy_revision_conflict":
|
|
raise BuilderPolicyConflictError() from error
|
|
raise Forbidden("Workspace administrator permission is required.") from error
|
|
|
|
|
|
@console_ns.route("/workspaces/current/dify-builder/policy")
|
|
class DifyBuilderPolicyApi(Resource):
|
|
@console_ns.response(200, "Success", console_ns.models[DifyBuilderPolicyResponse.__name__])
|
|
@console_ns.response(
|
|
403, "App Builder is disabled", console_ns.models[DifyBuilderFeatureUnavailableResponse.__name__]
|
|
)
|
|
@console_account_admission()
|
|
def get(self, context: RequestContext):
|
|
"""Read policy for an admitted workspace administrator when Builder is enabled."""
|
|
if not dify_config.DIFY_BUILDER_ENABLED:
|
|
return {"code": "feature_unavailable"}, 403
|
|
actor = _actor(context)
|
|
service = build_cognition_policy_service()
|
|
try:
|
|
result = policy_projection(service.availability(actor, admin=True))
|
|
except CognitionPolicyDeniedError as error:
|
|
_raise_policy_error(error)
|
|
return dump_response(DifyBuilderPolicyResponse, result), 200
|
|
|
|
@error_responses(BuilderPolicyConflictError)
|
|
@console_ns.expect(console_ns.models[DifyBuilderPolicyPayload.__name__])
|
|
@console_ns.response(200, "Success", console_ns.models[DifyBuilderPolicyResponse.__name__])
|
|
@console_ns.response(
|
|
403, "App Builder is disabled", console_ns.models[DifyBuilderFeatureUnavailableResponse.__name__]
|
|
)
|
|
@console_account_admission()
|
|
def put(self, context: RequestContext):
|
|
"""Validate and save policy for an admitted workspace administrator when Builder is enabled."""
|
|
if not dify_config.DIFY_BUILDER_ENABLED:
|
|
return {"code": "feature_unavailable"}, 403
|
|
actor = _actor(context)
|
|
try:
|
|
payload = DifyBuilderPolicyPayload.model_validate(request.get_json(silent=True))
|
|
service = build_cognition_policy_service()
|
|
result = policy_projection(
|
|
service.put_status(actor, payload.policy(), expected_revision=payload.expected_revision)
|
|
)
|
|
except (ValidationError, ValueError) as error:
|
|
raise BadRequest("Invalid Workspace Builder policy.") from error
|
|
except CognitionPolicyDeniedError as error:
|
|
_raise_policy_error(error)
|
|
return dump_response(DifyBuilderPolicyResponse, result), 200
|
|
|
|
|
|
@console_ns.route("/apps/<uuid:app_id>/dify-builder/availability")
|
|
class DifyBuilderAvailabilityApi(Resource):
|
|
@console_ns.response(200, "Success", console_ns.models[DifyBuilderAvailabilityResponse.__name__])
|
|
@console_ns.response(
|
|
403, "App Builder is disabled", console_ns.models[DifyBuilderFeatureUnavailableResponse.__name__]
|
|
)
|
|
@console_account_admission()
|
|
def get(self, context: RequestContext, app_id):
|
|
"""Inspect model readiness for an admitted app editor when Builder is enabled."""
|
|
if not dify_config.DIFY_BUILDER_ENABLED:
|
|
return {"code": "feature_unavailable"}, 403
|
|
actor = _actor(context)
|
|
from core.dify_builder.errors import NotFoundError
|
|
|
|
try:
|
|
_authorize_app(actor, str(app_id), AppAccess.EDIT)
|
|
result = policy_projection(build_cognition_policy_service().availability(actor))
|
|
except NotFoundError as error:
|
|
raise NotFound() from error
|
|
except CognitionPolicyDeniedError as error:
|
|
_raise_policy_error(error)
|
|
return dump_response(DifyBuilderAvailabilityResponse, result), 200
|