use axum::extract::{Extension, Query};
use axum::response::IntoResponse;
use axum::Json;
use dialtone_common::ap::pun::is_valid_pun;
use dialtone_common::rest::sites::site_data::{RegistrationMethod, SiteInfo};
use dialtone_common::rest::users::user_exchanges::{GetUser, PostUser, PostUserResponse};
use dialtone_common::rest::users::web_user::UserStatus;
use dialtone_common::utils::make_acct::make_acct;
use dialtone_common::utils::parse_acct::parse_user_acct;
use dialtone_sqlx::control::user::check_name_availability::check_user_name_availability;
use dialtone_sqlx::control::user::create_with_actor::create_user_with_default_actor;
use dialtone_sqlx::db::site_info::fetch_site;
use dialtone_sqlx::db::user_principal::change_status::change_user_status;
use sqlx::{Pool, Postgres};
use tokio::time::{sleep, Duration};
use crate::authz::authz_user::authz_acct_or_useradmin;
use crate::{err_bad_request, err_not_found, err_unauthorized};
use dialtone_sqlx::db::user_principal::fetch_info::fetch_user_info;
use crate::response::response_error::ResponseError;
use crate::start_server::{Claims, SharedState};
pub async fn get_user_handler(
claims: Claims,
Query(params): Query<GetUser>,
Extension(pool): Extension<Pool<Postgres>>,
Extension(state): Extension<SharedState>,
) -> Result<impl IntoResponse, ResponseError> {
authz_acct_or_useradmin(¶ms.acct, &claims, &state).await?;
let user = fetch_user_info(&pool, ¶ms.acct).await?;
user.map_or_else(|| err_unauthorized!(), |v| Ok(Json(v)))
}
pub async fn post_user_handler(
Json(request): Json<PostUser>,
Extension(pool): Extension<Pool<Postgres>>,
) -> Result<impl IntoResponse, ResponseError> {
sleep(Duration::from_millis(750)).await;
let user_host = match request {
PostUser::OpenRegistration(ref user_creds) => parse_user_acct(&user_creds.user_acct),
PostUser::SimpleCode {
ref user_creds,
simple_code_for_registration: _,
} => parse_user_acct(&user_creds.user_acct),
};
if let Ok(acct_parts) = user_host {
if !is_valid_pun(&acct_parts.user_name, false) {
return err_bad_request!();
}
let site_info = fetch_site(&pool, &acct_parts.host_name).await?;
if let Some(site_info) = site_info {
match request {
PostUser::OpenRegistration(user_creds) => {
if site_info
.site_data
.public
.registration_methods
.contains(&RegistrationMethod::OpenRegistration)
{
return do_registration(
&pool,
&acct_parts.user_name,
&acct_parts.host_name,
&user_creds.password,
&site_info,
&RegistrationMethod::OpenRegistration,
)
.await;
} else {
return err_bad_request!();
}
}
PostUser::SimpleCode {
user_creds,
simple_code_for_registration,
} => {
if site_info
.site_data
.public
.registration_methods
.contains(&RegistrationMethod::SimpleCode)
{
if site_info.site_data.simple_code_for_registration
== Some(simple_code_for_registration)
{
return do_registration(
&pool,
&acct_parts.user_name,
&acct_parts.host_name,
&user_creds.password,
&site_info,
&RegistrationMethod::SimpleCode,
)
.await;
} else {
return err_unauthorized!();
}
} else {
return err_bad_request!();
}
}
}
} else {
return err_not_found!();
}
} else {
err_bad_request!()
}
}
async fn do_registration(
pool: &Pool<Postgres>,
user_name: &str,
host_name: &str,
password: &str,
site_info: &SiteInfo,
registration_method: &RegistrationMethod,
) -> Result<impl IntoResponse, ResponseError> {
let name_available = check_user_name_availability(&pool, &user_name, &host_name).await?;
if !name_available {
return err_unauthorized!();
}
create_user_with_default_actor(&pool, &user_name, &host_name, &password).await?;
if site_info
.site_data
.auto_approved_registrations
.contains(registration_method)
{
change_user_status(pool, &make_acct(user_name, host_name), &UserStatus::Active).await?;
Ok(Json(PostUserResponse::AccountRegistered(None)))
} else {
Ok(Json(PostUserResponse::AccountNeedsApproval(None)))
}
}