@smbcloud / cli / commits / ecb41c3

Reset password instructions

Seto Elkahfi committed Sep 3, 2023 at 19:01 UTC ecb41c3009022ac30f7ff519edcc1acc5e57979e
2 files changed +99 -7
smbpndk-cli/src/account/lib.rs
+2
@@ -34,6 +34,7 @@ pub struct SmbAuthorization {
34 pub enum ErrorCode {
35 EmailNotFound = 1000,
36 EmailUnverified = 1001,
37 + PasswordNotSet = 1003,
38 }
39
40 impl Display for ErrorCode {
@@ -41,6 +42,7 @@ impl Display for ErrorCode {
42 match self {
43 ErrorCode::EmailNotFound => write!(f, "Email not found."),
44 ErrorCode::EmailUnverified => write!(f, "Email not verified."),
45 + ErrorCode::PasswordNotSet => write!(f, "Password not set."),
46 }
47 }
48 }
smbpndk-cli/src/account/login/process.rs
+97 -7
@@ -76,6 +76,11 @@ async fn process_authorization(auth: SmbAuthorization) -> Result<CommandResult>
76 return create_new_account(auth.user_email, auth.user_info).await
77 }
78 ErrorCode::EmailUnverified => return send_email_verification(auth.user).await,
79 + ErrorCode::PasswordNotSet => {
80 + // Only for email and password login
81 + let error = anyhow!("Password not set.");
82 + return Err(error);
83 + }
84 }
85 }
86
@@ -258,7 +263,7 @@ async fn do_process_login(args: LoginArgs) -> Result<CommandResult> {
263 return Err(error);
264 }
265 }
261 - },
266 + }
267 StatusCode::NOT_FOUND => {
268 // Account not found and we show signup option
269 Ok(CommandResult {
@@ -269,14 +274,13 @@ async fn do_process_login(args: LoginArgs) -> Result<CommandResult> {
274 symbol: "✅".to_owned(),
275 msg: "Please signup!".to_owned(),
276 })
272 - },
277 + }
278 StatusCode::UNPROCESSABLE_ENTITY => {
274 - // Account found but email not verified
275 - println!("✅ Account found but email not verified.");
279 + // Account found but email not verified / password not set
280 let result: SmbAuthorization = response.json().await?;
277 - // println!("Result: {:#?}", &result);
278 - return send_email_verification(result.user).await;
279 - },
281 + println!("Result: {:#?}", &result);
282 + return verify_or_set_password(result).await;
283 + }
284 _ => {
285 let error = anyhow!("Login failed. Check your username and password.");
286 return Err(error);
@@ -284,6 +288,86 @@ async fn do_process_login(args: LoginArgs) -> Result<CommandResult> {
288 }
289 }
290
291 +async fn verify_or_set_password(result: SmbAuthorization) -> Result<CommandResult> {
292 + match result.error_code {
293 + Some(error_code) => {
294 + debug!("{}", error_code);
295 + match error_code {
296 + ErrorCode::EmailUnverified => {
297 + return send_email_verification(result.user).await
298 + }
299 + ErrorCode::PasswordNotSet => {
300 + return send_reset_password(result.user).await
301 + }
302 + _ => {
303 + let error = anyhow!("Shouldn't be here.");
304 + return Err(error);
305 + }
306 + }
307 + }
308 + None => {
309 + let error = anyhow!("Shouldn't be here.");
310 + return Err(error);
311 + }
312 + }
313 +}
314 +
315 +async fn send_reset_password(user: Option<User>) -> Result<CommandResult> {
316 + // Return early if user is null
317 + if let Some(user) = user {
318 + let confirm = Confirm::with_theme(&ColorfulTheme::default())
319 + .with_prompt("Do you want to reset your password?")
320 + .interact()
321 + .unwrap();
322 +
323 + // Send verification email if user confirms
324 + if !confirm {
325 + let spinner = Spinner::new(
326 + spinners::Spinners::SimpleDotsScrolling,
327 + style("Cancel operation.").green().bold().to_string(),
328 + );
329 + return Ok(CommandResult {
330 + spinner,
331 + symbol: "✅".to_owned(),
332 + msg: "Doing nothing.".to_owned(),
333 + });
334 + }
335 + resend_reset_password_instruction(user).await
336 + } else {
337 + let error = anyhow!("Failed to get user.");
338 + Err(error)
339 + }
340 +}
341 +
342 +async fn resend_reset_password_instruction(user: User) -> Result<CommandResult> {
343 + let spinner = Spinner::new(
344 + spinners::Spinners::SimpleDotsScrolling,
345 + style("Sending reset password instruction...")
346 + .green()
347 + .bold()
348 + .to_string(),
349 + );
350 + let response = Client::new()
351 + .post(build_smb_resend_reset_password_instructions_url())
352 + .body(format!("id={}", user.id))
353 + .header("Accept", "application/json")
354 + .header("Content-Type", "application/x-www-form-urlencoded")
355 + .send()
356 + .await?;
357 +
358 + match response.status() {
359 + reqwest::StatusCode::OK => Ok(CommandResult {
360 + spinner,
361 + symbol: "✅".to_owned(),
362 + msg: "Reset password instruction sent!".to_owned(),
363 + }),
364 + _ => {
365 + let error = anyhow!("Failed to send reset password instruction.");
366 + Err(error)
367 + }
368 + }
369 +}
370 +
371 fn build_smb_login_url() -> String {
372 let mut url_builder = smb_base_url_builder();
373 url_builder.add_route("v1/users/sign_in");
@@ -296,6 +380,12 @@ fn build_smb_resend_email_verification_url() -> String {
380 url_builder.build()
381 }
382
383 +fn build_smb_resend_reset_password_instructions_url() -> String {
384 + let mut url_builder = smb_base_url_builder();
385 + url_builder.add_route("v1/resend_reset_password_instructions");
386 + url_builder.build()
387 +}
388 +
389 pub async fn process_logout() -> Result<CommandResult> {
390 let spinner = Spinner::new(
391 spinners::Spinners::SimpleDotsScrolling,