smbpndk_cli/project/
mod.rs

1pub mod cli;
2
3use self::cli::Commands;
4use anyhow::{anyhow, Result};
5use console::style;
6use dialoguer::{theme::ColorfulTheme, Input};
7use log::debug;
8use smbpndk_model::{CommandResult, Config, Project, ProjectCreate};
9use smbpndk_networking_project::{create_project, delete_project, get_all, get_project};
10use spinners::Spinner;
11use std::{fs::OpenOptions, io::Write};
12
13pub async fn process_project(commands: Commands) -> Result<CommandResult> {
14    match commands {
15        Commands::New {} => {
16            let project_name = Input::<String>::with_theme(&ColorfulTheme::default())
17                .with_prompt("Project name")
18                .interact()
19                .unwrap();
20            let description = Input::<String>::with_theme(&ColorfulTheme::default())
21                .with_prompt("Description")
22                .interact()
23                .unwrap();
24
25            let mut spinner = Spinner::new(
26                spinners::Spinners::SimpleDotsScrolling,
27                style("Creating a project...").green().bold().to_string(),
28            );
29
30            match create_project(ProjectCreate {
31                name: project_name.clone(),
32                description: description.clone(),
33            })
34            .await
35            {
36                Ok(_) => {
37                    spinner.stop_and_persist("✅", "Done.".to_owned());
38                    Ok(CommandResult {
39                        spinner: Spinner::new(
40                            spinners::Spinners::SimpleDotsScrolling,
41                            style("Loading...").green().bold().to_string(),
42                        ),
43                        symbol: "✅".to_owned(),
44                        msg: format!("{project_name} has been created."),
45                    })
46                }
47                Err(e) => {
48                    println!("Error: {e:#?}");
49                    Ok(CommandResult {
50                        spinner,
51                        symbol: "😩".to_owned(),
52                        msg: format!("Failed to create a project {project_name}."),
53                    })
54                }
55            }
56        }
57        Commands::List {} => {
58            let mut spinner = Spinner::new(
59                spinners::Spinners::SimpleDotsScrolling,
60                style("Loading...").green().bold().to_string(),
61            );
62
63            // Get all
64            match get_all().await {
65                Ok(projects) => {
66                    spinner.stop_and_persist("✅", "Loaded.".to_owned());
67                    let msg = if projects.is_empty() {
68                        "No projects found.".to_owned()
69                    } else {
70                        "Showing all projects.".to_owned()
71                    };
72                    show_projects(projects);
73                    Ok(CommandResult {
74                        spinner: Spinner::new(
75                            spinners::Spinners::SimpleDotsScrolling,
76                            style("Loading...").green().bold().to_string(),
77                        ),
78                        symbol: "✅".to_owned(),
79                        msg,
80                    })
81                }
82                Err(e) => {
83                    println!("Error: {e:#?}");
84                    Ok(CommandResult {
85                        spinner,
86                        symbol: "😩".to_owned(),
87                        msg: "Failed to get all projects.".to_owned(),
88                    })
89                }
90            }
91        }
92        Commands::Show { id } => {
93            let mut spinner = Spinner::new(
94                spinners::Spinners::SimpleDotsScrolling,
95                style("Loading...").green().bold().to_string(),
96            );
97            // Get Detail
98            match get_project(id).await {
99                Ok(project) => {
100                    spinner.stop_and_persist("✅", "Loaded.".to_owned());
101                    let message = format!("Showing project {}.", &project.name);
102                    show_projects(vec![project]);
103                    Ok(CommandResult {
104                        spinner: Spinner::new(
105                            spinners::Spinners::SimpleDotsScrolling,
106                            style("Loading...").green().bold().to_string(),
107                        ),
108                        symbol: "✅".to_owned(),
109                        msg: message,
110                    })
111                }
112                Err(e) => {
113                    spinner.stop_and_persist("😩", "Failed.".to_string());
114                    Err(anyhow!("{e}"))
115                }
116            }
117        }
118        Commands::Delete { id } => {
119            let confirmation = Input::<String>::with_theme(&ColorfulTheme::default())
120                .with_prompt("Are you sure? (y/n)")
121                .interact()
122                .unwrap();
123
124            let mut spinner = Spinner::new(
125                spinners::Spinners::SimpleDotsScrolling,
126                style("Deleting project...").green().bold().to_string(),
127            );
128
129            if confirmation != "y" {
130                return Ok(CommandResult {
131                    spinner,
132                    symbol: "✅".to_owned(),
133                    msg: "Cancelled.".to_string(),
134                });
135            }
136            match delete_project(id).await {
137                Ok(_) => {
138                    spinner.stop_and_persist("✅", "Done.".to_string());
139                    Ok(CommandResult {
140                        spinner: Spinner::new(
141                            spinners::Spinners::SimpleDotsScrolling,
142                            style("Loading...").green().bold().to_string(),
143                        ),
144                        symbol: "✅".to_owned(),
145                        msg: "Project has been deleted.".to_string(),
146                    })
147                }
148                Err(e) => {
149                    spinner.stop_and_persist("😩", "Failed.".to_string());
150                    Err(anyhow!("{e}"))
151                }
152            }
153        }
154        Commands::Use { id } => {
155            let project = get_project(id).await?;
156
157            let config = Config {
158                current_project: Some(project),
159                current_auth_app: None,
160            };
161
162            let spinner = Spinner::new(
163                spinners::Spinners::SimpleDotsScrolling,
164                style("Loading...").green().bold().to_string(),
165            );
166            match home::home_dir() {
167                Some(path) => {
168                    debug!("{}", path.to_str().unwrap());
169                    let mut file = OpenOptions::new()
170                        .create(true)
171                        .write(true)
172                        .open([path.to_str().unwrap(), "/.smb/config.json"].join(""))?;
173                    let json = serde_json::to_string(&config)?;
174                    file.write_all(json.as_bytes())?;
175
176                    Ok(CommandResult {
177                        spinner,
178                        symbol: "✅".to_owned(),
179                        msg: "Use project successful.".to_string(),
180                    })
181                }
182                None => {
183                    let error = anyhow!("Failed to get home directory.");
184                    Err(error)
185                }
186            }
187        }
188    }
189}
190
191// Private functions
192
193fn show_projects(projects: Vec<Project>) {
194    // println!("Projects: {projects:#?}");
195    if projects.is_empty() {
196        return;
197    }
198    println!(
199        "{0: <5} | {1: <20} | {2: <30} | {3: <20} | {4: <20}",
200        "ID", "Name", "Description", "Created at", "Updated at"
201    );
202    for project in projects {
203        println!(
204            "{0: <5} | {1: <20} | {2: <30} | {3: <20} | {4: <20}",
205            project.id,
206            project.name,
207            project.description,
208            project.created_at.date_naive(),
209            project.updated_at.date_naive(),
210        );
211    }
212}