auth.rs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. use crate::{
  2. entities::{token::Token, user::UserTable},
  3. service::user::{hash_password, verify_password, LoggedUser},
  4. sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
  5. };
  6. use anyhow::Context;
  7. use backend_service::{
  8. errors::{invalid_params, ErrorCode, ServerError},
  9. response::FlowyResponse,
  10. };
  11. use chrono::Utc;
  12. use flowy_user_infra::{
  13. parser::{UserEmail, UserName, UserPassword},
  14. protobuf::{SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserParams, UserProfile},
  15. };
  16. use sqlx::{PgPool, Postgres};
  17. use super::AUTHORIZED_USERS;
  18. use crate::service::user::user_default::create_default_workspace;
  19. pub async fn sign_in(pool: &PgPool, params: SignInParams) -> Result<SignInResponse, ServerError> {
  20. let email = UserEmail::parse(params.email).map_err(|e| ServerError::params_invalid().context(e))?;
  21. let password = UserPassword::parse(params.password).map_err(|e| ServerError::params_invalid().context(e))?;
  22. let mut transaction = pool
  23. .begin()
  24. .await
  25. .context("Failed to acquire a Postgres connection to sign in")?;
  26. let user = check_user_password(&mut transaction, email.as_ref(), password.as_ref()).await?;
  27. transaction
  28. .commit()
  29. .await
  30. .context("Failed to commit SQL transaction to sign in.")?;
  31. let token = Token::create_token(&user.id.to_string())?;
  32. let logged_user = LoggedUser::new(&user.id.to_string());
  33. AUTHORIZED_USERS.store_auth(logged_user, true);
  34. let mut response_data = SignInResponse::default();
  35. response_data.set_user_id(user.id.to_string());
  36. response_data.set_name(user.name);
  37. response_data.set_email(user.email);
  38. response_data.set_token(token.clone().into());
  39. Ok(response_data)
  40. }
  41. pub async fn sign_out(logged_user: LoggedUser) -> Result<FlowyResponse, ServerError> {
  42. AUTHORIZED_USERS.store_auth(logged_user, false);
  43. Ok(FlowyResponse::success())
  44. }
  45. pub async fn register_user(pool: &PgPool, params: SignUpParams) -> Result<FlowyResponse, ServerError> {
  46. let name = UserName::parse(params.name).map_err(|e| ServerError::params_invalid().context(e))?;
  47. let email = UserEmail::parse(params.email).map_err(|e| ServerError::params_invalid().context(e))?;
  48. let password = UserPassword::parse(params.password).map_err(|e| ServerError::params_invalid().context(e))?;
  49. let mut transaction = pool
  50. .begin()
  51. .await
  52. .context("Failed to acquire a Postgres connection to register user")?;
  53. let _ = is_email_exist(&mut transaction, email.as_ref()).await?;
  54. let response_data = insert_new_user(&mut transaction, name.as_ref(), email.as_ref(), password.as_ref())
  55. .await
  56. .context("Failed to insert user")?;
  57. let logged_user = LoggedUser::new(&response_data.user_id);
  58. AUTHORIZED_USERS.store_auth(logged_user, true);
  59. let _ = create_default_workspace(&mut transaction, response_data.get_user_id()).await?;
  60. transaction
  61. .commit()
  62. .await
  63. .context("Failed to commit SQL transaction to register user.")?;
  64. FlowyResponse::success().pb(response_data)
  65. }
  66. pub(crate) async fn get_user_profile(
  67. pool: &PgPool,
  68. token: Token,
  69. logged_user: LoggedUser,
  70. ) -> Result<FlowyResponse, ServerError> {
  71. let mut transaction = pool
  72. .begin()
  73. .await
  74. .context("Failed to acquire a Postgres connection to get user detail")?;
  75. let id = logged_user.as_uuid()?;
  76. let user_table = sqlx::query_as::<Postgres, UserTable>("SELECT * FROM user_table WHERE id = $1")
  77. .bind(id)
  78. .fetch_one(&mut transaction)
  79. .await
  80. .map_err(|err| ServerError::internal().context(err))?;
  81. transaction
  82. .commit()
  83. .await
  84. .context("Failed to commit SQL transaction to get user detail.")?;
  85. // update the user active time
  86. AUTHORIZED_USERS.store_auth(logged_user, true);
  87. let mut user_profile = UserProfile::default();
  88. user_profile.set_id(user_table.id.to_string());
  89. user_profile.set_email(user_table.email);
  90. user_profile.set_name(user_table.name);
  91. user_profile.set_token(token.0);
  92. FlowyResponse::success().pb(user_profile)
  93. }
  94. pub(crate) async fn set_user_profile(
  95. pool: &PgPool,
  96. logged_user: LoggedUser,
  97. params: UpdateUserParams,
  98. ) -> Result<FlowyResponse, ServerError> {
  99. let mut transaction = pool
  100. .begin()
  101. .await
  102. .context("Failed to acquire a Postgres connection to update user profile")?;
  103. let name = match params.has_name() {
  104. false => None,
  105. true => Some(UserName::parse(params.get_name().to_owned()).map_err(invalid_params)?.0),
  106. };
  107. let email = match params.has_email() {
  108. false => None,
  109. true => Some(
  110. UserEmail::parse(params.get_email().to_owned())
  111. .map_err(invalid_params)?
  112. .0,
  113. ),
  114. };
  115. let password = match params.has_password() {
  116. false => None,
  117. true => {
  118. let password = UserPassword::parse(params.get_password().to_owned()).map_err(invalid_params)?;
  119. let password = hash_password(password.as_ref())?;
  120. Some(password)
  121. },
  122. };
  123. let (sql, args) = SqlBuilder::update("user_table")
  124. .add_some_arg("name", name)
  125. .add_some_arg("email", email)
  126. .add_some_arg("password", password)
  127. .and_where_eq("id", &logged_user.as_uuid()?)
  128. .build()?;
  129. sqlx::query_with(&sql, args)
  130. .execute(&mut transaction)
  131. .await
  132. .map_err(map_sqlx_error)?;
  133. transaction
  134. .commit()
  135. .await
  136. .context("Failed to commit SQL transaction to update user profile.")?;
  137. Ok(FlowyResponse::success())
  138. }
  139. async fn is_email_exist(transaction: &mut DBTransaction<'_>, email: &str) -> Result<(), ServerError> {
  140. let result = sqlx::query(r#"SELECT email FROM user_table WHERE email = $1"#)
  141. .bind(email)
  142. .fetch_optional(transaction)
  143. .await
  144. .map_err(|err| ServerError::internal().context(err))?;
  145. match result {
  146. Some(_) => Err(ServerError {
  147. code: ErrorCode::EmailAlreadyExists,
  148. msg: format!("{} already exists", email),
  149. }),
  150. None => Ok(()),
  151. }
  152. }
  153. async fn check_user_password(
  154. transaction: &mut DBTransaction<'_>,
  155. email: &str,
  156. password: &str,
  157. ) -> Result<UserTable, ServerError> {
  158. let user = sqlx::query_as::<Postgres, UserTable>("SELECT * FROM user_table WHERE email = $1")
  159. .bind(email)
  160. .fetch_one(transaction)
  161. .await
  162. .map_err(|err| ServerError::internal().context(err))?;
  163. match verify_password(&password, &user.password) {
  164. Ok(true) => Ok(user),
  165. _ => Err(ServerError::password_not_match()),
  166. }
  167. }
  168. async fn insert_new_user(
  169. transaction: &mut DBTransaction<'_>,
  170. name: &str,
  171. email: &str,
  172. password: &str,
  173. ) -> Result<SignUpResponse, ServerError> {
  174. let uuid = uuid::Uuid::new_v4();
  175. let token = Token::create_token(&uuid.to_string())?;
  176. let password = hash_password(password)?;
  177. let _ = sqlx::query!(
  178. r#"
  179. INSERT INTO user_table (id, email, name, create_time, password)
  180. VALUES ($1, $2, $3, $4, $5)
  181. "#,
  182. uuid,
  183. email,
  184. name,
  185. Utc::now(),
  186. password,
  187. )
  188. .execute(transaction)
  189. .await
  190. .map_err(|e| ServerError::internal().context(e))?;
  191. let mut response = SignUpResponse::default();
  192. response.set_user_id(uuid.to_string());
  193. response.set_name(name.to_string());
  194. response.set_email(email.to_string());
  195. response.set_token(token.into());
  196. Ok(response)
  197. }