Skip to main content

systemprompt_cli/commands/core/content/files/
link.rs

1//! `core content files link` command attaching a file to content.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use anyhow::Result;
7use clap::{Args, ValueEnum};
8use systemprompt_database::DbPool;
9use systemprompt_files::{FileRepository, FileRole};
10use systemprompt_identifiers::{ContentId, FileId};
11use systemprompt_runtime::AppContext;
12
13use crate::CliConfig;
14use crate::commands::core::files::types::ContentLinkOutput;
15use crate::shared::CommandOutput;
16
17#[derive(Debug, Clone, Copy, ValueEnum)]
18pub enum FileRoleArg {
19    Featured,
20    Attachment,
21    Inline,
22    OgImage,
23    Thumbnail,
24}
25
26impl From<FileRoleArg> for FileRole {
27    fn from(role: FileRoleArg) -> Self {
28        match role {
29            FileRoleArg::Featured => Self::Featured,
30            FileRoleArg::Attachment => Self::Attachment,
31            FileRoleArg::Inline => Self::Inline,
32            FileRoleArg::OgImage => Self::OgImage,
33            FileRoleArg::Thumbnail => Self::Thumbnail,
34        }
35    }
36}
37
38#[derive(Debug, Clone, Args)]
39pub struct LinkArgs {
40    #[arg(value_name = "FILE_ID", help = "File ID")]
41    pub file: String,
42
43    #[arg(long, help = "Content ID")]
44    pub content: String,
45
46    #[arg(long, value_enum, help = "File role")]
47    pub role: FileRoleArg,
48
49    #[arg(long, default_value = "0", help = "Display order")]
50    pub order: i32,
51}
52
53pub(super) async fn execute(args: LinkArgs, config: &CliConfig) -> Result<CommandOutput> {
54    let ctx = AppContext::new().await?;
55    execute_with_pool(args, ctx.db_pool(), config).await
56}
57
58pub async fn execute_with_pool(
59    args: LinkArgs,
60    pool: &DbPool,
61    _config: &CliConfig,
62) -> Result<CommandOutput> {
63    let service = FileRepository::new(pool)?;
64
65    let file_id = FileId::new(args.file.clone());
66    let content_id = ContentId::new(args.content.clone());
67    let role: FileRole = args.role.into();
68
69    service
70        .link_to_content(&content_id, &file_id, role, args.order)
71        .await?;
72
73    let output = ContentLinkOutput {
74        file_id,
75        content_id,
76        role: role.as_str().to_owned(),
77        message: "File linked to content successfully".to_owned(),
78    };
79
80    Ok(CommandOutput::card_value("File Linked", &output))
81}