smbcloud_cli/account/forgot/
mod.rs

1use crate::{
2    cli::CommandResult,
3    ui::{fail_message, fail_symbol, succeed_message, succeed_symbol},
4};
5use anyhow::Result;
6use dialoguer::{theme::ColorfulTheme, Input, Password};
7use reqwest::{Client, StatusCode};
8use serde::{Deserialize, Serialize};
9use smbcloud_model::forgot::{Args, Email, Param, UserUpdatePassword};
10use smbcloud_networking::{
11    constants::PATH_USERS_PASSWORD, environment::Environment, smb_base_url_builder,
12};
13use smbcloud_utils::email_validation;
14use spinners::Spinner;
15
16pub async fn process_forgot(env: Environment) -> Result<CommandResult> {
17    println!("Provide your login credentials.");
18    let email = Input::<String>::with_theme(&ColorfulTheme::default())
19        .with_prompt("Email")
20        .validate_with(|email: &String| email_validation(email))
21        .interact()
22        .unwrap();
23    let mut spinner = Spinner::new(
24        spinners::Spinners::SimpleDotsScrolling,
25        succeed_message("Checking email"),
26    );
27
28    let params = Args {
29        user: Email { email },
30    };
31
32    let response = Client::new()
33        .post(build_smb_forgot_url(env))
34        .json(&params)
35        .send()
36        .await?;
37
38    match response.status() {
39        StatusCode::OK => {
40            spinner.stop_and_persist(
41                &succeed_symbol(),
42                succeed_message("Check your email and input your code here."),
43            );
44            input_code(env).await
45        }
46        _ => Ok(CommandResult {
47            spinner,
48            symbol: fail_symbol(),
49            msg: fail_message("Something wrong when trying to reset email."),
50        }),
51    }
52}
53
54async fn input_code(env: Environment) -> Result<CommandResult> {
55    let security_code = Input::<String>::with_theme(&ColorfulTheme::default())
56        .with_prompt("Code")
57        .interact()
58        .unwrap();
59
60    Spinner::new(
61        spinners::Spinners::Hamburger,
62        succeed_message("Checking your code."),
63    )
64    .stop_and_persist("✅", "Great. Now input your new password.".to_owned());
65
66    let new_password = Password::with_theme(&ColorfulTheme::default())
67        .with_prompt("Password")
68        .validate_with(|input: &String| -> Result<(), &str> {
69            if input.len() >= 6 {
70                Ok(())
71            } else {
72                Err("Password must be at least 6 characters")
73            }
74        })
75        .with_confirmation("Confirm password", "Passwords do not match")
76        .interact()
77        .unwrap();
78    let password_confirmation = String::from(&new_password);
79
80    // Should reuse this somehow
81    let params = Param {
82        user: UserUpdatePassword {
83            reset_password_token: security_code,
84            password: new_password,
85            password_confirmation,
86        },
87    };
88
89    let spinner = Spinner::new(
90        spinners::Spinners::Hamburger,
91        succeed_message("Updating your password."),
92    );
93
94    let response = Client::new()
95        .put(build_smb_forgot_url(env))
96        .json(&params)
97        .send()
98        .await?;
99
100    #[derive(Debug, Serialize, Deserialize)]
101    struct Response {
102        status: i32,
103        email: Option<String>,
104    }
105
106    match response.status() {
107        StatusCode::OK => Ok(CommandResult {
108            spinner,
109            symbol: succeed_symbol(),
110            msg: succeed_message("Your password has been updated. Login with your new password."),
111        }),
112        StatusCode::NOT_FOUND => Ok(CommandResult {
113            spinner,
114            symbol: fail_symbol(),
115            msg: fail_message("URL not found."),
116        }),
117        _ => Ok(CommandResult {
118            spinner,
119            symbol: fail_symbol(),
120            msg: fail_message("Something wrong when trying to reset email."),
121        }),
122    }
123}
124
125fn build_smb_forgot_url(env: Environment) -> String {
126    let mut url_builder = smb_base_url_builder(env);
127    url_builder.add_route(PATH_USERS_PASSWORD);
128    url_builder.build()
129}