AppFlowy-Cloud/src/api/user.rs

144 lines
4.7 KiB
Rust

use crate::biz;
use crate::component::auth::{
change_password, logged_user_from_request, login, logout, register, ChangePasswordRequest,
RegisterRequest,
};
use crate::component::auth::{InputParamsError, LoginRequest};
use crate::component::token_state::SessionToken;
use crate::domain::{UserEmail, UserName, UserPassword};
use crate::state::AppState;
use shared_entity::data::{AppResponse, JsonAppResponse};
use shared_entity::dto::{SignInTokenResponse, UpdateUsernameParams};
use storage_entity::AFUserProfileView;
use crate::component::auth::jwt::{Authorization, UserUuid};
use actix_web::web::{Data, Json};
use actix_web::HttpRequest;
use actix_web::Result;
use actix_web::{web, HttpResponse, Scope};
pub fn user_scope() -> Scope {
web::scope("/api/user")
// auth server integration
.service(web::resource("/verify/{access_token}").route(web::get().to(verify_handler)))
.service(web::resource("/update").route(web::post().to(update_handler)))
.service(web::resource("/profile").route(web::get().to(profile_handler)))
// native
.service(web::resource("/login").route(web::post().to(login_handler)))
.service(web::resource("/logout").route(web::get().to(logout_handler)))
.service(web::resource("/register").route(web::post().to(register_handler)))
.service(web::resource("/password").route(web::post().to(change_password_handler)))
}
async fn verify_handler(
path: web::Path<String>,
state: Data<AppState>,
) -> Result<JsonAppResponse<SignInTokenResponse>> {
let access_token = path.into_inner();
let is_new = biz::user::token_verify(&state.pg_pool, &state.gotrue_client, &access_token).await?;
let resp = SignInTokenResponse { is_new };
Ok(AppResponse::Ok().with_data(resp).into())
}
#[tracing::instrument(level = "debug", skip(state))]
async fn profile_handler(
uuid: UserUuid,
state: Data<AppState>,
) -> Result<JsonAppResponse<AFUserProfileView>> {
let profile = biz::user::get_profile(&state.pg_pool, &uuid).await?;
Ok(AppResponse::Ok().with_data(profile).into())
}
async fn update_handler(
auth: Authorization,
req: Json<UpdateUsernameParams>,
state: Data<AppState>,
) -> Result<JsonAppResponse<()>> {
let params = req.into_inner();
biz::user::update_user(&state.pg_pool, &auth.uuid()?, &params.new_name).await?;
Ok(AppResponse::Ok().into())
}
#[tracing::instrument(level = "debug", skip_all)]
async fn login_handler(
req: Json<LoginRequest>,
state: Data<AppState>,
session: SessionToken,
) -> Result<HttpResponse> {
let req = req.into_inner();
let email = UserEmail::parse(req.email)
.map_err(InputParamsError::InvalidEmail)?
.0;
let password = UserPassword::parse(req.password)
.map_err(InputParamsError::InvalidPassword)?
.0;
let (resp, token) = login(email, password, &state).await?;
// Renews the session key, assigning existing session state to new key.
session.renew();
if let Err(err) = session.insert_token(token) {
// It needs to navigate to login page in web application
tracing::error!("Insert session failed: {:?}", err);
}
Ok(HttpResponse::Ok().json(resp))
}
#[tracing::instrument(level = "debug", skip(state))]
async fn logout_handler(req: HttpRequest, state: Data<AppState>) -> Result<HttpResponse> {
let logged_user = logged_user_from_request(&req, &state.config.application.server_key)?;
logout(logged_user, state.user.clone()).await;
Ok(HttpResponse::Ok().finish())
}
#[tracing::instrument(level = "debug", skip(state))]
async fn register_handler(
req: Json<RegisterRequest>,
state: Data<AppState>,
) -> Result<HttpResponse> {
let req = req.into_inner();
let name = UserName::parse(req.name)
.map_err(InputParamsError::InvalidName)?
.0;
let email = UserEmail::parse(req.email)
.map_err(InputParamsError::InvalidEmail)?
.0;
let password = UserPassword::parse(req.password)
.map_err(InputParamsError::InvalidPassword)?
.0;
let resp = register(name, email, password, &state).await?;
Ok(HttpResponse::Ok().json(resp))
}
#[tracing::instrument(level = "debug", skip_all)]
async fn change_password_handler(
req: HttpRequest,
payload: Json<ChangePasswordRequest>,
// session: SessionToken,
state: Data<AppState>,
) -> Result<HttpResponse> {
let logged_user = logged_user_from_request(&req, &state.config.application.server_key)?;
let payload = payload.into_inner();
if payload.new_password != payload.new_password_confirm {
return Err(InputParamsError::PasswordNotMatch.into());
}
let new_password = UserPassword::parse(payload.new_password)
.map_err(InputParamsError::InvalidPassword)?
.0;
change_password(
state.pg_pool.clone(),
logged_user.clone(),
payload.current_password,
new_password,
)
.await?;
Ok(HttpResponse::Ok().finish())
}