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