AppFlowy/backend/src/user_service/auth_service.rs

140 lines
3.8 KiB
Rust
Raw Normal View History

2021-08-23 18:39:10 +08:00
use crate::{
entities::{token::Token, user::User},
user_service::utils::{hash_password, verify_password},
};
use actix_identity::Identity;
use anyhow::Context;
use chrono::Utc;
use flowy_net::{
2021-08-23 23:02:42 +08:00
errors::{ErrorCode, ServerError},
2021-08-23 18:39:10 +08:00
response::FlowyResponse,
};
use flowy_user::{
entities::{SignInResponse, SignUpResponse},
2021-08-23 23:02:42 +08:00
prelude::parser::{UserEmail, UserPassword},
2021-08-23 18:39:10 +08:00
protobuf::{SignInParams, SignUpParams},
};
use sqlx::{Error, PgPool, Postgres, Transaction};
use std::sync::Arc;
pub async fn sign_in(
pool: &PgPool,
params: SignInParams,
id: Identity,
) -> Result<FlowyResponse, ServerError> {
2021-08-23 23:02:42 +08:00
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))?;
2021-08-23 18:39:10 +08:00
let mut transaction = pool
.begin()
.await
.context("Failed to acquire a Postgres connection to sign in")?;
2021-08-23 23:02:42 +08:00
let user = read_user(&mut transaction, &email.0).await?;
2021-08-23 18:39:10 +08:00
transaction
.commit()
.await
.context("Failed to commit SQL transaction to sign in.")?;
2021-08-23 23:02:42 +08:00
match verify_password(&password.0, &user.password) {
2021-08-23 18:39:10 +08:00
Ok(true) => {
let token = Token::create_token(&user)?;
let data = SignInResponse {
uid: user.id.to_string(),
name: user.name,
email: user.email,
token: token.into(),
};
id.remember(data.token.clone());
FlowyResponse::success(data)
},
2021-08-23 23:02:42 +08:00
_ => Err(ServerError::password_not_match()),
2021-08-23 18:39:10 +08:00
}
}
pub async fn register_user(
pool: &PgPool,
params: SignUpParams,
) -> Result<FlowyResponse, ServerError> {
let mut transaction = pool
.begin()
.await
.context("Failed to acquire a Postgres connection to register user")?;
let _ = is_email_exist(&mut transaction, &params.email).await?;
let data = insert_user(&mut transaction, params)
.await
.context("Failed to insert user")?;
transaction
.commit()
.await
.context("Failed to commit SQL transaction to register user.")?;
FlowyResponse::success(data)
}
async fn is_email_exist(
transaction: &mut Transaction<'_, Postgres>,
email: &str,
) -> Result<(), ServerError> {
let result = sqlx::query(r#"SELECT email FROM user_table WHERE email = $1"#)
.bind(email)
.fetch_optional(transaction)
.await
2021-08-23 23:02:42 +08:00
.map_err(|err| ServerError::internal().context(err))?;
2021-08-23 18:39:10 +08:00
match result {
Some(_) => Err(ServerError {
2021-08-23 23:02:42 +08:00
code: ErrorCode::EmailAlreadyExists,
2021-08-23 18:39:10 +08:00
msg: format!("{} already exists", email),
}),
None => Ok(()),
}
}
async fn read_user(
transaction: &mut Transaction<'_, Postgres>,
email: &str,
) -> Result<User, ServerError> {
let user = sqlx::query_as::<Postgres, User>("SELECT * FROM user_table WHERE email = $1")
.bind(email)
.fetch_one(transaction)
.await
2021-08-23 23:02:42 +08:00
.map_err(|err| ServerError::internal().context(err))?;
2021-08-23 18:39:10 +08:00
Ok(user)
}
async fn insert_user(
transaction: &mut Transaction<'_, Postgres>,
params: SignUpParams,
) -> Result<SignUpResponse, ServerError> {
let uuid = uuid::Uuid::new_v4();
let password = hash_password(&params.password)?;
let _ = sqlx::query!(
r#"
INSERT INTO user_table (id, email, name, create_time, password)
VALUES ($1, $2, $3, $4, $5)
"#,
uuid,
params.email,
params.name,
Utc::now(),
password,
2021-08-23 18:39:10 +08:00
)
.execute(transaction)
.await
2021-08-23 23:02:42 +08:00
.map_err(|e| ServerError::internal().context(e))?;
2021-08-23 18:39:10 +08:00
let data = SignUpResponse {
uid: uuid.to_string(),
name: params.name,
email: params.email,
};
Ok(data)
}