@smbcloud / cli / commits / 4285a42

Add resend verification email

Seto Elkahfi committed Sep 3, 2023 at 17:54 UTC 4285a42b453ac100f3c996b0f1f4968dc715baac
4 files changed +103 -24
smbpndk-cli/src/account/lib.rs
+2 -2
@@ -174,7 +174,7 @@ pub async fn process_connect_github(code: String) -> Result<SmbAuthorization> {
174 StatusCode::OK => {
175 // Account authorized and token received
176 spinner.stop_and_persist("✅", "You're logged in with your GitHub account!".into());
177 - let result: SmbAuthorization = response.json().await?;
177 + let result = response.json().await?;
178 println!("Result: {:#?}", &result);
179 Ok(result)
180 }
@@ -188,7 +188,7 @@ pub async fn process_connect_github(code: String) -> Result<SmbAuthorization> {
188 StatusCode::UNPROCESSABLE_ENTITY => {
189 // Account found but email not verified
190 spinner.stop_and_persist("🥹", "Unverified email!".into());
191 - let result: SmbAuthorization = response.json().await?;
191 + let result = response.json().await?;
192 println!("Result: {:#?}", &result);
193 Ok(result)
194 }
smbpndk-cli/src/account/login/process.rs
+80 -16
@@ -12,7 +12,6 @@ use log::debug;
12 use reqwest::Client;
13 use serde::{Deserialize, Serialize};
14 use smbpndk_model::CommandResult;
15 -use smbpndk_networking::constants::BASE_URL;
15 use smbpndk_utils::email_validation;
16 use spinners::Spinner;
17 use std::{
@@ -27,7 +26,13 @@ pub struct LoginArgs {
26
27 #[derive(Debug, Serialize)]
28 struct LoginParams {
30 - user: User,
29 + user: UserParam,
30 +}
31 +
32 +#[derive(Debug, Serialize)]
33 +struct UserParam {
34 + email: String,
35 + password: String,
36 }
37
38 #[derive(Debug, Serialize, Deserialize)]
@@ -62,8 +67,19 @@ async fn login_with_github() -> Result<CommandResult> {
67 }
68
69 async fn process_authorization(auth: SmbAuthorization) -> Result<CommandResult> {
70 + // What to do if not logged in with GitHub?
71 + // Check error_code first
72 + if let Some(error_code) = auth.error_code {
73 + debug!("{}", error_code);
74 + match error_code {
75 + ErrorCode::EmailNotFound => return create_new_account(auth.user_email, auth.user_info).await,
76 + ErrorCode::EmailUnverified => return send_email_verification(auth.user).await,
77 + }
78 + }
79 +
80 // Logged in with GitHub
81 if let Some(user) = auth.user {
82 + print!("You are logged in with GitHub as {}.", user);
83 let spinner = Spinner::new(
84 spinners::Spinners::SimpleDotsScrolling,
85 style("Logging you in...").green().bold().to_string(),
@@ -76,17 +92,6 @@ async fn process_authorization(auth: SmbAuthorization) -> Result<CommandResult>
92 });
93 }
94
79 - // What to do if not logged in with GitHub?
80 - if let Some(error_code) = auth.error_code {
81 - debug!("{}", error_code);
82 - match error_code {
83 - ErrorCode::EmailNotFound => {
84 - return create_new_account(auth.user_email, auth.user_info).await
85 - }
86 - ErrorCode::EmailUnverified => return send_email_verification(auth.user_email).await,
87 - }
88 - }
89 -
95 let error: anyhow::Error = anyhow!("Failed to login with GitHub.");
96 Err(error)
97 }
@@ -130,8 +135,61 @@ async fn create_new_account(
135 Err(anyhow!("Shouldn't be here."))
136 }
137
133 -async fn send_email_verification(user_email: Option<GithubEmail>) -> Result<CommandResult> {
134 - Err(anyhow!("Failed to send email verification."))
138 +async fn send_email_verification(user: Option<User>) -> Result<CommandResult> {
139 + // Return early if user is null
140 + if let Some(user) = user {
141 +
142 + let confirm = Confirm::with_theme(&ColorfulTheme::default())
143 + .with_prompt("Do you want to send a new verification email?")
144 + .interact()
145 + .unwrap();
146 +
147 + // Send verification email if user confirms
148 + if !confirm {
149 + let spinner = Spinner::new(
150 + spinners::Spinners::SimpleDotsScrolling,
151 + style("Cancel operation.").green().bold().to_string(),
152 + );
153 + return Ok(CommandResult {
154 + spinner,
155 + symbol: "✅".to_owned(),
156 + msg: "Doing nothing.".to_owned(),
157 + });
158 + }
159 + resend_email_verification(user).await
160 + } else {
161 + let error = anyhow!("Failed to get user.");
162 + Err(error)
163 + }
164 +}
165 +
166 +async fn resend_email_verification(user: User) -> Result<CommandResult> {
167 + let spinner = Spinner::new(
168 + spinners::Spinners::SimpleDotsScrolling,
169 + style("Sending verification email...").green().bold().to_string(),
170 + );
171 +
172 + let response = Client::new()
173 + .post(build_smb_resend_email_verification_url())
174 + .body(format!("id={}", user.id))
175 + .header("Accept", "application/json")
176 + .header("Content-Type", "application/x-www-form-urlencoded")
177 + .send()
178 + .await?;
179 +
180 + match response.status() {
181 + reqwest::StatusCode::OK => {
182 + Ok(CommandResult {
183 + spinner,
184 + symbol: "✅".to_owned(),
185 + msg: "Verification email sent!".to_owned(),
186 + })
187 + }
188 + _ => {
189 + let error = anyhow!("Failed to send verification email.");
190 + Err(error)
191 + }
192 + }
193 }
194
195 async fn login_with_email() -> Result<CommandResult> {
@@ -167,7 +225,7 @@ async fn login_with_email() -> Result<CommandResult> {
225
226 async fn do_process_login(args: LoginArgs) -> Result<()> {
227 let login_params = LoginParams {
170 - user: User {
228 + user: UserParam {
229 email: args.username,
230 password: args.password,
231 },
@@ -222,6 +280,12 @@ fn build_smb_login_url() -> String {
280 url_builder.build()
281 }
282
283 +fn build_smb_resend_email_verification_url() -> String {
284 + let mut url_builder = smb_base_url_builder();
285 + url_builder.add_route("v1/resend_confirmation");
286 + url_builder.build()
287 +}
288 +
289 pub async fn process_logout() -> Result<CommandResult> {
290 let spinner = Spinner::new(
291 spinners::Spinners::SimpleDotsScrolling,
smbpndk-cli/src/account/model/mod.rs
+10 -1
@@ -1,9 +1,18 @@
1 +use std::fmt::{Formatter, Display};
2 +
3 use serde::{Deserialize, Serialize};
4
5 +// SMBPNDK Users.
6 #[derive(Debug, Serialize, Deserialize)]
7 pub struct User {
8 + pub(crate) id: i32,
9 pub(crate) email: String,
6 - pub(crate) password: String,
10 +}
11 +
12 +impl Display for User {
13 + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
14 + write!(f, "User: id: {}, email: {}", self.id, self.email)
15 + }
16 }
17
18 #[derive(Debug, Serialize, Deserialize)]
smbpndk-cli/src/account/signup/process.rs
+11 -5
@@ -1,6 +1,6 @@
1 use super::SignupMethod;
2 use crate::account::{
3 - lib::authorize_github,
3 + lib::{authorize_github, smb_base_url_builder},
4 model::{Data, Status},
5 };
6 use anyhow::{anyhow, Result};
@@ -10,7 +10,7 @@ use log::debug;
10 use reqwest::{Client, StatusCode};
11 use serde::{Deserialize, Serialize};
12 use smbpndk_model::CommandResult;
13 -use smbpndk_networking::constants::BASE_URL;
13 +
14 use smbpndk_utils::email_validation;
15 use spinners::Spinner;
16 use std::fmt::{Display, Formatter};
@@ -168,7 +168,7 @@ pub async fn do_signup<T: Serialize + ?Sized>(args: &T) -> Result<CommandResult>
168 );
169
170 let response = Client::new()
171 - .post([BASE_URL, "/v1/users"].join(""))
171 + .post(build_smb_signup_url())
172 .json(&args)
173 .send()
174 .await?;
@@ -176,8 +176,8 @@ pub async fn do_signup<T: Serialize + ?Sized>(args: &T) -> Result<CommandResult>
176 match response.status() {
177 StatusCode::OK => Ok(CommandResult {
178 spinner,
179 - symbol: "Yes".to_owned(),
180 - msg: "Success. Check email".to_owned(),
179 + symbol: "✅".to_owned(),
180 + msg: "Your account has been created. Check email for verification link.".to_owned(),
181 }),
182 StatusCode::UNPROCESSABLE_ENTITY => {
183 let result: SignupResult = response.json().await?;
@@ -190,3 +190,9 @@ pub async fn do_signup<T: Serialize + ?Sized>(args: &T) -> Result<CommandResult>
190 }
191 }
192 }
193 +
194 +fn build_smb_signup_url() -> String {
195 + let mut url_builder = smb_base_url_builder();
196 + url_builder.add_route("v1/users");
197 + url_builder.build()
198 +}