mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-25 13:45:03 +08:00
87190b7af3
Split the 1691-line deeplink.rs into a well-organized module directory: - mod.rs (120 lines): DeepLinkImportRequest struct and public exports - parser.rs (321 lines): URL parsing logic for all resource types - provider.rs (510 lines): Provider import and config merge logic - mcp.rs (191 lines): MCP server batch import - prompt.rs (86 lines): Prompt import - skill.rs (52 lines): Skill repository import - utils.rs (99 lines): Shared utilities (URL validation, Base64 decoding) - tests.rs (384 lines): All unit tests Benefits: - Max file size reduced from 1691 to 510 lines - Each resource type has its own import module - Shared utilities extracted for reuse - All 17 deeplink tests + 107 total tests passing
87 lines
2.8 KiB
Rust
87 lines
2.8 KiB
Rust
//! Prompt import from deep link
|
|
//!
|
|
//! Handles importing prompt configurations via ccswitch:// URLs.
|
|
|
|
use super::utils::decode_base64_param;
|
|
use super::DeepLinkImportRequest;
|
|
use crate::error::AppError;
|
|
use crate::prompt::Prompt;
|
|
use crate::services::PromptService;
|
|
use crate::store::AppState;
|
|
use crate::AppType;
|
|
use std::str::FromStr;
|
|
|
|
/// Import a prompt from deep link request
|
|
pub fn import_prompt_from_deeplink(
|
|
state: &AppState,
|
|
request: DeepLinkImportRequest,
|
|
) -> Result<String, AppError> {
|
|
// Verify this is a prompt request
|
|
if request.resource != "prompt" {
|
|
return Err(AppError::InvalidInput(format!(
|
|
"Expected prompt resource, got '{}'",
|
|
request.resource
|
|
)));
|
|
}
|
|
|
|
// Extract required fields
|
|
let app_str = request
|
|
.app
|
|
.as_ref()
|
|
.ok_or_else(|| AppError::InvalidInput("Missing 'app' field for prompt".to_string()))?;
|
|
|
|
let name = request
|
|
.name
|
|
.ok_or_else(|| AppError::InvalidInput("Missing 'name' field for prompt".to_string()))?;
|
|
|
|
// Parse app type
|
|
let app_type = AppType::from_str(app_str)
|
|
.map_err(|_| AppError::InvalidInput(format!("Invalid app type: {app_str}")))?;
|
|
|
|
// Decode content
|
|
let content_b64 = request
|
|
.content
|
|
.as_ref()
|
|
.ok_or_else(|| AppError::InvalidInput("Missing 'content' field for prompt".to_string()))?;
|
|
|
|
let content = decode_base64_param("content", content_b64)?;
|
|
let content = String::from_utf8(content)
|
|
.map_err(|e| AppError::InvalidInput(format!("Invalid UTF-8 in content: {e}")))?;
|
|
|
|
// Generate ID
|
|
let timestamp = chrono::Utc::now().timestamp_millis();
|
|
let sanitized_name = name
|
|
.chars()
|
|
.filter(|c| c.is_alphanumeric() || *c == '-' || *c == '_')
|
|
.collect::<String>()
|
|
.to_lowercase();
|
|
let id = format!("{sanitized_name}-{timestamp}");
|
|
|
|
// Check if we should enable this prompt
|
|
let should_enable = request.enabled.unwrap_or(false);
|
|
|
|
// Create Prompt (initially disabled)
|
|
let prompt = Prompt {
|
|
id: id.clone(),
|
|
name: name.clone(),
|
|
content,
|
|
description: request.description,
|
|
enabled: false, // Always start as disabled, will be enabled later if needed
|
|
created_at: Some(timestamp),
|
|
updated_at: Some(timestamp),
|
|
};
|
|
|
|
// Save using PromptService
|
|
PromptService::upsert_prompt(state, app_type.clone(), &id, prompt)?;
|
|
|
|
// If enabled flag is set, enable this prompt (which will disable others)
|
|
if should_enable {
|
|
PromptService::enable_prompt(state, app_type, &id)?;
|
|
log::info!("Successfully imported and enabled prompt '{name}' for {app_str}");
|
|
} else {
|
|
log::info!("Successfully imported prompt '{name}' for {app_str} (disabled)");
|
|
}
|
|
|
|
Ok(id)
|
|
}
|