3 files changed
+107
-73
smbpndk-cli/src/account/lib.rs
+12
-29
@@ -1,12 +1,11 @@
1
+use super::{model::User, signup::GithubEmail};
2
use anyhow::{anyhow, Result};
3
use console::style;
4
use log::debug;
5
use regex::Regex;
6
use reqwest::{Client, Response, StatusCode};
7
use serde::{Deserialize, Serialize};
7
-
8
use serde_repr::Deserialize_repr;
9
-use smbpndk_model::CommandResult;
9
use smbpndk_networking::smb_base_url_builder;
10
use spinners::Spinner;
11
use std::{
@@ -19,8 +18,6 @@ use std::{
18
};
19
use url_builder::URLBuilder;
20
22
-use super::{model::User, signup::GithubEmail};
23
-
21
// This is smb authorization model.
22
#[derive(Debug, Serialize, Deserialize)]
23
pub struct SmbAuthorization {
@@ -173,33 +170,33 @@ pub async fn process_connect_github(code: String) -> Result<SmbAuthorization> {
170
.bold()
171
.to_string(),
172
);
176
- println!("Response: {:#?}", &response);
173
+ // println!("Response: {:#?}", &response);
174
match response.status() {
175
StatusCode::OK => {
176
// Account authorized and token received
180
- spinner.stop_and_persist("✅", "You're logged in with your GitHub account!".into());
177
+ spinner.stop_and_persist("✅", "You are logged in with your GitHub account!".into());
178
save_token(&response).await?;
179
let result = response.json().await?;
183
- println!("Result: {:#?}", &result);
180
+ // println!("Result: {:#?}", &result);
181
Ok(result)
182
}
183
StatusCode::NOT_FOUND => {
184
// Account not found and we show signup option
185
spinner.stop_and_persist("🥲", "Account not found. Please signup!".into());
186
let result = response.json().await?;
190
- println!("Result: {:#?}", &result);
187
+ // println!("Result: {:#?}", &result);
188
Ok(result)
189
}
190
StatusCode::UNPROCESSABLE_ENTITY => {
191
// Account found but email not verified
192
spinner.stop_and_persist("🥹", "Unverified email!".into());
193
let result = response.json().await?;
197
- println!("Result: {:#?}", &result);
194
+ // println!("Result: {:#?}", &result);
195
Ok(result)
196
}
197
_ => {
198
// Other errors
202
- let error = anyhow!("Error while authorizing token.");
199
+ let error = anyhow!("Error while authorizing with GitHub.");
200
Err(error)
201
}
202
}
@@ -237,9 +234,9 @@ fn github_base_url_builder() -> URLBuilder {
234
url_builder
235
}
236
240
-pub async fn save_token(response: &Response) -> Result<CommandResult> {
237
+pub async fn save_token(response: &Response) -> Result<()> {
238
let headers = response.headers();
242
- println!("Headers: {:#?}", &headers);
239
+ // println!("Headers: {:#?}", &headers);
240
match headers.get("Authorization") {
241
Some(token) => {
242
debug!("{}", token.to_str()?);
@@ -252,25 +249,11 @@ pub async fn save_token(response: &Response) -> Result<CommandResult> {
249
.write(true)
250
.open([path.to_str().unwrap(), "/.smb/token"].join(""))?;
251
file.write_all(token.to_str()?.as_bytes())?;
255
-
256
- Ok(CommandResult {
257
- spinner: Spinner::new(
258
- spinners::Spinners::SimpleDotsScrolling,
259
- style("Logging you in...").green().bold().to_string(),
260
- ),
261
- symbol: "✅".to_owned(),
262
- msg: "You are logged in!".to_owned(),
263
- })
264
- }
265
- None => {
266
- let error = anyhow!("Failed to get home directory.");
267
- return Err(error);
252
+ Ok(())
253
}
254
+ None => Err(anyhow!("Failed to get home directory.")),
255
}
256
}
271
- None => {
272
- let error = anyhow!("Failed to get token. Probably a backend issue.");
273
- return Err(error);
274
- }
257
+ None => Err(anyhow!("Failed to get token. Probably a backend issue.")),
258
}
259
}
smbpndk-cli/src/account/login/process.rs
+94
-43
@@ -13,7 +13,7 @@ use log::debug;
13
use reqwest::{Client, StatusCode};
14
use serde::{Deserialize, Serialize};
15
use smbpndk_model::CommandResult;
16
-use smbpndk_networking::{smb_base_url_builder, smb_token_file_path};
16
+use smbpndk_networking::{get_smb_token, smb_base_url_builder, smb_token_file_path};
17
use smbpndk_utils::email_validation;
18
use spinners::Spinner;
19
use std::fs::{self};
@@ -67,6 +67,59 @@ pub async fn process_login() -> Result<CommandResult> {
67
}
68
}
69
70
+pub async fn process_logout() -> Result<CommandResult> {
71
+ // Logout if user confirms
72
+ if let Some(token_path) = smb_token_file_path() {
73
+ let confirm = Confirm::with_theme(&ColorfulTheme::default())
74
+ .with_prompt("Do you want to logout? y/n")
75
+ .interact()
76
+ .unwrap();
77
+ if !confirm {
78
+ return Ok(CommandResult {
79
+ spinner: Spinner::new(
80
+ spinners::Spinners::SimpleDotsScrolling,
81
+ style("Cancel operation.").green().bold().to_string(),
82
+ ),
83
+ symbol: "✅".to_owned(),
84
+ msg: "Doing nothing.".to_owned(),
85
+ });
86
+ }
87
+
88
+ let mut spinner = Spinner::new(
89
+ spinners::Spinners::SimpleDotsScrolling,
90
+ style("Logging you out...").green().bold().to_string(),
91
+ );
92
+
93
+ // Call backend
94
+ match do_process_logout().await {
95
+ Ok(_) => {
96
+ spinner.stop_and_persist("✅", "Done.".to_owned());
97
+ fs::remove_file(token_path)?;
98
+ Ok(CommandResult {
99
+ spinner: Spinner::new(
100
+ spinners::Spinners::SimpleDotsScrolling,
101
+ style("Loading...").green().bold().to_string(),
102
+ ),
103
+ symbol: "✅".to_owned(),
104
+ msg: "You are now logged out!".to_owned(),
105
+ })
106
+ }
107
+ Err(e) => Err(anyhow!("{e}")),
108
+ }
109
+ } else {
110
+ Ok(CommandResult {
111
+ spinner: Spinner::new(
112
+ spinners::Spinners::SimpleDotsScrolling,
113
+ style("Loading...").green().bold().to_string(),
114
+ ),
115
+ symbol: "😏".to_owned(),
116
+ msg: "You are not logged in.".to_owned(),
117
+ })
118
+ }
119
+}
120
+
121
+// Private functions
122
+
123
async fn login_with_github() -> Result<CommandResult> {
124
match authorize_github().await {
125
Ok(result) => process_authorization(result).await,
@@ -95,18 +148,18 @@ async fn process_authorization(auth: SmbAuthorization) -> Result<CommandResult>
148
}
149
}
150
98
- // Logged in with GitHub
151
+ // Logged in with GitHub!
152
+ // Token handling is in the lib.rs account module.
153
if let Some(user) = auth.user {
100
- println!("You are logged in with GitHub as {}.", user);
154
let spinner = Spinner::new(
155
spinners::Spinners::SimpleDotsScrolling,
156
style("Logging you in...").green().bold().to_string(),
157
);
105
- // We're logged in with GitHub, but not with SMB.
158
+ // We're logged in with GitHub.
159
return Ok(CommandResult {
160
spinner,
161
symbol: "✅".to_owned(),
109
- msg: "You are logged in!".to_owned(),
162
+ msg: format!("You are logged in with GitHub as {}.", user.email),
163
});
164
}
165
@@ -241,7 +294,15 @@ async fn do_process_login(args: LoginArgs) -> Result<CommandResult> {
294
match response.status() {
295
StatusCode::OK => {
296
// Login successful
244
- save_token(&response).await
297
+ save_token(&response).await?;
298
+ Ok(CommandResult {
299
+ spinner: Spinner::new(
300
+ spinners::Spinners::SimpleDotsScrolling,
301
+ style("Loading...").green().bold().to_string(),
302
+ ),
303
+ symbol: "✅".to_owned(),
304
+ msg: "You are now logged in!".to_owned(),
305
+ })
306
}
307
StatusCode::NOT_FOUND => {
308
// Account not found and we show signup option
@@ -257,13 +318,10 @@ async fn do_process_login(args: LoginArgs) -> Result<CommandResult> {
318
StatusCode::UNPROCESSABLE_ENTITY => {
319
// Account found but email not verified / password not set
320
let result: SmbAuthorization = response.json().await?;
260
- println!("Result: {:#?}", &result);
261
- return verify_or_set_password(result).await;
262
- }
263
- _ => {
264
- let error = anyhow!("Login failed. Check your username and password.");
265
- return Err(error);
321
+ // println!("Result: {:#?}", &result);
322
+ verify_or_set_password(result).await
323
}
324
+ _ => Err(anyhow!("Login failed. Check your username and password.")),
325
}
326
}
327
@@ -272,18 +330,12 @@ async fn verify_or_set_password(result: SmbAuthorization) -> Result<CommandResul
330
Some(error_code) => {
331
debug!("{}", error_code);
332
match error_code {
275
- ErrorCode::EmailUnverified => return send_email_verification(result.user).await,
276
- ErrorCode::PasswordNotSet => return send_reset_password(result.user).await,
277
- _ => {
278
- let error = anyhow!("Shouldn't be here.");
279
- return Err(error);
280
- }
333
+ ErrorCode::EmailUnverified => send_email_verification(result.user).await,
334
+ ErrorCode::PasswordNotSet => send_reset_password(result.user).await,
335
+ _ => Err(anyhow!("Shouldn't be here.")),
336
}
337
}
283
- None => {
284
- let error = anyhow!("Shouldn't be here.");
285
- return Err(error);
286
- }
338
+ None => Err(anyhow!("Shouldn't be here.")),
339
}
340
}
341
@@ -392,36 +444,35 @@ async fn input_reset_password_token() -> Result<CommandResult> {
444
}
445
}
446
395
-pub async fn process_logout() -> Result<CommandResult> {
396
- let spinner = Spinner::new(
397
- spinners::Spinners::SimpleDotsScrolling,
398
- style("Logging you out...").green().bold().to_string(),
399
- );
400
- if let Some(token_path) = smb_token_file_path() {
401
- // Call backend
402
- fs::remove_file(token_path)?;
403
- Ok(CommandResult {
404
- spinner,
405
- symbol: "✅".to_owned(),
406
- msg: "You are now logged out!".to_owned(),
407
- })
408
- } else {
409
- Ok(CommandResult {
410
- spinner,
411
- symbol: "😏".to_owned(),
412
- msg: "You are not logged in.".to_owned(),
413
- })
447
+async fn do_process_logout() -> Result<()> {
448
+ let token = get_smb_token().await?;
449
+
450
+ let response = Client::new()
451
+ .delete(build_smb_logout_url())
452
+ .header("Authorization", token)
453
+ .header("Accept", "application/json")
454
+ .header("Content-Type", "application/x-www-form-urlencoded")
455
+ .send()
456
+ .await?;
457
+
458
+ match response.status() {
459
+ StatusCode::OK => Ok(()),
460
+ _ => Err(anyhow!("Failed to logout.")),
461
}
462
}
463
417
-// Private functions
418
-
464
fn build_smb_login_url() -> String {
465
let mut url_builder = smb_base_url_builder();
466
url_builder.add_route("v1/users/sign_in");
467
url_builder.build()
468
}
469
470
+fn build_smb_logout_url() -> String {
471
+ let mut url_builder = smb_base_url_builder();
472
+ url_builder.add_route("v1/users/sign_out");
473
+ url_builder.build()
474
+}
475
+
476
fn build_smb_resend_email_verification_url() -> String {
477
let mut url_builder = smb_base_url_builder();
478
url_builder.add_route("v1/resend_confirmation");
smbpndk-cli/src/project/mod.rs
+1
-1
@@ -192,7 +192,7 @@ pub async fn process_project(commands: Commands) -> Result<CommandResult> {
192
193
fn show_projects(projects: Vec<Project>) {
194
// println!("Projects: {projects:#?}");
195
- if projects.len() == 0 {
195
+ if projects.is_empty() {
196
return;
197
}
198
println!(