smbcloud_cli/project/
crud_read.rs

1use std::{fs::OpenOptions, io::Write};
2
3use crate::{
4    cli::CommandResult,
5    ui::{fail_message, fail_symbol, succeed_message, succeed_symbol},
6};
7use anyhow::{anyhow, Result};
8use log::debug;
9use smbcloud_model::project::{Config, Project};
10use smbcloud_networking::{environment::Environment, get_smb_token};
11use smbcloud_networking_project::crud_project_read::{get_project, get_projects};
12use spinners::Spinner;
13use tabled::{Table, Tabled};
14
15#[derive(Tabled)]
16struct ProjectRow {
17    #[tabled(rename = "ID")]
18    id: i32,
19    #[tabled(rename = "Name")]
20    name: String,
21    #[tabled(rename = "Repository")]
22    repository: String,
23    #[tabled(rename = "Description")]
24    description: String,
25}
26
27#[derive(Tabled)]
28struct ProjectDetailRow {
29    #[tabled(rename = "ID")]
30    id: i32,
31    #[tabled(rename = "Name")]
32    name: String,
33    #[tabled(rename = "Repository")]
34    repository: String,
35    #[tabled(rename = "Description")]
36    description: String,
37    #[tabled(rename = "Created at")]
38    created_at: String,
39    #[tabled(rename = "Updated at")]
40    updated_at: String,
41}
42
43pub async fn process_project_list(env: Environment) -> Result<CommandResult> {
44    let mut spinner = Spinner::new(
45        spinners::Spinners::SimpleDotsScrolling,
46        succeed_message("Loading"),
47    );
48    let token = get_smb_token(env).await?;
49    match get_projects(env, token).await {
50        Ok(projects) => {
51            spinner.stop_and_persist(&succeed_symbol(), succeed_message("Loaded."));
52            let msg = if projects.is_empty() {
53                succeed_message("No projects found.")
54            } else {
55                succeed_message("Showing all projects.")
56            };
57            show_projects(projects);
58            Ok(CommandResult {
59                spinner: Spinner::new(
60                    spinners::Spinners::SimpleDotsScrolling,
61                    succeed_message("Loading"),
62                ),
63                symbol: succeed_symbol(),
64                msg,
65            })
66        }
67        Err(e) => {
68            println!("Error: {e:#?}");
69            Ok(CommandResult {
70                spinner,
71                symbol: fail_symbol(),
72                msg: fail_message("Failed to get all projects."),
73            })
74        }
75    }
76}
77
78pub async fn process_project_show(env: Environment, id: String) -> Result<CommandResult> {
79    let mut spinner = Spinner::new(
80        spinners::Spinners::SimpleDotsScrolling,
81        succeed_message("Loading"),
82    );
83    let access_token = get_smb_token(env).await?;
84    match get_project(env, access_token, id).await {
85        Ok(project) => {
86            spinner.stop_and_persist(&succeed_symbol(), succeed_message("Loaded."));
87            let message = succeed_message(&format!("Showing project {}.", &project.name));
88            show_project_detail(&project);
89            Ok(CommandResult {
90                spinner: Spinner::new(
91                    spinners::Spinners::SimpleDotsScrolling,
92                    succeed_message("Loading"),
93                ),
94                symbol: succeed_symbol(),
95                msg: message,
96            })
97        }
98        Err(e) => {
99            spinner.stop_and_persist(&fail_symbol(), fail_message("Failed."));
100            Err(anyhow!("{e}"))
101        }
102    }
103}
104
105pub(crate) fn show_projects(projects: Vec<Project>) {
106    if projects.is_empty() {
107        return;
108    }
109    let rows: Vec<ProjectRow> = projects
110        .into_iter()
111        .map(|p| ProjectRow {
112            id: p.id,
113            name: p.name,
114            repository: p.repository,
115            description: p.description.unwrap_or("-".to_owned()),
116        })
117        .collect();
118    let table = Table::new(rows);
119    println!("{table}");
120}
121
122pub(crate) fn show_project_detail(project: &Project) {
123    let row = ProjectDetailRow {
124        id: project.id,
125        name: project.name.clone(),
126        repository: project.repository.clone(),
127        description: project.description.clone().unwrap_or("-".to_owned()),
128        created_at: project.created_at.date_naive().to_string(),
129        updated_at: project.updated_at.date_naive().to_string(),
130    };
131    let table = Table::new(vec![row]);
132    println!("{table}");
133}
134
135pub(crate) async fn process_project_use(env: Environment, id: String) -> Result<CommandResult> {
136    let access_token = get_smb_token(env).await?;
137    let project = get_project(env, access_token, id).await?;
138
139    let config = Config {
140        current_project: Some(project),
141        current_auth_app: None,
142    };
143
144    let spinner = Spinner::new(
145        spinners::Spinners::SimpleDotsScrolling,
146        succeed_message("Loading"),
147    );
148    match home::home_dir() {
149        Some(path) => {
150            debug!("{}", path.to_str().unwrap());
151            let mut file = OpenOptions::new()
152                .create(true)
153                .truncate(true)
154                .write(true)
155                .open([path.to_str().unwrap(), "/.smb/config.json"].join(""))?;
156            let json = serde_json::to_string(&config)?;
157            file.write_all(json.as_bytes())?;
158
159            Ok(CommandResult {
160                spinner,
161                symbol: succeed_symbol(),
162                msg: succeed_message("Use project successful."),
163            })
164        }
165        None => {
166            let error = anyhow!("Failed to get home directory.");
167            Err(error)
168        }
169    }
170}