123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- use super::AUTHORIZED_USERS;
- use crate::{
- entities::{token::Token, user::UserTable},
- sqlx_ext::DBTransaction,
- user_service::{hash_password, verify_password, LoggedUser},
- workspace_service::user_default::create_default_workspace,
- };
- use crate::sqlx_ext::{map_sqlx_error, SqlBuilder};
- use anyhow::Context;
- use chrono::Utc;
- use flowy_net::{
- errors::{invalid_params, ErrorCode, ServerError},
- response::FlowyResponse,
- };
- use flowy_user::{
- entities::parser::{UserEmail, UserName, UserPassword},
- protobuf::{
- SignInParams,
- SignInResponse,
- SignUpParams,
- SignUpResponse,
- UpdateUserParams,
- UserProfile,
- },
- };
- use sqlx::{PgPool, Postgres};
- pub async fn sign_in(pool: &PgPool, params: SignInParams) -> Result<SignInResponse, ServerError> {
- let email =
- UserEmail::parse(params.email).map_err(|e| ServerError::params_invalid().context(e))?;
- let password = UserPassword::parse(params.password)
- .map_err(|e| ServerError::params_invalid().context(e))?;
- let mut transaction = pool
- .begin()
- .await
- .context("Failed to acquire a Postgres connection to sign in")?;
- let user = check_user_password(&mut transaction, email.as_ref(), password.as_ref()).await?;
- transaction
- .commit()
- .await
- .context("Failed to commit SQL transaction to sign in.")?;
- let token = Token::create_token(&user.id.to_string())?;
- let logged_user = LoggedUser::new(&user.id.to_string());
- let _ = AUTHORIZED_USERS.store_auth(logged_user, true)?;
- let mut response_data = SignInResponse::default();
- response_data.set_uid(user.id.to_string());
- response_data.set_name(user.name);
- response_data.set_email(user.email);
- response_data.set_token(token.clone().into());
- Ok(response_data)
- }
- pub async fn sign_out(logged_user: LoggedUser) -> Result<FlowyResponse, ServerError> {
- let _ = AUTHORIZED_USERS.store_auth(logged_user, false)?;
- Ok(FlowyResponse::success())
- }
- pub async fn register_user(
- pool: &PgPool,
- params: SignUpParams,
- ) -> Result<FlowyResponse, ServerError> {
- let name =
- UserName::parse(params.name).map_err(|e| ServerError::params_invalid().context(e))?;
- let email =
- UserEmail::parse(params.email).map_err(|e| ServerError::params_invalid().context(e))?;
- let password = UserPassword::parse(params.password)
- .map_err(|e| ServerError::params_invalid().context(e))?;
- let mut transaction = pool
- .begin()
- .await
- .context("Failed to acquire a Postgres connection to register user")?;
- let _ = is_email_exist(&mut transaction, email.as_ref()).await?;
- let response_data = insert_new_user(
- &mut transaction,
- name.as_ref(),
- email.as_ref(),
- password.as_ref(),
- )
- .await
- .context("Failed to insert user")?;
- let logged_user = LoggedUser::new(&response_data.user_id);
- let _ = AUTHORIZED_USERS.store_auth(logged_user, true)?;
- let _ = create_default_workspace(&mut transaction, response_data.get_user_id()).await?;
- transaction
- .commit()
- .await
- .context("Failed to commit SQL transaction to register user.")?;
- FlowyResponse::success().pb(response_data)
- }
- pub(crate) async fn get_user_profile(
- pool: &PgPool,
- logged_user: LoggedUser,
- ) -> Result<FlowyResponse, ServerError> {
- let mut transaction = pool
- .begin()
- .await
- .context("Failed to acquire a Postgres connection to get user detail")?;
- let id = logged_user.get_user_id()?;
- let user_table =
- sqlx::query_as::<Postgres, UserTable>("SELECT * FROM user_table WHERE id = $1")
- .bind(id)
- .fetch_one(&mut transaction)
- .await
- .map_err(|err| ServerError::internal().context(err))?;
- transaction
- .commit()
- .await
- .context("Failed to commit SQL transaction to get user detail.")?;
- // update the user active time
- let _ = AUTHORIZED_USERS.store_auth(logged_user, true)?;
- let mut user_profile = UserProfile::default();
- user_profile.set_id(user_table.id.to_string());
- user_profile.set_email(user_table.email);
- user_profile.set_name(user_table.name);
- FlowyResponse::success().pb(user_profile)
- }
- pub(crate) async fn set_user_profile(
- pool: &PgPool,
- logged_user: LoggedUser,
- params: UpdateUserParams,
- ) -> Result<FlowyResponse, ServerError> {
- let mut transaction = pool
- .begin()
- .await
- .context("Failed to acquire a Postgres connection to update user profile")?;
- let name = match params.has_name() {
- false => None,
- true => Some(
- UserName::parse(params.get_name().to_owned())
- .map_err(invalid_params)?
- .0,
- ),
- };
- let email = match params.has_email() {
- false => None,
- true => Some(
- UserEmail::parse(params.get_email().to_owned())
- .map_err(invalid_params)?
- .0,
- ),
- };
- let password = match params.has_password() {
- false => None,
- true => {
- let password =
- UserPassword::parse(params.get_password().to_owned()).map_err(invalid_params)?;
- let password = hash_password(password.as_ref())?;
- Some(password)
- },
- };
- let (sql, args) = SqlBuilder::update("user_table")
- .add_some_arg("name", name)
- .add_some_arg("email", email)
- .add_some_arg("password", password)
- .and_where_eq("id", &logged_user.get_user_id()?)
- .build()?;
- sqlx::query_with(&sql, args)
- .execute(&mut transaction)
- .await
- .map_err(map_sqlx_error)?;
- transaction
- .commit()
- .await
- .context("Failed to commit SQL transaction to update user profile.")?;
- Ok(FlowyResponse::success())
- }
- async fn is_email_exist(
- transaction: &mut DBTransaction<'_>,
- email: &str,
- ) -> Result<(), ServerError> {
- let result = sqlx::query(r#"SELECT email FROM user_table WHERE email = $1"#)
- .bind(email)
- .fetch_optional(transaction)
- .await
- .map_err(|err| ServerError::internal().context(err))?;
- match result {
- Some(_) => Err(ServerError {
- code: ErrorCode::EmailAlreadyExists,
- msg: format!("{} already exists", email),
- }),
- None => Ok(()),
- }
- }
- async fn check_user_password(
- transaction: &mut DBTransaction<'_>,
- email: &str,
- password: &str,
- ) -> Result<UserTable, ServerError> {
- let user = sqlx::query_as::<Postgres, UserTable>("SELECT * FROM user_table WHERE email = $1")
- .bind(email)
- .fetch_one(transaction)
- .await
- .map_err(|err| ServerError::internal().context(err))?;
- match verify_password(&password, &user.password) {
- Ok(true) => Ok(user),
- _ => Err(ServerError::password_not_match()),
- }
- }
- async fn insert_new_user(
- transaction: &mut DBTransaction<'_>,
- name: &str,
- email: &str,
- password: &str,
- ) -> Result<SignUpResponse, ServerError> {
- let uuid = uuid::Uuid::new_v4();
- let token = Token::create_token(&uuid.to_string())?;
- let password = hash_password(password)?;
- let _ = sqlx::query!(
- r#"
- INSERT INTO user_table (id, email, name, create_time, password)
- VALUES ($1, $2, $3, $4, $5)
- "#,
- uuid,
- email,
- name,
- Utc::now(),
- password,
- )
- .execute(transaction)
- .await
- .map_err(|e| ServerError::internal().context(e))?;
- let mut response = SignUpResponse::default();
- response.set_user_id(uuid.to_string());
- response.set_name(name.to_string());
- response.set_email(email.to_string());
- response.set_token(token.into());
- Ok(response)
- }
|