15 files changed
+194
-159
Cargo.lock
+1
@@ -1683,6 +1683,7 @@ version = "0.3.8"
1683
dependencies = [
1684
"anyhow",
1685
"async-trait",
1686
+ "clap",
1687
"dirs 5.0.1",
1688
"home",
1689
"log",
smbcloud-cli/src/account/forgot/mod.rs
+10
-8
@@ -5,11 +5,13 @@ use dialoguer::{theme::ColorfulTheme, Input, Password};
5
use reqwest::{Client, StatusCode};
6
use serde::{Deserialize, Serialize};
7
use smbcloud_model::forgot::{Args, Email, Param, UserUpdatePassword};
8
-use smbcloud_networking::{constants::PATH_USERS_PASSWORD, smb_base_url_builder};
8
+use smbcloud_networking::{
9
+ constants::PATH_USERS_PASSWORD, environment::Environment, smb_base_url_builder,
10
+};
11
use smbcloud_utils::email_validation;
12
use spinners::Spinner;
13
12
-pub async fn process_forgot() -> Result<CommandResult> {
14
+pub async fn process_forgot(env: Environment) -> Result<CommandResult> {
15
println!("Provide your login credentials.");
16
let email = Input::<String>::with_theme(&ColorfulTheme::default())
17
.with_prompt("Email")
@@ -26,7 +28,7 @@ pub async fn process_forgot() -> Result<CommandResult> {
28
};
29
30
let response = Client::new()
29
- .post(build_smb_forgot_url())
31
+ .post(build_smb_forgot_url(env))
32
.json(¶ms)
33
.send()
34
.await?;
@@ -37,7 +39,7 @@ pub async fn process_forgot() -> Result<CommandResult> {
39
"✅",
40
"Check your email and input your code here.".to_owned(),
41
);
40
- input_code().await
42
+ input_code(env.clone()).await
43
}
44
_ => Ok(CommandResult {
45
spinner,
@@ -47,7 +49,7 @@ pub async fn process_forgot() -> Result<CommandResult> {
49
}
50
}
51
50
-async fn input_code() -> Result<CommandResult> {
52
+async fn input_code(env: Environment) -> Result<CommandResult> {
53
let security_code = Input::<String>::with_theme(&ColorfulTheme::default())
54
.with_prompt("Code")
55
.interact()
@@ -91,7 +93,7 @@ async fn input_code() -> Result<CommandResult> {
93
);
94
95
let response = Client::new()
94
- .put(build_smb_forgot_url())
96
+ .put(build_smb_forgot_url(env))
97
.json(¶ms)
98
.send()
99
.await?;
@@ -121,8 +123,8 @@ async fn input_code() -> Result<CommandResult> {
123
}
124
}
125
124
-fn build_smb_forgot_url() -> String {
125
- let mut url_builder = smb_base_url_builder();
126
+fn build_smb_forgot_url(env: Environment) -> String {
127
+ let mut url_builder = smb_base_url_builder(env);
128
url_builder.add_route(PATH_USERS_PASSWORD);
129
url_builder.build()
130
}
smbcloud-cli/src/account/lib.rs
+7
-6
@@ -8,6 +8,7 @@ use smbcloud_networking::{
8
constants::{
9
GH_OAUTH_CLIENT_ID, GH_OAUTH_REDIRECT_HOST, GH_OAUTH_REDIRECT_PORT, PATH_AUTHORIZE,
10
},
11
+ environment::Environment,
12
smb_base_url_builder,
13
};
14
use spinners::Spinner;
@@ -19,7 +20,7 @@ use std::{
20
};
21
use url_builder::URLBuilder;
22
22
-pub async fn authorize_github() -> Result<SmbAuthorization> {
23
+pub async fn authorize_github(env: &Environment) -> Result<SmbAuthorization> {
24
// Spin up a simple localhost server to listen for the GitHub OAuth callback
25
// setup_oauth_callback_server();
26
// Open the GitHub OAuth URL in the user's browser
@@ -57,7 +58,7 @@ pub async fn authorize_github() -> Result<SmbAuthorization> {
58
Ok(code) => {
59
debug!("Got code from channel: {:#?}", &code);
60
//Err(anyhow!("Failed to get code from channel."))
60
- process_connect_github(code).await
61
+ process_connect_github(env.clone(), code).await
62
}
63
Err(e) => {
64
let error = anyhow!("Failed to get code from channel: {e}");
@@ -140,9 +141,9 @@ fn handle_connection(mut stream: TcpStream, tx: Sender<String>) {
141
}
142
143
// Get access token
143
-pub async fn process_connect_github(code: String) -> Result<SmbAuthorization> {
144
+pub async fn process_connect_github(env: Environment, code: String) -> Result<SmbAuthorization> {
145
let response = Client::new()
145
- .post(build_authorize_smb_url())
146
+ .post(build_authorize_smb_url(env))
147
.body(format!("gh_code={}", code))
148
.header("Accept", "application/json")
149
.header("Content-Type", "application/x-www-form-urlencoded")
@@ -187,8 +188,8 @@ pub async fn process_connect_github(code: String) -> Result<SmbAuthorization> {
188
}
189
}
190
190
-fn build_authorize_smb_url() -> String {
191
- let mut url_builder = smb_base_url_builder();
191
+fn build_authorize_smb_url(env: Environment) -> String {
192
+ let mut url_builder = smb_base_url_builder(env);
193
url_builder.add_route(PATH_AUTHORIZE);
194
url_builder.build()
195
}
smbcloud-cli/src/account/login/process.rs
+53
-48
@@ -21,13 +21,14 @@ use smbcloud_networking::{
21
PATH_LINK_GITHUB_ACCOUNT, PATH_RESEND_CONFIRMATION, PATH_RESET_PASSWORD_INSTRUCTIONS,
22
PATH_USERS_PASSWORD, PATH_USERS_SIGN_IN, PATH_USERS_SIGN_OUT,
23
},
24
+ environment::Environment,
25
get_smb_token, smb_base_url_builder, smb_token_file_path,
26
};
27
use smbcloud_utils::email_validation;
28
use spinners::Spinner;
29
use std::fs::{self};
30
30
-pub async fn process_login() -> Result<CommandResult> {
31
+pub async fn process_login(env: Environment) -> Result<CommandResult> {
32
// Check if token file exists
33
if smb_token_file_path().is_some() {
34
return Ok(CommandResult {
@@ -55,12 +56,12 @@ pub async fn process_login() -> Result<CommandResult> {
56
};
57
58
match selection {
58
- SignupMethod::Email => login_with_email().await,
59
- SignupMethod::GitHub => login_with_github().await,
59
+ SignupMethod::Email => login_with_email(env).await,
60
+ SignupMethod::GitHub => login_with_github(env).await,
61
}
62
}
63
63
-pub async fn process_logout() -> Result<CommandResult> {
64
+pub async fn process_logout(env: Environment) -> Result<CommandResult> {
65
// Logout if user confirms
66
if let Some(token_path) = smb_token_file_path() {
67
let confirm = match Confirm::with_theme(&ColorfulTheme::default())
@@ -90,7 +91,7 @@ pub async fn process_logout() -> Result<CommandResult> {
91
);
92
93
// Call backend
93
- match do_process_logout().await {
94
+ match do_process_logout(env).await {
95
Ok(_) => {
96
spinner.stop_and_persist("✅", "Done.".to_owned());
97
fs::remove_file(token_path)?;
@@ -119,9 +120,9 @@ pub async fn process_logout() -> Result<CommandResult> {
120
121
// Private functions
122
122
-async fn login_with_github() -> Result<CommandResult> {
123
- match authorize_github().await {
124
- Ok(result) => process_authorization(result).await,
123
+async fn login_with_github(env: Environment) -> Result<CommandResult> {
124
+ match authorize_github(&env).await {
125
+ Ok(result) => process_authorization(env, result).await,
126
Err(err) => {
127
let error = anyhow!("Failed to authorize your GitHub account. {}", err);
128
Err(error)
@@ -129,22 +130,22 @@ async fn login_with_github() -> Result<CommandResult> {
130
}
131
}
132
132
-async fn process_authorization(auth: SmbAuthorization) -> Result<CommandResult> {
133
+async fn process_authorization(env: Environment, auth: SmbAuthorization) -> Result<CommandResult> {
134
// What to do if not logged in with GitHub?
135
// Check error_code first
136
if let Some(error_code) = auth.error_code {
137
debug!("{}", error_code);
138
match error_code {
139
ErrorCode::EmailNotFound => {
139
- return create_new_account(auth.user_email, auth.user_info).await
140
+ return create_new_account(env, auth.user_email, auth.user_info).await
141
}
141
- ErrorCode::EmailUnverified => return send_email_verification(auth.user).await,
142
+ ErrorCode::EmailUnverified => return send_email_verification(env, auth.user).await,
143
ErrorCode::PasswordNotSet => {
144
// Only for email and password login
145
let error = anyhow!("Password not set.");
146
return Err(error);
147
}
147
- ErrorCode::GithubNotLinked => return connect_github_account(auth).await,
148
+ ErrorCode::GithubNotLinked => return connect_github_account(env, auth).await,
149
}
150
}
151
@@ -168,6 +169,7 @@ async fn process_authorization(auth: SmbAuthorization) -> Result<CommandResult>
169
}
170
171
async fn create_new_account(
172
+ env: Environment,
173
user_email: Option<GithubEmail>,
174
user_info: Option<GithubInfo>,
175
) -> Result<CommandResult> {
@@ -206,13 +208,13 @@ async fn create_new_account(
208
},
209
};
210
209
- return do_signup(¶ms).await;
211
+ return do_signup(env, ¶ms).await;
212
}
213
214
Err(anyhow!("Shouldn't be here."))
215
}
216
215
-async fn send_email_verification(user: Option<User>) -> Result<CommandResult> {
217
+async fn send_email_verification(env: Environment, user: Option<User>) -> Result<CommandResult> {
218
// Return early if user is null
219
if let Some(user) = user {
220
let confirm = match Confirm::with_theme(&ColorfulTheme::default())
@@ -238,14 +240,14 @@ async fn send_email_verification(user: Option<User>) -> Result<CommandResult> {
240
msg: "Doing nothing.".to_owned(),
241
});
242
}
241
- resend_email_verification(user).await
243
+ resend_email_verification(env, user).await
244
} else {
245
let error = anyhow!("Failed to get user.");
246
Err(error)
247
}
248
}
249
248
-async fn resend_email_verification(user: User) -> Result<CommandResult> {
250
+async fn resend_email_verification(env: Environment, user: User) -> Result<CommandResult> {
251
let spinner = Spinner::new(
252
spinners::Spinners::SimpleDotsScrolling,
253
style("Sending verification email...")
@@ -255,7 +257,7 @@ async fn resend_email_verification(user: User) -> Result<CommandResult> {
257
);
258
259
let response = Client::new()
258
- .post(build_smb_resend_email_verification_url())
260
+ .post(build_smb_resend_email_verification_url(env))
261
.body(format!("id={}", user.id))
262
.header("Accept", "application/json")
263
.header("Content-Type", "application/x-www-form-urlencoded")
@@ -275,7 +277,7 @@ async fn resend_email_verification(user: User) -> Result<CommandResult> {
277
}
278
}
279
278
-async fn connect_github_account(auth: SmbAuthorization) -> Result<CommandResult> {
280
+async fn connect_github_account(env: Environment, auth: SmbAuthorization) -> Result<CommandResult> {
281
let confirm = match Confirm::with_theme(&ColorfulTheme::default())
282
.with_prompt("Do you want to link your GitHub account?")
283
.interact()
@@ -309,7 +311,7 @@ async fn connect_github_account(auth: SmbAuthorization) -> Result<CommandResult>
311
);
312
313
let response = Client::new()
312
- .post(build_smb_connect_github_url())
314
+ .post(build_smb_connect_github_url(env))
315
.json(&auth)
316
.header("Accept", "application/json")
317
.header("Content-Type", "application/x-www-form-urlencoded")
@@ -329,7 +331,7 @@ async fn connect_github_account(auth: SmbAuthorization) -> Result<CommandResult>
331
}
332
}
333
332
-async fn login_with_email() -> Result<CommandResult> {
334
+async fn login_with_email(env: Environment) -> Result<CommandResult> {
335
println!("Provide your login credentials.");
336
let username = match Input::<String>::with_theme(&ColorfulTheme::default())
337
.with_prompt("Email")
@@ -352,10 +354,10 @@ async fn login_with_email() -> Result<CommandResult> {
354
return Err(error);
355
}
356
};
355
- do_process_login(LoginArgs { username, password }).await
357
+ do_process_login(env, LoginArgs { username, password }).await
358
}
359
358
-async fn do_process_login(args: LoginArgs) -> Result<CommandResult> {
360
+async fn do_process_login(env: Environment, args: LoginArgs) -> Result<CommandResult> {
361
let login_params = LoginParams {
362
user: UserParam {
363
email: args.username,
@@ -364,7 +366,7 @@ async fn do_process_login(args: LoginArgs) -> Result<CommandResult> {
366
};
367
368
let response = Client::new()
367
- .post(build_smb_login_url())
369
+ .post(build_smb_login_url(env))
370
.json(&login_params)
371
.send()
372
.await?;
@@ -397,19 +399,22 @@ async fn do_process_login(args: LoginArgs) -> Result<CommandResult> {
399
// Account found but email not verified / password not set
400
let result: SmbAuthorization = response.json().await?;
401
// println!("Result: {:#?}", &result);
400
- verify_or_set_password(result).await
402
+ verify_or_set_password(&env, result).await
403
}
404
_ => Err(anyhow!("Login failed. Check your username and password.")),
405
}
406
}
407
406
-async fn verify_or_set_password(result: SmbAuthorization) -> Result<CommandResult> {
408
+async fn verify_or_set_password(
409
+ env: &Environment,
410
+ result: SmbAuthorization,
411
+) -> Result<CommandResult> {
412
match result.error_code {
413
Some(error_code) => {
414
debug!("{}", error_code);
415
match error_code {
411
- ErrorCode::EmailUnverified => send_email_verification(result.user).await,
412
- ErrorCode::PasswordNotSet => send_reset_password(result.user).await,
416
+ ErrorCode::EmailUnverified => send_email_verification(*env, result.user).await,
417
+ ErrorCode::PasswordNotSet => send_reset_password(*env, result.user).await,
418
_ => Err(anyhow!("Shouldn't be here.")),
419
}
420
}
@@ -417,7 +422,7 @@ async fn verify_or_set_password(result: SmbAuthorization) -> Result<CommandResul
422
}
423
}
424
420
-async fn send_reset_password(user: Option<User>) -> Result<CommandResult> {
425
+async fn send_reset_password(env: Environment, user: Option<User>) -> Result<CommandResult> {
426
// Return early if user is null
427
if let Some(user) = user {
428
let confirm = match Confirm::with_theme(&ColorfulTheme::default())
@@ -443,14 +448,14 @@ async fn send_reset_password(user: Option<User>) -> Result<CommandResult> {
448
msg: "Doing nothing.".to_owned(),
449
});
450
}
446
- resend_reset_password_instruction(user).await
451
+ resend_reset_password_instruction(env, user).await
452
} else {
453
let error = anyhow!("Failed to get user.");
454
Err(error)
455
}
456
}
457
453
-async fn resend_reset_password_instruction(user: User) -> Result<CommandResult> {
458
+async fn resend_reset_password_instruction(env: Environment, user: User) -> Result<CommandResult> {
459
let mut spinner = Spinner::new(
460
spinners::Spinners::SimpleDotsScrolling,
461
style("Sending reset password instruction...")
@@ -459,7 +464,7 @@ async fn resend_reset_password_instruction(user: User) -> Result<CommandResult>
464
.to_string(),
465
);
466
let response = Client::new()
462
- .post(build_smb_resend_reset_password_instructions_url())
467
+ .post(build_smb_resend_reset_password_instructions_url(env))
468
.body(format!("id={}", user.id))
469
.header("Accept", "application/json")
470
.header("Content-Type", "application/x-www-form-urlencoded")
@@ -472,7 +477,7 @@ async fn resend_reset_password_instruction(user: User) -> Result<CommandResult>
477
"✅",
478
"Reset password instruction sent! Please check your email.".to_owned(),
479
);
475
- input_reset_password_token().await
480
+ input_reset_password_token(env).await
481
}
482
_ => {
483
let error = anyhow!("Failed to send reset password instruction.");
@@ -481,7 +486,7 @@ async fn resend_reset_password_instruction(user: User) -> Result<CommandResult>
486
}
487
}
488
484
-async fn input_reset_password_token() -> Result<CommandResult> {
489
+async fn input_reset_password_token(env: Environment) -> Result<CommandResult> {
490
let token = match Input::<String>::with_theme(&ColorfulTheme::default())
491
.with_prompt("Input reset password token")
492
.interact()
@@ -520,7 +525,7 @@ async fn input_reset_password_token() -> Result<CommandResult> {
525
};
526
527
let response = Client::new()
523
- .put(build_smb_reset_password_url())
528
+ .put(build_smb_reset_password_url(env))
529
.json(¶ms)
530
.header("Accept", "application/json")
531
.header("Content-Type", "application/x-www-form-urlencoded")
@@ -540,11 +545,11 @@ async fn input_reset_password_token() -> Result<CommandResult> {
545
}
546
}
547
543
-async fn do_process_logout() -> Result<()> {
548
+async fn do_process_logout(env: Environment) -> Result<()> {
549
let token = get_smb_token().await?;
550
551
let response = Client::new()
547
- .delete(build_smb_logout_url())
552
+ .delete(build_smb_logout_url(env))
553
.header("Authorization", token)
554
.header("Accept", "application/json")
555
.header("Content-Type", "application/x-www-form-urlencoded")
@@ -557,38 +562,38 @@ async fn do_process_logout() -> Result<()> {
562
}
563
}
564
560
-fn build_smb_login_url() -> String {
561
- let mut url_builder = smb_base_url_builder();
565
+fn build_smb_login_url(env: Environment) -> String {
566
+ let mut url_builder = smb_base_url_builder(env);
567
url_builder.add_route(PATH_USERS_SIGN_IN);
568
url_builder.build()
569
}
570
566
-fn build_smb_logout_url() -> String {
567
- let mut url_builder = smb_base_url_builder();
571
+fn build_smb_logout_url(env: Environment) -> String {
572
+ let mut url_builder = smb_base_url_builder(env);
573
url_builder.add_route(PATH_USERS_SIGN_OUT);
574
url_builder.build()
575
}
576
572
-fn build_smb_resend_email_verification_url() -> String {
573
- let mut url_builder = smb_base_url_builder();
577
+fn build_smb_resend_email_verification_url(env: Environment) -> String {
578
+ let mut url_builder = smb_base_url_builder(env);
579
url_builder.add_route(PATH_RESEND_CONFIRMATION);
580
url_builder.build()
581
}
582
578
-fn build_smb_resend_reset_password_instructions_url() -> String {
579
- let mut url_builder = smb_base_url_builder();
583
+fn build_smb_resend_reset_password_instructions_url(env: Environment) -> String {
584
+ let mut url_builder = smb_base_url_builder(env);
585
url_builder.add_route(PATH_RESET_PASSWORD_INSTRUCTIONS);
586
url_builder.build()
587
}
588
584
-fn build_smb_reset_password_url() -> String {
585
- let mut url_builder = smb_base_url_builder();
589
+fn build_smb_reset_password_url(env: Environment) -> String {
590
+ let mut url_builder = smb_base_url_builder(env);
591
url_builder.add_route(PATH_USERS_PASSWORD);
592
url_builder.build()
593
}
594
590
-fn build_smb_connect_github_url() -> String {
591
- let mut url_builder = smb_base_url_builder();
595
+fn build_smb_connect_github_url(env: Environment) -> String {
596
+ let mut url_builder = smb_base_url_builder(env);
597
url_builder.add_route(PATH_LINK_GITHUB_ACCOUNT);
598
url_builder.build()
599
}
smbcloud-cli/src/account/mod.rs
+6
-5
@@ -12,12 +12,13 @@ use self::{
12
};
13
use crate::cli::CommandResult;
14
use anyhow::Result;
15
+use smbcloud_networking::environment::Environment;
16
16
-pub async fn process_account(commands: Commands) -> Result<CommandResult> {
17
+pub async fn process_account(env: Environment, commands: Commands) -> Result<CommandResult> {
18
match commands {
18
- Commands::Signup {} => process_signup().await,
19
- Commands::Login {} => process_login().await,
20
- Commands::Logout {} => process_logout().await,
21
- Commands::Forgot {} => process_forgot().await,
19
+ Commands::Signup {} => process_signup(env).await,
20
+ Commands::Login {} => process_login(env).await,
21
+ Commands::Logout {} => process_logout(env).await,
22
+ Commands::Forgot {} => process_forgot(env).await,
23
}
24
}
smbcloud-cli/src/account/signup/process.rs
+14
-12
@@ -7,11 +7,13 @@ use log::debug;
7
use reqwest::{Client, StatusCode};
8
use serde::Serialize;
9
use smbcloud_model::signup::{SignupEmailParams, SignupResult, SignupUserEmail};
10
-use smbcloud_networking::{constants::PATH_USERS, smb_base_url_builder, smb_token_file_path};
10
+use smbcloud_networking::{
11
+ constants::PATH_USERS, environment::Environment, smb_base_url_builder, smb_token_file_path,
12
+};
13
use smbcloud_utils::email_validation;
14
use spinners::Spinner;
15
14
-pub async fn process_signup() -> Result<CommandResult> {
16
+pub async fn process_signup(env: Environment) -> Result<CommandResult> {
17
// Check if token file exists
18
if smb_token_file_path().is_some() {
19
return Ok(CommandResult {
@@ -33,12 +35,12 @@ pub async fn process_signup() -> Result<CommandResult> {
35
.unwrap();
36
37
match selection {
36
- SignupMethod::Email => signup_with_email(None).await,
37
- SignupMethod::GitHub => signup_with_github().await,
38
+ SignupMethod::Email => signup_with_email(env, None).await,
39
+ SignupMethod::GitHub => signup_with_github(env).await,
40
}
41
}
42
41
-pub async fn signup_with_email(email: Option<String>) -> Result<CommandResult> {
43
+pub async fn signup_with_email(env: Environment, email: Option<String>) -> Result<CommandResult> {
44
let email = if let Some(email) = email {
45
email
46
} else {
@@ -71,7 +73,7 @@ pub async fn signup_with_email(email: Option<String>) -> Result<CommandResult> {
73
user: SignupUserEmail { email, password },
74
};
75
74
- match do_signup(¶ms).await {
76
+ match do_signup(env, ¶ms).await {
77
Ok(_) => Ok(CommandResult {
78
spinner,
79
symbol: style("✅".to_string()).for_stderr().green().to_string(),
@@ -85,8 +87,8 @@ pub async fn signup_with_email(email: Option<String>) -> Result<CommandResult> {
87
}
88
}
89
88
-async fn signup_with_github() -> Result<CommandResult> {
89
- match authorize_github().await {
90
+async fn signup_with_github(env: Environment) -> Result<CommandResult> {
91
+ match authorize_github(&env).await {
92
Ok(code) => {
93
debug!("Code: {:#?}", code);
94
Ok(CommandResult {
@@ -108,14 +110,14 @@ async fn signup_with_github() -> Result<CommandResult> {
110
}
111
}
112
111
-pub async fn do_signup<T: Serialize + ?Sized>(args: &T) -> Result<CommandResult> {
113
+pub async fn do_signup<T: Serialize + ?Sized>(env: Environment, args: &T) -> Result<CommandResult> {
114
let spinner = Spinner::new(
115
spinners::Spinners::BouncingBall,
116
style("Signing you up...").green().bold().to_string(),
117
);
118
119
let response = Client::new()
118
- .post(build_smb_signup_url())
120
+ .post(build_smb_signup_url(env))
121
.json(&args)
122
.send()
123
.await?;
@@ -138,8 +140,8 @@ pub async fn do_signup<T: Serialize + ?Sized>(args: &T) -> Result<CommandResult>
140
}
141
}
142
141
-fn build_smb_signup_url() -> String {
142
- let mut url_builder = smb_base_url_builder();
143
+fn build_smb_signup_url(env: Environment) -> String {
144
+ let mut url_builder = smb_base_url_builder(env);
145
url_builder.add_route(PATH_USERS);
146
url_builder.build()
147
}
smbcloud-cli/src/cli/mod.rs
+1
-36
@@ -1,5 +1,6 @@
1
use crate::{account, project};
2
use clap::{Parser, Subcommand};
3
+use smbcloud_networking::environment::Environment;
4
use spinners::Spinner;
5
6
pub struct CommandResult {
@@ -8,42 +9,6 @@ pub struct CommandResult {
9
pub msg: String,
10
}
11
11
-#[derive(clap::ValueEnum, Clone)]
12
-pub enum Environment {
13
- Dev,
14
- Production,
15
-}
16
-
17
-impl std::fmt::Display for Environment {
18
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19
- write!(f, "{}", self.to_str())
20
- }
21
-}
22
-
23
-impl Environment {
24
- pub fn from_str(env: &str) -> Self {
25
- match env.to_lowercase().as_str() {
26
- "dev" => Environment::Dev,
27
- "production" => Environment::Production,
28
- _ => panic!("Invalid environment: {}", env),
29
- }
30
- }
31
-
32
- pub fn to_str(&self) -> &str {
33
- match self {
34
- Environment::Dev => "dev",
35
- Environment::Production => "production",
36
- }
37
- }
38
-
39
- pub fn smb_dir(&self) -> String {
40
- match self {
41
- Environment::Dev => ".smb-dev".to_string(),
42
- Environment::Production => ".smb".to_string(),
43
- }
44
- }
45
-}
46
-
12
#[derive(Parser)]
13
#[clap(author, version, about)]
14
pub struct Cli {
smbcloud-cli/src/main.rs
+17
-6
@@ -1,7 +1,7 @@
1
use anyhow::{anyhow, Result};
2
use clap::Parser;
3
use console::style;
4
-use smbcloud_cli::cli::{CommandResult, Environment};
4
+use smbcloud_cli::cli::CommandResult;
5
use smbcloud_cli::project::init::process_project_init;
6
use smbcloud_cli::{
7
account::process_account,
@@ -9,6 +9,7 @@ use smbcloud_cli::{
9
deploy::process_deploy,
10
project::process_project,
11
};
12
+use smbcloud_networking::environment::Environment;
13
use std::{
14
fs::{create_dir_all, OpenOptions},
15
path::PathBuf,
@@ -18,15 +19,22 @@ use tracing::subscriber::set_global_default;
19
use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer};
20
use tracing_subscriber::{filter::LevelFilter, prelude::*, EnvFilter};
21
21
-fn setup_logging( env: Environment, level: Option<EnvFilter>) -> Result<()> {
22
+fn setup_logging(env: Environment, level: Option<EnvFilter>) -> Result<()> {
23
// Log in the current directory
24
let log_path = match home::home_dir() {
25
Some(path) => {
26
create_dir_all(path.join(env.smb_dir()))?;
26
- let log_path = [path.to_str().unwrap(), "/", &env.smb_dir(), "/smbcloud-cli.log"].join("");
27
+ let log_path = [
28
+ path.to_str().unwrap(),
29
+ "/",
30
+ &env.smb_dir(),
31
+ "/smbcloud-cli.log",
32
+ ]
33
+ .join("");
34
// Create the file if it doesn't exist
35
let _file = OpenOptions::new()
36
.create(true)
37
+ .truncate(true)
38
.write(true)
39
.open(&log_path)?;
40
@@ -39,6 +47,7 @@ fn setup_logging( env: Environment, level: Option<EnvFilter>) -> Result<()> {
47
48
let file = OpenOptions::new()
49
.create(true)
50
+ .truncate(true)
51
.write(true)
52
.open(log_path)
53
.unwrap();
@@ -101,9 +110,11 @@ async fn run() -> Result<CommandResult> {
110
}
111
112
match cli.command {
104
- Commands::Account { command } => process_account(command).await,
105
- Commands::Project { command } => process_project(command).await,
106
- Commands::Init { name, description } => process_project_init(name, description).await,
113
+ Commands::Account { command } => process_account(cli.environment, command).await,
114
+ Commands::Project { command } => process_project(cli.environment, command).await,
115
+ Commands::Init { name, description } => {
116
+ process_project_init(cli.environment, name, description).await
117
+ }
118
Commands::Deploy {} => process_deploy().await,
119
}
120
}
smbcloud-cli/src/project/init.rs
+4
-2
@@ -2,10 +2,12 @@ use crate::cli::CommandResult;
2
use anyhow::Result;
3
use console::style;
4
use smbcloud_model::project::ProjectCreate;
5
+use smbcloud_networking::environment::Environment;
6
use smbcloud_networking_project::create_project;
7
use spinners::Spinner;
8
9
pub async fn process_project_init(
10
+ env: Environment,
11
name: Option<String>,
12
description: Option<String>,
13
) -> Result<CommandResult> {
@@ -16,7 +18,7 @@ pub async fn process_project_init(
18
let name = name.unwrap_or_else(|| "New Project".to_string());
19
let description = description.unwrap_or_else(|| "No description".to_string());
20
let project = ProjectCreate { name, description };
19
- match create_project(project).await {
21
+ match create_project(env, project).await {
22
Ok(p) => {
23
spinner.stop_and_persist("✅", "Done.".to_owned());
24
Ok(CommandResult {
@@ -30,7 +32,7 @@ pub async fn process_project_init(
32
Ok(CommandResult {
33
spinner,
34
symbol: "😩".to_owned(),
33
- msg: format!("Failed to initiate a project."),
35
+ msg: "Failed to initiate a project.".to_string(),
36
})
37
}
38
}
smbcloud-cli/src/project/mod.rs
+13
-9
@@ -11,11 +11,12 @@ use smbcloud_model::{
11
self,
12
project::{Config, Project, ProjectCreate},
13
};
14
+use smbcloud_networking::environment::Environment;
15
use smbcloud_networking_project::{create_project, delete_project, get_all, get_project};
16
use spinners::Spinner;
17
use std::{fs::OpenOptions, io::Write};
18
18
-pub async fn process_project(commands: Commands) -> Result<CommandResult> {
19
+pub async fn process_project(env: Environment, commands: Commands) -> Result<CommandResult> {
20
match commands {
21
Commands::New {} => {
22
let project_name = Input::<String>::with_theme(&ColorfulTheme::default())
@@ -32,10 +33,13 @@ pub async fn process_project(commands: Commands) -> Result<CommandResult> {
33
style("Creating a project...").green().bold().to_string(),
34
);
35
35
- match create_project(ProjectCreate {
36
- name: project_name.clone(),
37
- description: description.clone(),
38
- })
36
+ match create_project(
37
+ env,
38
+ ProjectCreate {
39
+ name: project_name.clone(),
40
+ description: description.clone(),
41
+ },
42
+ )
43
.await
44
{
45
Ok(_) => {
@@ -66,7 +70,7 @@ pub async fn process_project(commands: Commands) -> Result<CommandResult> {
70
);
71
72
// Get all
69
- match get_all().await {
73
+ match get_all(env).await {
74
Ok(projects) => {
75
spinner.stop_and_persist("✅", "Loaded.".to_owned());
76
let msg = if projects.is_empty() {
@@ -100,7 +104,7 @@ pub async fn process_project(commands: Commands) -> Result<CommandResult> {
104
style("Loading...").green().bold().to_string(),
105
);
106
// Get Detail
103
- match get_project(id).await {
107
+ match get_project(env, id).await {
108
Ok(project) => {
109
spinner.stop_and_persist("✅", "Loaded.".to_owned());
110
let message = format!("Showing project {}.", &project.name);
@@ -138,7 +142,7 @@ pub async fn process_project(commands: Commands) -> Result<CommandResult> {
142
msg: "Cancelled.".to_string(),
143
});
144
}
141
- match delete_project(id).await {
145
+ match delete_project(env, id).await {
146
Ok(_) => {
147
spinner.stop_and_persist("✅", "Done.".to_string());
148
Ok(CommandResult {
@@ -157,7 +161,7 @@ pub async fn process_project(commands: Commands) -> Result<CommandResult> {
161
}
162
}
163
Commands::Use { id } => {
160
- let project = get_project(id).await?;
164
+ let project = get_project(env, id).await?;
165
166
let config = Config {
167
current_project: Some(project),
smbcloud-networking-project/src/lib.rs
+13
-13
@@ -5,16 +5,16 @@ use smbcloud_model::{
5
self,
6
project::{Project, ProjectCreate},
7
};
8
-use smbcloud_networking::{get_smb_token, smb_base_url_builder};
8
+use smbcloud_networking::{environment::Environment, get_smb_token, smb_base_url_builder};
9
10
-pub async fn get_all() -> Result<Vec<Project>> {
10
+pub async fn get_all(env: Environment) -> Result<Vec<Project>> {
11
// Get current token
12
let token = get_smb_token().await?;
13
14
debug!("Current token: {}", token);
15
16
let response = Client::new()
17
- .get(build_project_url())
17
+ .get(build_project_url(env))
18
.header("Authorization", token)
19
.header("User-agent", "smbcloud-cli")
20
.send()
@@ -29,12 +29,12 @@ pub async fn get_all() -> Result<Vec<Project>> {
29
}
30
}
31
32
-pub async fn create_project(project: ProjectCreate) -> Result<Project> {
32
+pub async fn create_project(env: Environment, project: ProjectCreate) -> Result<Project> {
33
// Get current token
34
let token = get_smb_token().await?;
35
36
let response = Client::new()
37
- .post(build_project_url())
37
+ .post(build_project_url(env))
38
.json(&project)
39
.header("Authorization", token)
40
.send()
@@ -50,12 +50,12 @@ pub async fn create_project(project: ProjectCreate) -> Result<Project> {
50
}
51
}
52
53
-pub async fn get_project(id: String) -> Result<Project> {
53
+pub async fn get_project(env: Environment, id: String) -> Result<Project> {
54
// Get current token
55
let token = get_smb_token().await?;
56
57
let response = Client::new()
58
- .get(build_project_url_with_id(id))
58
+ .get(build_project_url_with_id(env, id))
59
.header("Authorization", token)
60
.send()
61
.await?;
@@ -70,12 +70,12 @@ pub async fn get_project(id: String) -> Result<Project> {
70
}
71
}
72
73
-pub async fn delete_project(id: String) -> Result<()> {
73
+pub async fn delete_project(env: Environment, id: String) -> Result<()> {
74
// Get current token
75
let token = get_smb_token().await?;
76
77
let response = Client::new()
78
- .delete(build_project_url_with_id(id))
78
+ .delete(build_project_url_with_id(env, id))
79
.header("Authorization", token)
80
.send()
81
.await?;
@@ -91,14 +91,14 @@ pub async fn delete_project(id: String) -> Result<()> {
91
92
// Private functions
93
94
-fn build_project_url() -> String {
95
- let mut url_builder = smb_base_url_builder();
94
+fn build_project_url(env: Environment) -> String {
95
+ let mut url_builder = smb_base_url_builder(env);
96
url_builder.add_route("v1/projects");
97
url_builder.build()
98
}
99
100
-fn build_project_url_with_id(id: String) -> String {
101
- let mut url_builder = smb_base_url_builder();
100
+fn build_project_url_with_id(env: Environment, id: String) -> String {
101
+ let mut url_builder = smb_base_url_builder(env);
102
url_builder.add_route("v1/projects");
103
url_builder.add_route(id.as_str());
104
url_builder.build()
smbcloud-networking/Cargo.toml
+1
@@ -14,6 +14,7 @@ categories = ["command-line-utilities", "command-line-interface", "cryptography:
14
[dependencies]
15
anyhow = { workspace = true }
16
async-trait = { workspace = true, optional = true }
17
+clap = { workspace = true, features = ["derive", "env"] }
18
dirs = { workspace = true }
19
home = { workspace = true }
20
log = { workspace = true }
smbcloud-networking/src/constants.rs
-10
@@ -11,16 +11,6 @@ pub const GH_OAUTH_REDIRECT_PORT: &str = "8808";
11
pub const SMB_CLIENT_ID: &str = "cli";
12
pub const SMB_CLIENT_SECRET: &str = "secretttttttt";
13
14
-#[cfg(debug_assertions)]
15
-pub const SMB_API_PROTOCOL: &str = "http";
16
-#[cfg(not(debug_assertions))]
17
-pub const SMB_API_PROTOCOL: &str = "https";
18
-
19
-#[cfg(debug_assertions)]
20
-pub const SMB_API_HOST: &str = "localhost:8088";
21
-#[cfg(not(debug_assertions))]
22
-pub const SMB_API_HOST: &str = "api.smbcloud.xyz";
23
-
14
// Paths
15
pub const PATH_USERS: &str = "v1/users";
16
pub const PATH_USERS_PASSWORD: &str = "v1/users/password";
smbcloud-networking/src/environment.rs
new
+48
@@ -0,0 +1,48 @@
1
+#[derive(clap::ValueEnum, Clone, Copy)]
2
+pub enum Environment {
3
+ Dev,
4
+ Production,
5
+}
6
+
7
+impl std::fmt::Display for Environment {
8
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9
+ write!(f, "{}", self.to_str())
10
+ }
11
+}
12
+
13
+impl Environment {
14
+ pub fn from_str(env: &str) -> Self {
15
+ match env.to_lowercase().as_str() {
16
+ "dev" => Environment::Dev,
17
+ "production" => Environment::Production,
18
+ _ => panic!("Invalid environment: {}", env),
19
+ }
20
+ }
21
+
22
+ pub fn to_str(&self) -> &str {
23
+ match self {
24
+ Environment::Dev => "dev",
25
+ Environment::Production => "production",
26
+ }
27
+ }
28
+
29
+ pub fn smb_dir(&self) -> String {
30
+ match self {
31
+ Environment::Dev => ".smb-dev".to_string(),
32
+ Environment::Production => ".smb".to_string(),
33
+ }
34
+ }
35
+
36
+ pub fn api_protocol(&self) -> String {
37
+ match self {
38
+ Environment::Dev => "http".to_string(),
39
+ Environment::Production => "https".to_string(),
40
+ }
41
+ }
42
+ pub fn api_host(&self) -> String {
43
+ match self {
44
+ Environment::Dev => "localhost:8088".to_string(),
45
+ Environment::Production => "api.smbcloud.xyz".to_string(),
46
+ }
47
+ }
48
+}
smbcloud-networking/src/lib.rs
+6
-4
@@ -1,8 +1,10 @@
1
pub mod constants;
2
+pub mod environment;
3
4
use crate::constants::TOKEN_PATH_STR;
5
use anyhow::{anyhow, Result};
5
-use constants::{SMB_API_HOST, SMB_API_PROTOCOL, SMB_CLIENT_ID, SMB_CLIENT_SECRET};
6
+use constants::{SMB_CLIENT_ID, SMB_CLIENT_SECRET};
7
+use environment::Environment;
8
use log::debug;
9
use std::path::PathBuf;
10
use url_builder::URLBuilder;
@@ -35,11 +37,11 @@ pub fn smb_token_file_path() -> Option<PathBuf> {
37
}
38
}
39
38
-pub fn smb_base_url_builder() -> URLBuilder {
40
+pub fn smb_base_url_builder(env: Environment) -> URLBuilder {
41
let mut url_builder = URLBuilder::new();
42
url_builder
41
- .set_protocol(SMB_API_PROTOCOL)
42
- .set_host(SMB_API_HOST)
43
+ .set_protocol(&env.api_protocol())
44
+ .set_host(&env.api_host())
45
.add_param("client_id", SMB_CLIENT_ID)
46
.add_param("client_secret", SMB_CLIENT_SECRET);
47
url_builder