systemprompt_cli/commands/core/content/
delete.rs1use super::types::DeleteOutput;
2use crate::cli_settings::CliConfig;
3use crate::interactive::require_confirmation;
4use crate::shared::CommandOutput;
5use anyhow::{Result, anyhow};
6use clap::Args;
7use systemprompt_content::ContentRepository;
8use systemprompt_identifiers::{ContentId, LocaleCode, SourceId};
9use systemprompt_logging::CliService;
10use systemprompt_runtime::AppContext;
11
12#[derive(Debug, Args)]
13pub struct DeleteArgs {
14 #[arg(help = "Content ID or slug")]
15 pub identifier: String,
16
17 #[arg(long, help = "Source ID (required when using slug)")]
18 pub source: Option<String>,
19
20 #[arg(short = 'y', long, help = "Skip confirmation")]
21 pub yes: bool,
22
23 #[arg(long, help = "Preview deletion without executing")]
24 pub dry_run: bool,
25}
26
27pub async fn execute(args: DeleteArgs, config: &CliConfig) -> Result<CommandOutput> {
28 let ctx = AppContext::new().await?;
29 let repo = ContentRepository::new(ctx.db_pool())?;
30
31 let content = if args.identifier.starts_with("content_")
32 || args.identifier.contains('-') && args.identifier.len() > 30
33 {
34 let id = ContentId::new(args.identifier.clone());
35 repo.get_by_id(&id)
36 .await?
37 .ok_or_else(|| anyhow!("Content not found: {}", args.identifier))?
38 } else {
39 let source_id = args
40 .source
41 .as_ref()
42 .ok_or_else(|| anyhow!("Source ID required when using slug (use --source)"))?;
43 let source = SourceId::new(source_id.clone());
44 repo.get_by_source_and_slug(&source, &args.identifier, &LocaleCode::new("en"))
45 .await?
46 .ok_or_else(|| {
47 anyhow!(
48 "Content not found: {} in source {}",
49 args.identifier,
50 source_id
51 )
52 })?
53 };
54
55 if args.dry_run {
56 let output = DeleteOutput {
57 deleted: false,
58 content_id: content.id.clone(),
59 message: Some(format!(
60 "[DRY-RUN] Would delete content '{}' ({})",
61 content.title, content.id
62 )),
63 };
64 return Ok(CommandOutput::card_value(
65 "Content Delete (Dry Run)",
66 &output,
67 ));
68 }
69
70 if config.is_interactive() && !args.yes {
71 CliService::warning(&format!(
72 "This will permanently delete content: {}",
73 args.identifier
74 ));
75 }
76
77 require_confirmation("Are you sure you want to continue?", args.yes, config)?;
78
79 repo.delete(&content.id).await?;
80
81 let output = DeleteOutput {
82 deleted: true,
83 content_id: content.id.clone(),
84 message: None,
85 };
86
87 Ok(CommandOutput::card_value("Content Deleted", &output))
88}