mirror of
https://github.com/langgenius/dify.git
synced 2026-02-24 18:05:11 +00:00
feat: add Creators Platform helper for DSL upload and OAuth redirect (Vibe Kanban) (#32232)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -627,6 +627,11 @@ INNER_API_KEY_FOR_PLUGIN=QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y
|
||||
MARKETPLACE_ENABLED=true
|
||||
MARKETPLACE_API_URL=https://marketplace.dify.ai
|
||||
|
||||
# Creators Platform configuration
|
||||
CREATORS_PLATFORM_FEATURES_ENABLED=true
|
||||
CREATORS_PLATFORM_API_URL=https://creators.dify.ai
|
||||
CREATORS_PLATFORM_OAUTH_CLIENT_ID=
|
||||
|
||||
# Endpoint configuration
|
||||
ENDPOINT_URL_TEMPLATE=http://localhost:5002/e/{hook_id}
|
||||
|
||||
|
||||
@@ -293,6 +293,27 @@ class MarketplaceConfig(BaseSettings):
|
||||
)
|
||||
|
||||
|
||||
class CreatorsPlatformConfig(BaseSettings):
|
||||
"""
|
||||
Configuration for creators platform
|
||||
"""
|
||||
|
||||
CREATORS_PLATFORM_FEATURES_ENABLED: bool = Field(
|
||||
description="Enable or disable creators platform features",
|
||||
default=True,
|
||||
)
|
||||
|
||||
CREATORS_PLATFORM_API_URL: HttpUrl = Field(
|
||||
description="Creators Platform API URL",
|
||||
default=HttpUrl("https://creators.dify.ai"),
|
||||
)
|
||||
|
||||
CREATORS_PLATFORM_OAUTH_CLIENT_ID: str = Field(
|
||||
description="OAuth client_id for the Creators Platform app registered in Dify",
|
||||
default="",
|
||||
)
|
||||
|
||||
|
||||
class EndpointConfig(BaseSettings):
|
||||
"""
|
||||
Configuration for various application endpoints and URLs
|
||||
@@ -1396,6 +1417,7 @@ class FeatureConfig(
|
||||
PluginConfig,
|
||||
CliApiConfig,
|
||||
MarketplaceConfig,
|
||||
CreatorsPlatformConfig,
|
||||
DataSetConfig,
|
||||
EndpointConfig,
|
||||
FileAccessConfig,
|
||||
|
||||
@@ -736,6 +736,46 @@ class AppExportBundleApi(Resource):
|
||||
return result.model_dump(mode="json")
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/publish-to-creators-platform")
|
||||
class AppPublishToCreatorsPlatformApi(Resource):
|
||||
@get_app_model
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@edit_permission_required
|
||||
def post(self, app_model):
|
||||
"""Bundle the app DSL and upload to Creators Platform, returning a redirect URL."""
|
||||
import httpx
|
||||
|
||||
from configs import dify_config
|
||||
from core.helper.creators import get_redirect_url, upload_dsl
|
||||
from services.app_bundle_service import AppBundleService
|
||||
|
||||
if not dify_config.CREATORS_PLATFORM_FEATURES_ENABLED:
|
||||
return {"message": "Creators Platform is not enabled"}, 403
|
||||
|
||||
current_user, _ = current_account_with_tenant()
|
||||
|
||||
# 1. Export the app bundle (DSL + assets) to a temporary zip
|
||||
bundle_result = AppBundleService.export_bundle(
|
||||
app_model=app_model,
|
||||
account_id=str(current_user.id),
|
||||
include_secret=False,
|
||||
)
|
||||
|
||||
# 2. Download the zip from the temporary URL
|
||||
download_response = httpx.get(bundle_result.download_url, timeout=60, follow_redirects=True)
|
||||
download_response.raise_for_status()
|
||||
|
||||
# 3. Upload to Creators Platform
|
||||
claim_code = upload_dsl(download_response.content, filename=bundle_result.filename)
|
||||
|
||||
# 4. Generate redirect URL (with optional OAuth code)
|
||||
redirect_url = get_redirect_url(str(current_user.id), claim_code)
|
||||
|
||||
return {"redirect_url": redirect_url}
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/name")
|
||||
class AppNameApi(Resource):
|
||||
@console_ns.doc("check_app_name")
|
||||
|
||||
75
api/core/helper/creators.py
Normal file
75
api/core/helper/creators.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
Helper module for Creators Platform integration.
|
||||
|
||||
Provides functionality to upload DSL files to the Creators Platform
|
||||
and generate redirect URLs with OAuth authorization codes.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from urllib.parse import urlencode
|
||||
|
||||
import httpx
|
||||
from yarl import URL
|
||||
|
||||
from configs import dify_config
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
creators_platform_api_url = URL(str(dify_config.CREATORS_PLATFORM_API_URL))
|
||||
|
||||
|
||||
def upload_dsl(dsl_file_bytes: bytes, filename: str = "template.yaml") -> str:
|
||||
"""Upload a DSL file to the Creators Platform anonymous upload endpoint.
|
||||
|
||||
Args:
|
||||
dsl_file_bytes: Raw bytes of the DSL file (YAML or ZIP).
|
||||
filename: Original filename for the upload.
|
||||
|
||||
Returns:
|
||||
The claim_code string used to retrieve the DSL later.
|
||||
|
||||
Raises:
|
||||
httpx.HTTPStatusError: If the upload request fails.
|
||||
ValueError: If the response does not contain a valid claim_code.
|
||||
"""
|
||||
url = str(creators_platform_api_url / "api/v1/templates/anonymous-upload")
|
||||
response = httpx.post(url, files={"file": (filename, dsl_file_bytes)}, timeout=30)
|
||||
response.raise_for_status()
|
||||
|
||||
data = response.json()
|
||||
claim_code = data.get("data", {}).get("claim_code")
|
||||
if not claim_code:
|
||||
raise ValueError("Creators Platform did not return a valid claim_code")
|
||||
|
||||
return claim_code
|
||||
|
||||
|
||||
def get_redirect_url(user_account_id: str, claim_code: str) -> str:
|
||||
"""Generate the redirect URL to the Creators Platform frontend.
|
||||
|
||||
Redirects to the Creators Platform root page with the dsl_claim_code.
|
||||
If CREATORS_PLATFORM_OAUTH_CLIENT_ID is configured (Dify Cloud),
|
||||
also signs an OAuth authorization code so the frontend can
|
||||
automatically authenticate the user via the OAuth callback.
|
||||
|
||||
For self-hosted Dify without OAuth client_id configured, only the
|
||||
dsl_claim_code is passed and the user must log in manually.
|
||||
|
||||
Args:
|
||||
user_account_id: The Dify user account ID.
|
||||
claim_code: The claim_code obtained from upload_dsl().
|
||||
|
||||
Returns:
|
||||
The full redirect URL string.
|
||||
"""
|
||||
base_url = str(dify_config.CREATORS_PLATFORM_API_URL).rstrip("/")
|
||||
params: dict[str, str] = {"dsl_claim_code": claim_code}
|
||||
|
||||
client_id = str(dify_config.CREATORS_PLATFORM_OAUTH_CLIENT_ID or "")
|
||||
if client_id:
|
||||
from services.oauth_server import OAuthServerService
|
||||
|
||||
oauth_code = OAuthServerService.sign_oauth_authorization_code(client_id, user_account_id)
|
||||
params["oauth_code"] = oauth_code
|
||||
|
||||
return f"{base_url}?{urlencode(params)}"
|
||||
@@ -177,6 +177,7 @@ class SystemFeatureModel(BaseModel):
|
||||
trial_models: list[str] = []
|
||||
enable_trial_app: bool = False
|
||||
enable_explore_banner: bool = False
|
||||
enable_creators_platform: bool = False
|
||||
|
||||
|
||||
class FeatureService:
|
||||
@@ -238,6 +239,9 @@ class FeatureService:
|
||||
if dify_config.MARKETPLACE_ENABLED:
|
||||
system_features.enable_marketplace = True
|
||||
|
||||
if dify_config.CREATORS_PLATFORM_FEATURES_ENABLED:
|
||||
system_features.enable_creators_platform = True
|
||||
|
||||
return system_features
|
||||
|
||||
@classmethod
|
||||
|
||||
Reference in New Issue
Block a user