smbpndk_cli/project/
mod.rs1pub 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 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 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
191fn show_projects(projects: Vec<Project>) {
194 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}