@smbcloud / cli / commits / 9dd0f90

Project CRUD

Seto Elkahfi committed Sep 11, 2023 at 11:03 UTC 9dd0f902f002355e1f93cc11b059d583d4333ada
3 files changed +94 -45
smbpndk-cli/src/project/mod.rs
+89 -40
@@ -5,7 +5,7 @@ use anyhow::{anyhow, Result};
5 use console::style;
6 use dialoguer::{theme::ColorfulTheme, Input};
7 use log::debug;
8 -use smbpndk_model::{CommandResult, Config, ProjectCreate};
8 +use smbpndk_model::{CommandResult, Config, Project, ProjectCreate};
9 use smbpndk_networking_project::{create_project, delete_project, get_all, get_project};
10 use spinners::Spinner;
11 use std::{fs::OpenOptions, io::Write};
@@ -22,9 +22,9 @@ pub async fn process_project(commands: Commands) -> Result<CommandResult> {
22 .interact()
23 .unwrap();
24
25 - let spinner = Spinner::new(
25 + let mut spinner = Spinner::new(
26 spinners::Spinners::SimpleDotsScrolling,
27 - style("Creating project...").green().bold().to_string(),
27 + style("Creating a project...").green().bold().to_string(),
28 );
29
30 match create_project(ProjectCreate {
@@ -33,11 +33,17 @@ pub async fn process_project(commands: Commands) -> Result<CommandResult> {
33 })
34 .await
35 {
36 - Ok(_) => Ok(CommandResult {
37 - spinner,
38 - symbol: "✅".to_owned(),
39 - msg: format!("Creating a project {project_name}."),
40 - }),
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 {
@@ -49,7 +55,7 @@ pub async fn process_project(commands: Commands) -> Result<CommandResult> {
55 }
56 }
57 Commands::List {} => {
52 - let spinner = Spinner::new(
58 + let mut spinner = Spinner::new(
59 spinners::Spinners::SimpleDotsScrolling,
60 style("Loading...").green().bold().to_string(),
61 );
@@ -57,24 +63,20 @@ pub async fn process_project(commands: Commands) -> Result<CommandResult> {
63 // Get all
64 match get_all().await {
65 Ok(projects) => {
60 - println!("Projects: {projects:#?}");
61 - println!(
62 - "{0: <5} | {1: <20} | {2: <10} | {3: <10}",
63 - "ID", "Name", "Created at", "Updated at"
64 - );
65 - for project in projects {
66 - println!(
67 - "{0: <5} | {1: <20} | {2: <30} | {3: <30}",
68 - project.id,
69 - project.name,
70 - project.created_at.date_naive(),
71 - project.updated_at.date_naive()
72 - );
73 - }
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 {
75 - spinner,
74 + spinner: Spinner::new(
75 + spinners::Spinners::SimpleDotsScrolling,
76 + style("Loading...").green().bold().to_string(),
77 + ),
78 symbol: "✅".to_owned(),
77 - msg: "Showing all projects.".to_owned(),
79 + msg,
80 })
81 }
82 Err(e) => {
@@ -88,42 +90,66 @@ pub async fn process_project(commands: Commands) -> Result<CommandResult> {
90 }
91 }
92 Commands::Show { id } => {
91 - let spinner = Spinner::new(
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 {
97 - Ok(_) => Ok(CommandResult {
98 - spinner,
99 - symbol: "✅".to_owned(),
100 - msg: "Showing all projects.".to_owned(),
101 - }),
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 println!("Error: {e:#?}");
114 Ok(CommandResult {
115 spinner,
116 symbol: "😩".to_owned(),
107 - msg: "Failed to get all projects.".to_owned(),
117 + msg: "Failed to get project.".to_owned(),
118 })
119 }
120 }
121 }
122 Commands::Delete { id } => {
113 - let spinner = Spinner::new(
123 + let confirmation = Input::<String>::with_theme(&ColorfulTheme::default())
124 + .with_prompt("Are you sure? (y/n)")
125 + .interact()
126 + .unwrap();
127 +
128 + let mut spinner = Spinner::new(
129 spinners::Spinners::SimpleDotsScrolling,
130 style("Deleting project...").green().bold().to_string(),
131 );
117 - match delete_project(id).await {
118 - Ok(_) => Ok(CommandResult {
132 +
133 + if confirmation != "y" {
134 + return Ok(CommandResult {
135 spinner,
136 symbol: "✅".to_owned(),
121 - msg: "Project deleted.".to_string(),
122 - }),
123 - Err(e) => {
124 - let error = anyhow!("Failed to delete project. {e}");
125 - Err(error)
137 + msg: "Cancelled.".to_string(),
138 + });
139 + }
140 + match delete_project(id).await {
141 + Ok(_) => {
142 + spinner.stop_and_persist("✅", "Done.".to_string());
143 + Ok(CommandResult {
144 + spinner: Spinner::new(
145 + spinners::Spinners::SimpleDotsScrolling,
146 + style("Loading...").green().bold().to_string(),
147 + ),
148 + symbol: "✅".to_owned(),
149 + msg: "Project has been deleted.".to_string(),
150 + })
151 }
152 + Err(e) => Err(anyhow!("{e}")),
153 }
154 }
155 Commands::Use { id } => {
@@ -162,3 +188,26 @@ pub async fn process_project(commands: Commands) -> Result<CommandResult> {
188 }
189 }
190 }
191 +
192 +// Private functions
193 +
194 +fn show_projects(projects: Vec<Project>) {
195 + // println!("Projects: {projects:#?}");
196 + if projects.len() == 0 {
197 + return;
198 + }
199 + println!(
200 + "{0: <5} | {1: <20} | {2: <30} | {3: <20} | {4: <20}",
201 + "ID", "Name", "Description", "Created at", "Updated at"
202 + );
203 + for project in projects {
204 + println!(
205 + "{0: <5} | {1: <20} | {2: <30} | {3: <20} | {4: <20}",
206 + project.id,
207 + project.name,
208 + project.description,
209 + project.created_at.date_naive(),
210 + project.updated_at.date_naive(),
211 + );
212 + }
213 +}
smbpndk-model/src/lib.rs
+1
@@ -73,6 +73,7 @@ pub struct Config {
73 pub struct Project {
74 pub id: i32,
75 pub name: String,
76 + pub description: String,
77 #[serde(with = "ar_date_format")]
78 pub created_at: DateTime<Utc>,
79 #[serde(with = "ar_date_format")]
smbpndk-networking-project/src/lib.rs
+4 -5
@@ -1,7 +1,6 @@
1 use anyhow::{anyhow, Result};
2 use log::debug;
3 use reqwest::Client;
4 -
4 use smbpndk_model::{Project, ProjectCreate};
5 use smbpndk_networking::{get_token, smb_base_url_builder};
6
@@ -41,7 +40,7 @@ pub async fn create_project(project: ProjectCreate) -> Result<Project> {
40 match response.status() {
41 reqwest::StatusCode::CREATED => {
42 let project: Project = response.json().await?;
44 - println!("Project created: {project:#?}");
43 + // println!("Project created: {project:#?}");
44 Ok(project)
45 }
46 _ => Err(anyhow!("Failed to create a project.")),
@@ -53,7 +52,7 @@ pub async fn get_project(id: String) -> Result<Project> {
52 let token = get_token().await.unwrap();
53
54 let response = Client::new()
56 - .get(build_project_url())
55 + .get(build_project_url_with_id(id))
56 .header("Authorization", token)
57 .send()
58 .await?;
@@ -73,7 +72,7 @@ pub async fn delete_project(id: String) -> Result<()> {
72 let token = get_token().await.unwrap();
73
74 let response = Client::new()
76 - .delete(build_delete_project_url(id))
75 + .delete(build_project_url_with_id(id))
76 .header("Authorization", token)
77 .send()
78 .await?;
@@ -95,7 +94,7 @@ fn build_project_url() -> String {
94 url_builder.build()
95 }
96
98 -fn build_delete_project_url(id: String) -> String {
97 +fn build_project_url_with_id(id: String) -> String {
98 let mut url_builder = smb_base_url_builder();
99 url_builder.add_route("v1/projects");
100 url_builder.add_route(id.as_str());